interp: implement runtime.sliceCopy

This implements the copy() built-in function. It may not work in all
cases, but should work in most cases.

This commit gets the following 3 packages to compile, according to
tinygo-site/imports/main.go:

  * encoding/base32
  * encoding/base64
  * encoding/pem (was blocked by encoding/base64)
This commit is contained in:
Ayke van Laethem
2019-09-22 00:16:26 +02:00
committed by Ayke
parent 4ea1559d46
commit 582457b81e
8 changed files with 201 additions and 7 deletions
+43
View File
@@ -316,6 +316,49 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
ret = llvm.ConstInsertValue(ret, retPtr, []uint32{0})
ret = llvm.ConstInsertValue(ret, retLen, []uint32{1})
fr.locals[inst] = &LocalValue{fr.Eval, ret}
case callee.Name() == "runtime.sliceCopy":
elementSize := fr.getLocal(inst.Operand(4)).(*LocalValue).Value().ZExtValue()
dstArray := fr.getLocal(inst.Operand(0)).(*LocalValue).stripPointerCasts()
srcArray := fr.getLocal(inst.Operand(1)).(*LocalValue).stripPointerCasts()
dstLen := fr.getLocal(inst.Operand(2)).(*LocalValue)
srcLen := fr.getLocal(inst.Operand(3)).(*LocalValue)
if elementSize != 1 && dstArray.Type().ElementType().TypeKind() == llvm.ArrayTypeKind && srcArray.Type().ElementType().TypeKind() == llvm.ArrayTypeKind {
// Slice data pointers are created by adding a global array
// and getting the address of the first element using a GEP.
// However, before the compiler can pass it to
// runtime.sliceCopy, it has to perform a bitcast to a *i8,
// to make it a unsafe.Pointer. Now, when the IR builder
// sees a bitcast of a GEP with zero indices, it will make
// a bitcast of the original array instead of the GEP,
// which breaks our assumptions.
// Re-add this GEP, in the hope that it it is then of the correct type...
dstArray = dstArray.GetElementPtr([]uint32{0, 0}).(*LocalValue)
srcArray = srcArray.GetElementPtr([]uint32{0, 0}).(*LocalValue)
}
if fr.Eval.TargetData.TypeAllocSize(dstArray.Type().ElementType()) != elementSize {
return nil, nil, errors.New("interp: slice dst element size does not match pointer type")
}
if fr.Eval.TargetData.TypeAllocSize(srcArray.Type().ElementType()) != elementSize {
return nil, nil, errors.New("interp: slice src element size does not match pointer type")
}
if dstArray.Type() != srcArray.Type() {
return nil, nil, errors.New("interp: slice element types don't match")
}
length := dstLen.Value().SExtValue()
if srcLength := srcLen.Value().SExtValue(); srcLength < length {
length = srcLength
}
if length < 0 {
return nil, nil, errors.New("interp: trying to copy a slice with negative length?")
}
for i := int64(0); i < length; i++ {
// *dst = *src
dstArray.Store(srcArray.Load())
// dst++
dstArray = dstArray.GetElementPtr([]uint32{1}).(*LocalValue)
// src++
srcArray = srcArray.GetElementPtr([]uint32{1}).(*LocalValue)
}
case callee.Name() == "runtime.stringToBytes":
// convert a string to a []byte
bufPtr := fr.getLocal(inst.Operand(0))