compiler: refactor parseExpr
parseExpr (now createExpr) and all callers (recursively) are switched over to the new builder object!
Этот коммит содержится в:
родитель
d752e66be5
коммит
19bf8acde0
2 изменённых файлов: 188 добавлений и 187 удалений
|
@ -1026,7 +1026,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
|
||||||
|
|
||||||
switch instr := instr.(type) {
|
switch instr := instr.(type) {
|
||||||
case ssa.Value:
|
case ssa.Value:
|
||||||
if value, err := c.parseExpr(frame, instr); err != nil {
|
if value, err := frame.createExpr(instr); err != nil {
|
||||||
// This expression could not be parsed. Add the error to the list
|
// This expression could not be parsed. Add the error to the list
|
||||||
// of diagnostics and continue with an undef value.
|
// of diagnostics and continue with an undef value.
|
||||||
// The resulting IR will be incorrect (but valid). However,
|
// The resulting IR will be incorrect (but valid). However,
|
||||||
|
@ -1432,41 +1432,42 @@ func (b *builder) getValue(expr ssa.Value) llvm.Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseExpr translates a Go SSA expression to a LLVM instruction.
|
// createExpr translates a Go SSA expression to LLVM IR. This can be zero, one,
|
||||||
func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
// or multiple LLVM IR instructions and/or runtime calls.
|
||||||
if _, ok := frame.locals[expr]; ok {
|
func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||||
|
if _, ok := b.locals[expr]; ok {
|
||||||
// sanity check
|
// sanity check
|
||||||
panic("local has already been parsed: " + expr.String())
|
panic("instruction has already been created: " + expr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
switch expr := expr.(type) {
|
switch expr := expr.(type) {
|
||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
typ := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||||
if expr.Heap {
|
if expr.Heap {
|
||||||
size := c.targetData.TypeAllocSize(typ)
|
size := b.targetData.TypeAllocSize(typ)
|
||||||
// Calculate ^uintptr(0)
|
// Calculate ^uintptr(0)
|
||||||
maxSize := llvm.ConstNot(llvm.ConstInt(c.uintptrType, 0, false)).ZExtValue()
|
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
|
||||||
if size > maxSize {
|
if size > maxSize {
|
||||||
// Size would be truncated if truncated to uintptr.
|
// Size would be truncated if truncated to uintptr.
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), fmt.Sprintf("value is too big (%v bytes)", size))
|
return llvm.Value{}, b.makeError(expr.Pos(), fmt.Sprintf("value is too big (%v bytes)", size))
|
||||||
}
|
}
|
||||||
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||||
buf := c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, expr.Comment)
|
buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue}, expr.Comment)
|
||||||
buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
buf = b.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
||||||
return buf, nil
|
return buf, nil
|
||||||
} else {
|
} else {
|
||||||
buf := llvmutil.CreateEntryBlockAlloca(c.builder, typ, expr.Comment)
|
buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment)
|
||||||
if c.targetData.TypeAllocSize(typ) != 0 {
|
if b.targetData.TypeAllocSize(typ) != 0 {
|
||||||
c.builder.CreateStore(llvm.ConstNull(typ), buf) // zero-initialize var
|
b.CreateStore(llvm.ConstNull(typ), buf) // zero-initialize var
|
||||||
}
|
}
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
case *ssa.BinOp:
|
case *ssa.BinOp:
|
||||||
x := frame.getValue(expr.X)
|
x := b.getValue(expr.X)
|
||||||
y := frame.getValue(expr.Y)
|
y := b.getValue(expr.Y)
|
||||||
return frame.createBinOp(expr.Op, expr.X.Type(), x, y, expr.Pos())
|
return b.createBinOp(expr.Op, expr.X.Type(), x, y, expr.Pos())
|
||||||
case *ssa.Call:
|
case *ssa.Call:
|
||||||
return frame.createFunctionCall(expr.Common())
|
return b.createFunctionCall(expr.Common())
|
||||||
case *ssa.ChangeInterface:
|
case *ssa.ChangeInterface:
|
||||||
// Do not change between interface types: always use the underlying
|
// Do not change between interface types: always use the underlying
|
||||||
// (concrete) type in the type number of the interface. Every method
|
// (concrete) type in the type number of the interface. Every method
|
||||||
|
@ -1474,13 +1475,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
// This is different from how the official Go compiler works, because of
|
// This is different from how the official Go compiler works, because of
|
||||||
// heap allocation and because it's easier to implement, see:
|
// heap allocation and because it's easier to implement, see:
|
||||||
// https://research.swtch.com/interfaces
|
// https://research.swtch.com/interfaces
|
||||||
return frame.getValue(expr.X), nil
|
return b.getValue(expr.X), nil
|
||||||
case *ssa.ChangeType:
|
case *ssa.ChangeType:
|
||||||
// This instruction changes the type, but the underlying value remains
|
// This instruction changes the type, but the underlying value remains
|
||||||
// the same. This is often a no-op, but sometimes we have to change the
|
// the same. This is often a no-op, but sometimes we have to change the
|
||||||
// LLVM type as well.
|
// LLVM type as well.
|
||||||
x := frame.getValue(expr.X)
|
x := b.getValue(expr.X)
|
||||||
llvmType := c.getLLVMType(expr.Type())
|
llvmType := b.getLLVMType(expr.Type())
|
||||||
if x.Type() == llvmType {
|
if x.Type() == llvmType {
|
||||||
// Different Go type but same LLVM type (for example, named int).
|
// Different Go type but same LLVM type (for example, named int).
|
||||||
// This is the common case.
|
// This is the common case.
|
||||||
|
@ -1494,70 +1495,70 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
// values from the previous struct in there.
|
// values from the previous struct in there.
|
||||||
value := llvm.Undef(llvmType)
|
value := llvm.Undef(llvmType)
|
||||||
for i := 0; i < llvmType.StructElementTypesCount(); i++ {
|
for i := 0; i < llvmType.StructElementTypesCount(); i++ {
|
||||||
field := c.builder.CreateExtractValue(x, i, "changetype.field")
|
field := b.CreateExtractValue(x, i, "changetype.field")
|
||||||
value = c.builder.CreateInsertValue(value, field, i, "changetype.struct")
|
value = b.CreateInsertValue(value, field, i, "changetype.struct")
|
||||||
}
|
}
|
||||||
return value, nil
|
return value, nil
|
||||||
case llvm.PointerTypeKind:
|
case llvm.PointerTypeKind:
|
||||||
// This can happen with pointers to structs. This case is easy:
|
// This can happen with pointers to structs. This case is easy:
|
||||||
// simply bitcast the pointer to the destination type.
|
// simply bitcast the pointer to the destination type.
|
||||||
return c.builder.CreateBitCast(x, llvmType, "changetype.pointer"), nil
|
return b.CreateBitCast(x, llvmType, "changetype.pointer"), nil
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String())
|
return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String())
|
||||||
}
|
}
|
||||||
case *ssa.Const:
|
case *ssa.Const:
|
||||||
panic("const is not an expression")
|
panic("const is not an expression")
|
||||||
case *ssa.Convert:
|
case *ssa.Convert:
|
||||||
x := frame.getValue(expr.X)
|
x := b.getValue(expr.X)
|
||||||
return frame.createConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
|
return b.createConvert(expr.X.Type(), expr.Type(), x, expr.Pos())
|
||||||
case *ssa.Extract:
|
case *ssa.Extract:
|
||||||
if _, ok := expr.Tuple.(*ssa.Select); ok {
|
if _, ok := expr.Tuple.(*ssa.Select); ok {
|
||||||
return frame.getChanSelectResult(expr), nil
|
return b.getChanSelectResult(expr), nil
|
||||||
}
|
}
|
||||||
value := frame.getValue(expr.Tuple)
|
value := b.getValue(expr.Tuple)
|
||||||
return c.builder.CreateExtractValue(value, expr.Index, ""), nil
|
return b.CreateExtractValue(value, expr.Index, ""), nil
|
||||||
case *ssa.Field:
|
case *ssa.Field:
|
||||||
value := frame.getValue(expr.X)
|
value := b.getValue(expr.X)
|
||||||
result := c.builder.CreateExtractValue(value, expr.Field, "")
|
result := b.CreateExtractValue(value, expr.Field, "")
|
||||||
return result, nil
|
return result, nil
|
||||||
case *ssa.FieldAddr:
|
case *ssa.FieldAddr:
|
||||||
val := frame.getValue(expr.X)
|
val := b.getValue(expr.X)
|
||||||
// Check for nil pointer before calculating the address, from the spec:
|
// Check for nil pointer before calculating the address, from the spec:
|
||||||
// > For an operand x of type T, the address operation &x generates a
|
// > For an operand x of type T, the address operation &x generates a
|
||||||
// > pointer of type *T to x. [...] If the evaluation of x would cause a
|
// > pointer of type *T to x. [...] If the evaluation of x would cause a
|
||||||
// > run-time panic, then the evaluation of &x does too.
|
// > run-time panic, then the evaluation of &x does too.
|
||||||
frame.createNilCheck(val, "gep")
|
b.createNilCheck(val, "gep")
|
||||||
// Do a GEP on the pointer to get the field address.
|
// Do a GEP on the pointer to get the field address.
|
||||||
indices := []llvm.Value{
|
indices := []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), uint64(expr.Field), false),
|
llvm.ConstInt(b.ctx.Int32Type(), uint64(expr.Field), false),
|
||||||
}
|
}
|
||||||
return c.builder.CreateInBoundsGEP(val, indices, ""), nil
|
return b.CreateInBoundsGEP(val, indices, ""), nil
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
panic("function is not an expression")
|
panic("function is not an expression")
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
panic("global is not an expression")
|
panic("global is not an expression")
|
||||||
case *ssa.Index:
|
case *ssa.Index:
|
||||||
array := frame.getValue(expr.X)
|
array := b.getValue(expr.X)
|
||||||
index := frame.getValue(expr.Index)
|
index := b.getValue(expr.Index)
|
||||||
|
|
||||||
// Check bounds.
|
// Check bounds.
|
||||||
arrayLen := expr.X.Type().(*types.Array).Len()
|
arrayLen := expr.X.Type().(*types.Array).Len()
|
||||||
arrayLenLLVM := llvm.ConstInt(c.uintptrType, uint64(arrayLen), false)
|
arrayLenLLVM := llvm.ConstInt(b.uintptrType, uint64(arrayLen), false)
|
||||||
frame.createLookupBoundsCheck(arrayLenLLVM, index, expr.Index.Type())
|
b.createLookupBoundsCheck(arrayLenLLVM, index, expr.Index.Type())
|
||||||
|
|
||||||
// Can't load directly from array (as index is non-constant), so have to
|
// Can't load directly from array (as index is non-constant), so have to
|
||||||
// do it using an alloca+gep+load.
|
// do it using an alloca+gep+load.
|
||||||
alloca, allocaPtr, allocaSize := c.createTemporaryAlloca(array.Type(), "index.alloca")
|
alloca, allocaPtr, allocaSize := b.createTemporaryAlloca(array.Type(), "index.alloca")
|
||||||
c.builder.CreateStore(array, alloca)
|
b.CreateStore(array, alloca)
|
||||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
ptr := c.builder.CreateInBoundsGEP(alloca, []llvm.Value{zero, index}, "index.gep")
|
ptr := b.CreateInBoundsGEP(alloca, []llvm.Value{zero, index}, "index.gep")
|
||||||
result := c.builder.CreateLoad(ptr, "index.load")
|
result := b.CreateLoad(ptr, "index.load")
|
||||||
c.emitLifetimeEnd(allocaPtr, allocaSize)
|
b.emitLifetimeEnd(allocaPtr, allocaSize)
|
||||||
return result, nil
|
return result, nil
|
||||||
case *ssa.IndexAddr:
|
case *ssa.IndexAddr:
|
||||||
val := frame.getValue(expr.X)
|
val := b.getValue(expr.X)
|
||||||
index := frame.getValue(expr.Index)
|
index := b.getValue(expr.Index)
|
||||||
|
|
||||||
// Get buffer pointer and length
|
// Get buffer pointer and length
|
||||||
var bufptr, buflen llvm.Value
|
var bufptr, buflen llvm.Value
|
||||||
|
@ -1567,42 +1568,42 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
switch typ := typ.(type) {
|
switch typ := typ.(type) {
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
bufptr = val
|
bufptr = val
|
||||||
buflen = llvm.ConstInt(c.uintptrType, uint64(typ.Len()), false)
|
buflen = llvm.ConstInt(b.uintptrType, uint64(typ.Len()), false)
|
||||||
// Check for nil pointer before calculating the address, from
|
// Check for nil pointer before calculating the address, from
|
||||||
// the spec:
|
// the spec:
|
||||||
// > For an operand x of type T, the address operation &x
|
// > For an operand x of type T, the address operation &x
|
||||||
// > generates a pointer of type *T to x. [...] If the
|
// > generates a pointer of type *T to x. [...] If the
|
||||||
// > evaluation of x would cause a run-time panic, then the
|
// > evaluation of x would cause a run-time panic, then the
|
||||||
// > evaluation of &x does too.
|
// > evaluation of &x does too.
|
||||||
frame.createNilCheck(bufptr, "gep")
|
b.createNilCheck(bufptr, "gep")
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), "todo: indexaddr: "+typ.String())
|
return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+typ.String())
|
||||||
}
|
}
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
bufptr = c.builder.CreateExtractValue(val, 0, "indexaddr.ptr")
|
bufptr = b.CreateExtractValue(val, 0, "indexaddr.ptr")
|
||||||
buflen = c.builder.CreateExtractValue(val, 1, "indexaddr.len")
|
buflen = b.CreateExtractValue(val, 1, "indexaddr.len")
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), "todo: indexaddr: "+ptrTyp.String())
|
return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+ptrTyp.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounds check.
|
// Bounds check.
|
||||||
frame.createLookupBoundsCheck(buflen, index, expr.Index.Type())
|
b.createLookupBoundsCheck(buflen, index, expr.Index.Type())
|
||||||
|
|
||||||
switch expr.X.Type().Underlying().(type) {
|
switch expr.X.Type().Underlying().(type) {
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
indices := []llvm.Value{
|
indices := []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
index,
|
index,
|
||||||
}
|
}
|
||||||
return c.builder.CreateInBoundsGEP(bufptr, indices, ""), nil
|
return b.CreateInBoundsGEP(bufptr, indices, ""), nil
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
return c.builder.CreateInBoundsGEP(bufptr, []llvm.Value{index}, ""), nil
|
return b.CreateInBoundsGEP(bufptr, []llvm.Value{index}, ""), nil
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
case *ssa.Lookup:
|
case *ssa.Lookup:
|
||||||
value := frame.getValue(expr.X)
|
value := b.getValue(expr.X)
|
||||||
index := frame.getValue(expr.Index)
|
index := b.getValue(expr.Index)
|
||||||
switch xType := expr.X.Type().Underlying().(type) {
|
switch xType := expr.X.Type().Underlying().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
// Value type must be a string, which is a basic type.
|
// Value type must be a string, which is a basic type.
|
||||||
|
@ -1611,153 +1612,153 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounds check.
|
// Bounds check.
|
||||||
length := c.builder.CreateExtractValue(value, 1, "len")
|
length := b.CreateExtractValue(value, 1, "len")
|
||||||
frame.createLookupBoundsCheck(length, index, expr.Index.Type())
|
b.createLookupBoundsCheck(length, index, expr.Index.Type())
|
||||||
|
|
||||||
// Lookup byte
|
// Lookup byte
|
||||||
buf := c.builder.CreateExtractValue(value, 0, "")
|
buf := b.CreateExtractValue(value, 0, "")
|
||||||
bufPtr := c.builder.CreateInBoundsGEP(buf, []llvm.Value{index}, "")
|
bufPtr := b.CreateInBoundsGEP(buf, []llvm.Value{index}, "")
|
||||||
return c.builder.CreateLoad(bufPtr, ""), nil
|
return b.CreateLoad(bufPtr, ""), nil
|
||||||
case *types.Map:
|
case *types.Map:
|
||||||
valueType := expr.Type()
|
valueType := expr.Type()
|
||||||
if expr.CommaOk {
|
if expr.CommaOk {
|
||||||
valueType = valueType.(*types.Tuple).At(0).Type()
|
valueType = valueType.(*types.Tuple).At(0).Type()
|
||||||
}
|
}
|
||||||
return frame.createMapLookup(xType.Key(), valueType, value, index, expr.CommaOk, expr.Pos())
|
return b.createMapLookup(xType.Key(), valueType, value, index, expr.CommaOk, expr.Pos())
|
||||||
default:
|
default:
|
||||||
panic("unknown lookup type: " + expr.String())
|
panic("unknown lookup type: " + expr.String())
|
||||||
}
|
}
|
||||||
case *ssa.MakeChan:
|
case *ssa.MakeChan:
|
||||||
return frame.createMakeChan(expr), nil
|
return b.createMakeChan(expr), nil
|
||||||
case *ssa.MakeClosure:
|
case *ssa.MakeClosure:
|
||||||
return c.parseMakeClosure(frame, expr)
|
return b.parseMakeClosure(expr)
|
||||||
case *ssa.MakeInterface:
|
case *ssa.MakeInterface:
|
||||||
val := frame.getValue(expr.X)
|
val := b.getValue(expr.X)
|
||||||
return frame.createMakeInterface(val, expr.X.Type(), expr.Pos()), nil
|
return b.createMakeInterface(val, expr.X.Type(), expr.Pos()), nil
|
||||||
case *ssa.MakeMap:
|
case *ssa.MakeMap:
|
||||||
return frame.createMakeMap(expr)
|
return b.createMakeMap(expr)
|
||||||
case *ssa.MakeSlice:
|
case *ssa.MakeSlice:
|
||||||
sliceLen := frame.getValue(expr.Len)
|
sliceLen := b.getValue(expr.Len)
|
||||||
sliceCap := frame.getValue(expr.Cap)
|
sliceCap := b.getValue(expr.Cap)
|
||||||
sliceType := expr.Type().Underlying().(*types.Slice)
|
sliceType := expr.Type().Underlying().(*types.Slice)
|
||||||
llvmElemType := c.getLLVMType(sliceType.Elem())
|
llvmElemType := b.getLLVMType(sliceType.Elem())
|
||||||
elemSize := c.targetData.TypeAllocSize(llvmElemType)
|
elemSize := b.targetData.TypeAllocSize(llvmElemType)
|
||||||
elemSizeValue := llvm.ConstInt(c.uintptrType, elemSize, false)
|
elemSizeValue := llvm.ConstInt(b.uintptrType, elemSize, false)
|
||||||
|
|
||||||
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in
|
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in
|
||||||
// uintptr if uintptr were signed.
|
// uintptr if uintptr were signed.
|
||||||
maxSize := llvm.ConstLShr(llvm.ConstNot(llvm.ConstInt(c.uintptrType, 0, false)), llvm.ConstInt(c.uintptrType, 1, false))
|
maxSize := llvm.ConstLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false))
|
||||||
if elemSize > maxSize.ZExtValue() {
|
if elemSize > maxSize.ZExtValue() {
|
||||||
// This seems to be checked by the typechecker already, but let's
|
// This seems to be checked by the typechecker already, but let's
|
||||||
// check it again just to be sure.
|
// check it again just to be sure.
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), fmt.Sprintf("slice element type is too big (%v bytes)", elemSize))
|
return llvm.Value{}, b.makeError(expr.Pos(), fmt.Sprintf("slice element type is too big (%v bytes)", elemSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounds checking.
|
// Bounds checking.
|
||||||
lenType := expr.Len.Type().(*types.Basic)
|
lenType := expr.Len.Type().(*types.Basic)
|
||||||
capType := expr.Cap.Type().(*types.Basic)
|
capType := expr.Cap.Type().(*types.Basic)
|
||||||
frame.createSliceBoundsCheck(maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType)
|
b.createSliceBoundsCheck(maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType)
|
||||||
|
|
||||||
// Allocate the backing array.
|
// Allocate the backing array.
|
||||||
sliceCapCast, err := frame.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
|
sliceCapCast, err := b.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
sliceSize := c.builder.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
|
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
|
||||||
slicePtr := c.createRuntimeCall("alloc", []llvm.Value{sliceSize}, "makeslice.buf")
|
slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize}, "makeslice.buf")
|
||||||
slicePtr = c.builder.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array")
|
slicePtr = b.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array")
|
||||||
|
|
||||||
// Extend or truncate if necessary. This is safe as we've already done
|
// Extend or truncate if necessary. This is safe as we've already done
|
||||||
// the bounds check.
|
// the bounds check.
|
||||||
sliceLen, err = frame.createConvert(expr.Len.Type(), types.Typ[types.Uintptr], sliceLen, expr.Pos())
|
sliceLen, err = b.createConvert(expr.Len.Type(), types.Typ[types.Uintptr], sliceLen, expr.Pos())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
sliceCap, err = frame.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
|
sliceCap, err = b.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the slice.
|
// Create the slice.
|
||||||
slice := c.ctx.ConstStruct([]llvm.Value{
|
slice := b.ctx.ConstStruct([]llvm.Value{
|
||||||
llvm.Undef(slicePtr.Type()),
|
llvm.Undef(slicePtr.Type()),
|
||||||
llvm.Undef(c.uintptrType),
|
llvm.Undef(b.uintptrType),
|
||||||
llvm.Undef(c.uintptrType),
|
llvm.Undef(b.uintptrType),
|
||||||
}, false)
|
}, false)
|
||||||
slice = c.builder.CreateInsertValue(slice, slicePtr, 0, "")
|
slice = b.CreateInsertValue(slice, slicePtr, 0, "")
|
||||||
slice = c.builder.CreateInsertValue(slice, sliceLen, 1, "")
|
slice = b.CreateInsertValue(slice, sliceLen, 1, "")
|
||||||
slice = c.builder.CreateInsertValue(slice, sliceCap, 2, "")
|
slice = b.CreateInsertValue(slice, sliceCap, 2, "")
|
||||||
return slice, nil
|
return slice, nil
|
||||||
case *ssa.Next:
|
case *ssa.Next:
|
||||||
rangeVal := expr.Iter.(*ssa.Range).X
|
rangeVal := expr.Iter.(*ssa.Range).X
|
||||||
llvmRangeVal := frame.getValue(rangeVal)
|
llvmRangeVal := b.getValue(rangeVal)
|
||||||
it := frame.getValue(expr.Iter)
|
it := b.getValue(expr.Iter)
|
||||||
if expr.IsString {
|
if expr.IsString {
|
||||||
return c.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
|
return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
|
||||||
} else { // map
|
} else { // map
|
||||||
llvmKeyType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
llvmKeyType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
||||||
llvmValueType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
llvmValueType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
||||||
|
|
||||||
mapKeyAlloca, mapKeyPtr, mapKeySize := c.createTemporaryAlloca(llvmKeyType, "range.key")
|
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmKeyType, "range.key")
|
||||||
mapValueAlloca, mapValuePtr, mapValueSize := c.createTemporaryAlloca(llvmValueType, "range.value")
|
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
|
||||||
ok := c.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
|
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
|
||||||
|
|
||||||
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
||||||
tuple = c.builder.CreateInsertValue(tuple, ok, 0, "")
|
tuple = b.CreateInsertValue(tuple, ok, 0, "")
|
||||||
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapKeyAlloca, ""), 1, "")
|
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapKeyAlloca, ""), 1, "")
|
||||||
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapValueAlloca, ""), 2, "")
|
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapValueAlloca, ""), 2, "")
|
||||||
c.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
||||||
c.emitLifetimeEnd(mapValuePtr, mapValueSize)
|
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
|
||||||
return tuple, nil
|
return tuple, nil
|
||||||
}
|
}
|
||||||
case *ssa.Phi:
|
case *ssa.Phi:
|
||||||
phi := c.builder.CreatePHI(c.getLLVMType(expr.Type()), "")
|
phi := b.CreatePHI(b.getLLVMType(expr.Type()), "")
|
||||||
frame.phis = append(frame.phis, Phi{expr, phi})
|
b.phis = append(b.phis, Phi{expr, phi})
|
||||||
return phi, nil
|
return phi, nil
|
||||||
case *ssa.Range:
|
case *ssa.Range:
|
||||||
var iteratorType llvm.Type
|
var iteratorType llvm.Type
|
||||||
switch typ := expr.X.Type().Underlying().(type) {
|
switch typ := expr.X.Type().Underlying().(type) {
|
||||||
case *types.Basic: // string
|
case *types.Basic: // string
|
||||||
iteratorType = c.getLLVMRuntimeType("stringIterator")
|
iteratorType = b.getLLVMRuntimeType("stringIterator")
|
||||||
case *types.Map:
|
case *types.Map:
|
||||||
iteratorType = c.getLLVMRuntimeType("hashmapIterator")
|
iteratorType = b.getLLVMRuntimeType("hashmapIterator")
|
||||||
default:
|
default:
|
||||||
panic("unknown type in range: " + typ.String())
|
panic("unknown type in range: " + typ.String())
|
||||||
}
|
}
|
||||||
it, _, _ := c.createTemporaryAlloca(iteratorType, "range.it")
|
it, _, _ := b.createTemporaryAlloca(iteratorType, "range.it")
|
||||||
c.builder.CreateStore(llvm.ConstNull(iteratorType), it)
|
b.CreateStore(llvm.ConstNull(iteratorType), it)
|
||||||
return it, nil
|
return it, nil
|
||||||
case *ssa.Select:
|
case *ssa.Select:
|
||||||
return frame.createSelect(expr), nil
|
return b.createSelect(expr), nil
|
||||||
case *ssa.Slice:
|
case *ssa.Slice:
|
||||||
value := frame.getValue(expr.X)
|
value := b.getValue(expr.X)
|
||||||
|
|
||||||
var lowType, highType, maxType *types.Basic
|
var lowType, highType, maxType *types.Basic
|
||||||
var low, high, max llvm.Value
|
var low, high, max llvm.Value
|
||||||
|
|
||||||
if expr.Low != nil {
|
if expr.Low != nil {
|
||||||
lowType = expr.Low.Type().Underlying().(*types.Basic)
|
lowType = expr.Low.Type().Underlying().(*types.Basic)
|
||||||
low = frame.getValue(expr.Low)
|
low = b.getValue(expr.Low)
|
||||||
if low.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
|
if low.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
|
||||||
if lowType.Info()&types.IsUnsigned != 0 {
|
if lowType.Info()&types.IsUnsigned != 0 {
|
||||||
low = c.builder.CreateZExt(low, c.uintptrType, "")
|
low = b.CreateZExt(low, b.uintptrType, "")
|
||||||
} else {
|
} else {
|
||||||
low = c.builder.CreateSExt(low, c.uintptrType, "")
|
low = b.CreateSExt(low, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lowType = types.Typ[types.Uintptr]
|
lowType = types.Typ[types.Uintptr]
|
||||||
low = llvm.ConstInt(c.uintptrType, 0, false)
|
low = llvm.ConstInt(b.uintptrType, 0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expr.High != nil {
|
if expr.High != nil {
|
||||||
highType = expr.High.Type().Underlying().(*types.Basic)
|
highType = expr.High.Type().Underlying().(*types.Basic)
|
||||||
high = frame.getValue(expr.High)
|
high = b.getValue(expr.High)
|
||||||
if high.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
|
if high.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
|
||||||
if highType.Info()&types.IsUnsigned != 0 {
|
if highType.Info()&types.IsUnsigned != 0 {
|
||||||
high = c.builder.CreateZExt(high, c.uintptrType, "")
|
high = b.CreateZExt(high, b.uintptrType, "")
|
||||||
} else {
|
} else {
|
||||||
high = c.builder.CreateSExt(high, c.uintptrType, "")
|
high = b.CreateSExt(high, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1766,12 +1767,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
|
|
||||||
if expr.Max != nil {
|
if expr.Max != nil {
|
||||||
maxType = expr.Max.Type().Underlying().(*types.Basic)
|
maxType = expr.Max.Type().Underlying().(*types.Basic)
|
||||||
max = frame.getValue(expr.Max)
|
max = b.getValue(expr.Max)
|
||||||
if max.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
|
if max.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
|
||||||
if maxType.Info()&types.IsUnsigned != 0 {
|
if maxType.Info()&types.IsUnsigned != 0 {
|
||||||
max = c.builder.CreateZExt(max, c.uintptrType, "")
|
max = b.CreateZExt(max, b.uintptrType, "")
|
||||||
} else {
|
} else {
|
||||||
max = c.builder.CreateSExt(max, c.uintptrType, "")
|
max = b.CreateSExt(max, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1782,7 +1783,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
case *types.Pointer: // pointer to array
|
case *types.Pointer: // pointer to array
|
||||||
// slice an array
|
// slice an array
|
||||||
length := typ.Elem().Underlying().(*types.Array).Len()
|
length := typ.Elem().Underlying().(*types.Array).Len()
|
||||||
llvmLen := llvm.ConstInt(c.uintptrType, uint64(length), false)
|
llvmLen := llvm.ConstInt(b.uintptrType, uint64(length), false)
|
||||||
if high.IsNil() {
|
if high.IsNil() {
|
||||||
high = llvmLen
|
high = llvmLen
|
||||||
}
|
}
|
||||||
|
@ -1790,43 +1791,43 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
max = llvmLen
|
max = llvmLen
|
||||||
}
|
}
|
||||||
indices := []llvm.Value{
|
indices := []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
|
||||||
low,
|
low,
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.createSliceBoundsCheck(llvmLen, low, high, max, lowType, highType, maxType)
|
b.createSliceBoundsCheck(llvmLen, low, high, max, lowType, highType, maxType)
|
||||||
|
|
||||||
// Truncate ints bigger than uintptr. This is after the bounds
|
// Truncate ints bigger than uintptr. This is after the bounds
|
||||||
// check so it's safe.
|
// check so it's safe.
|
||||||
if c.targetData.TypeAllocSize(low.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
low = c.builder.CreateTrunc(low, c.uintptrType, "")
|
low = b.CreateTrunc(low, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
if c.targetData.TypeAllocSize(high.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
high = c.builder.CreateTrunc(high, c.uintptrType, "")
|
high = b.CreateTrunc(high, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
if c.targetData.TypeAllocSize(max.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(max.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
max = c.builder.CreateTrunc(max, c.uintptrType, "")
|
max = b.CreateTrunc(max, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
sliceLen := c.builder.CreateSub(high, low, "slice.len")
|
sliceLen := b.CreateSub(high, low, "slice.len")
|
||||||
slicePtr := c.builder.CreateInBoundsGEP(value, indices, "slice.ptr")
|
slicePtr := b.CreateInBoundsGEP(value, indices, "slice.ptr")
|
||||||
sliceCap := c.builder.CreateSub(max, low, "slice.cap")
|
sliceCap := b.CreateSub(max, low, "slice.cap")
|
||||||
|
|
||||||
slice := c.ctx.ConstStruct([]llvm.Value{
|
slice := b.ctx.ConstStruct([]llvm.Value{
|
||||||
llvm.Undef(slicePtr.Type()),
|
llvm.Undef(slicePtr.Type()),
|
||||||
llvm.Undef(c.uintptrType),
|
llvm.Undef(b.uintptrType),
|
||||||
llvm.Undef(c.uintptrType),
|
llvm.Undef(b.uintptrType),
|
||||||
}, false)
|
}, false)
|
||||||
slice = c.builder.CreateInsertValue(slice, slicePtr, 0, "")
|
slice = b.CreateInsertValue(slice, slicePtr, 0, "")
|
||||||
slice = c.builder.CreateInsertValue(slice, sliceLen, 1, "")
|
slice = b.CreateInsertValue(slice, sliceLen, 1, "")
|
||||||
slice = c.builder.CreateInsertValue(slice, sliceCap, 2, "")
|
slice = b.CreateInsertValue(slice, sliceCap, 2, "")
|
||||||
return slice, nil
|
return slice, nil
|
||||||
|
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
// slice a slice
|
// slice a slice
|
||||||
oldPtr := c.builder.CreateExtractValue(value, 0, "")
|
oldPtr := b.CreateExtractValue(value, 0, "")
|
||||||
oldLen := c.builder.CreateExtractValue(value, 1, "")
|
oldLen := b.CreateExtractValue(value, 1, "")
|
||||||
oldCap := c.builder.CreateExtractValue(value, 2, "")
|
oldCap := b.CreateExtractValue(value, 2, "")
|
||||||
if high.IsNil() {
|
if high.IsNil() {
|
||||||
high = oldLen
|
high = oldLen
|
||||||
}
|
}
|
||||||
|
@ -1834,76 +1835,76 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
max = oldCap
|
max = oldCap
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.createSliceBoundsCheck(oldCap, low, high, max, lowType, highType, maxType)
|
b.createSliceBoundsCheck(oldCap, low, high, max, lowType, highType, maxType)
|
||||||
|
|
||||||
// Truncate ints bigger than uintptr. This is after the bounds
|
// Truncate ints bigger than uintptr. This is after the bounds
|
||||||
// check so it's safe.
|
// check so it's safe.
|
||||||
if c.targetData.TypeAllocSize(low.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
low = c.builder.CreateTrunc(low, c.uintptrType, "")
|
low = b.CreateTrunc(low, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
if c.targetData.TypeAllocSize(high.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
high = c.builder.CreateTrunc(high, c.uintptrType, "")
|
high = b.CreateTrunc(high, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
if c.targetData.TypeAllocSize(max.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(max.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
max = c.builder.CreateTrunc(max, c.uintptrType, "")
|
max = b.CreateTrunc(max, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
newPtr := c.builder.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
|
newPtr := b.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
|
||||||
newLen := c.builder.CreateSub(high, low, "")
|
newLen := b.CreateSub(high, low, "")
|
||||||
newCap := c.builder.CreateSub(max, low, "")
|
newCap := b.CreateSub(max, low, "")
|
||||||
slice := c.ctx.ConstStruct([]llvm.Value{
|
slice := b.ctx.ConstStruct([]llvm.Value{
|
||||||
llvm.Undef(newPtr.Type()),
|
llvm.Undef(newPtr.Type()),
|
||||||
llvm.Undef(c.uintptrType),
|
llvm.Undef(b.uintptrType),
|
||||||
llvm.Undef(c.uintptrType),
|
llvm.Undef(b.uintptrType),
|
||||||
}, false)
|
}, false)
|
||||||
slice = c.builder.CreateInsertValue(slice, newPtr, 0, "")
|
slice = b.CreateInsertValue(slice, newPtr, 0, "")
|
||||||
slice = c.builder.CreateInsertValue(slice, newLen, 1, "")
|
slice = b.CreateInsertValue(slice, newLen, 1, "")
|
||||||
slice = c.builder.CreateInsertValue(slice, newCap, 2, "")
|
slice = b.CreateInsertValue(slice, newCap, 2, "")
|
||||||
return slice, nil
|
return slice, nil
|
||||||
|
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
if typ.Info()&types.IsString == 0 {
|
if typ.Info()&types.IsString == 0 {
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), "unknown slice type: "+typ.String())
|
return llvm.Value{}, b.makeError(expr.Pos(), "unknown slice type: "+typ.String())
|
||||||
}
|
}
|
||||||
// slice a string
|
// slice a string
|
||||||
if expr.Max != nil {
|
if expr.Max != nil {
|
||||||
// This might as well be a panic, as the frontend should have
|
// This might as well be a panic, as the frontend should have
|
||||||
// handled this already.
|
// handled this already.
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), "slicing a string with a max parameter is not allowed by the spec")
|
return llvm.Value{}, b.makeError(expr.Pos(), "slicing a string with a max parameter is not allowed by the spec")
|
||||||
}
|
}
|
||||||
oldPtr := c.builder.CreateExtractValue(value, 0, "")
|
oldPtr := b.CreateExtractValue(value, 0, "")
|
||||||
oldLen := c.builder.CreateExtractValue(value, 1, "")
|
oldLen := b.CreateExtractValue(value, 1, "")
|
||||||
if high.IsNil() {
|
if high.IsNil() {
|
||||||
high = oldLen
|
high = oldLen
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.createSliceBoundsCheck(oldLen, low, high, high, lowType, highType, maxType)
|
b.createSliceBoundsCheck(oldLen, low, high, high, lowType, highType, maxType)
|
||||||
|
|
||||||
// Truncate ints bigger than uintptr. This is after the bounds
|
// Truncate ints bigger than uintptr. This is after the bounds
|
||||||
// check so it's safe.
|
// check so it's safe.
|
||||||
if c.targetData.TypeAllocSize(low.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
low = c.builder.CreateTrunc(low, c.uintptrType, "")
|
low = b.CreateTrunc(low, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
if c.targetData.TypeAllocSize(high.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) {
|
||||||
high = c.builder.CreateTrunc(high, c.uintptrType, "")
|
high = b.CreateTrunc(high, b.uintptrType, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
newPtr := c.builder.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
|
newPtr := b.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
|
||||||
newLen := c.builder.CreateSub(high, low, "")
|
newLen := b.CreateSub(high, low, "")
|
||||||
str := llvm.Undef(c.getLLVMRuntimeType("_string"))
|
str := llvm.Undef(b.getLLVMRuntimeType("_string"))
|
||||||
str = c.builder.CreateInsertValue(str, newPtr, 0, "")
|
str = b.CreateInsertValue(str, newPtr, 0, "")
|
||||||
str = c.builder.CreateInsertValue(str, newLen, 1, "")
|
str = b.CreateInsertValue(str, newLen, 1, "")
|
||||||
return str, nil
|
return str, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), "unknown slice type: "+typ.String())
|
return llvm.Value{}, b.makeError(expr.Pos(), "unknown slice type: "+typ.String())
|
||||||
}
|
}
|
||||||
case *ssa.TypeAssert:
|
case *ssa.TypeAssert:
|
||||||
return frame.createTypeAssert(expr), nil
|
return b.createTypeAssert(expr), nil
|
||||||
case *ssa.UnOp:
|
case *ssa.UnOp:
|
||||||
return frame.createUnOp(expr)
|
return b.createUnOp(expr)
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, c.makeError(expr.Pos(), "todo: unknown expression: "+expr.String())
|
return llvm.Value{}, b.makeError(expr.Pos(), "todo: unknown expression: "+expr.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,24 +153,24 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
|
||||||
|
|
||||||
// parseMakeClosure makes a function value (with context) from the given
|
// parseMakeClosure makes a function value (with context) from the given
|
||||||
// closure expression.
|
// closure expression.
|
||||||
func (c *Compiler) parseMakeClosure(frame *Frame, expr *ssa.MakeClosure) (llvm.Value, error) {
|
func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
|
||||||
if len(expr.Bindings) == 0 {
|
if len(expr.Bindings) == 0 {
|
||||||
panic("unexpected: MakeClosure without bound variables")
|
panic("unexpected: MakeClosure without bound variables")
|
||||||
}
|
}
|
||||||
f := c.ir.GetFunction(expr.Fn.(*ssa.Function))
|
f := b.ir.GetFunction(expr.Fn.(*ssa.Function))
|
||||||
|
|
||||||
// Collect all bound variables.
|
// Collect all bound variables.
|
||||||
boundVars := make([]llvm.Value, len(expr.Bindings))
|
boundVars := make([]llvm.Value, len(expr.Bindings))
|
||||||
for i, binding := range expr.Bindings {
|
for i, binding := range expr.Bindings {
|
||||||
// The context stores the bound variables.
|
// The context stores the bound variables.
|
||||||
llvmBoundVar := frame.getValue(binding)
|
llvmBoundVar := b.getValue(binding)
|
||||||
boundVars[i] = llvmBoundVar
|
boundVars[i] = llvmBoundVar
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the bound variables in a single object, allocating it on the heap
|
// Store the bound variables in a single object, allocating it on the heap
|
||||||
// if necessary.
|
// if necessary.
|
||||||
context := c.emitPointerPack(boundVars)
|
context := b.emitPointerPack(boundVars)
|
||||||
|
|
||||||
// Create the closure.
|
// Create the closure.
|
||||||
return c.createFuncValue(f.LLVMFn, context, f.Signature), nil
|
return b.createFuncValue(f.LLVMFn, context, f.Signature), nil
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче