interp: make toLLVMValue return an error instead of panicking

This commit replaces a number of panics with returning an error value as
a result of changing the toLLVMValue method signature. This should make
it easier to diagnose issues.
Этот коммит содержится в:
Ayke van Laethem 2021-03-29 23:04:23 +02:00 коммит произвёл Ron Evans
родитель 8d93b9e545
коммит 35bf0746a1
3 изменённых файлов: 111 добавлений и 58 удалений

Просмотреть файл

@ -125,7 +125,10 @@ func Run(mod llvm.Module, debug bool) error {
if obj.buffer == nil { if obj.buffer == nil {
continue continue
} }
initializer := obj.buffer.toLLVMValue(obj.llvmGlobal.Type().ElementType(), &mem) initializer, err := obj.buffer.toLLVMValue(obj.llvmGlobal.Type().ElementType(), &mem)
if err != nil {
return err
}
if checks && initializer.Type() != obj.llvmGlobal.Type().ElementType() { if checks && initializer.Type() != obj.llvmGlobal.Type().ElementType() {
panic("initializer type mismatch") panic("initializer type mismatch")
} }

Просмотреть файл

@ -282,7 +282,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
fmt.Fprintln(os.Stderr, indent+"call (reflect.rawType).elem:", operands[1:]) fmt.Fprintln(os.Stderr, indent+"call (reflect.rawType).elem:", operands[1:])
} }
// Extract the type code global from the first parameter. // Extract the type code global from the first parameter.
typecodeID := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem).Operand(0) typecodeIDPtrToInt, err := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
typecodeID := typecodeIDPtrToInt.Operand(0)
// Get the type class. // Get the type class.
// See also: getClassAndValueFromTypeCode in transform/reflect.go. // See also: getClassAndValueFromTypeCode in transform/reflect.go.
@ -315,8 +319,14 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if r.debug { if r.debug {
fmt.Fprintln(os.Stderr, indent+"typeassert:", operands[1:]) fmt.Fprintln(os.Stderr, indent+"typeassert:", operands[1:])
} }
assertedType := operands[2].toLLVMValue(inst.llvmInst.Operand(1).Type(), &mem) assertedType, err := operands[2].toLLVMValue(inst.llvmInst.Operand(1).Type(), &mem)
actualTypePtrToInt := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem) if err != nil {
return nil, mem, r.errorAt(inst, err)
}
actualTypePtrToInt, err := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
actualType := actualTypePtrToInt.Operand(0) actualType := actualTypePtrToInt.Operand(0)
if actualType.Name()+"$id" == assertedType.Name() { if actualType.Name()+"$id" == assertedType.Name() {
locals[inst.localIndex] = literalValue{uint8(1)} locals[inst.localIndex] = literalValue{uint8(1)}
@ -377,7 +387,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// Load the first param, which is the type code (ptrtoint of the // Load the first param, which is the type code (ptrtoint of the
// type code global). // type code global).
typecodeID := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem).Operand(0).Initializer() typecodeIDPtrToInt, err := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
typecodeID := typecodeIDPtrToInt.Operand(0).Initializer()
// Load the method set, which is part of the typecodeID object. // Load the method set, which is part of the typecodeID object.
methodSet := llvm.ConstExtractValue(typecodeID, []uint32{2}).Operand(0).Initializer() methodSet := llvm.ConstExtractValue(typecodeID, []uint32{2}).Operand(0).Initializer()
@ -888,7 +902,11 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
for i := 0; i < numOperands; i++ { for i := 0; i < numOperands; i++ {
operand := inst.llvmInst.Operand(i) operand := inst.llvmInst.Operand(i)
if !operand.IsAInstruction().IsNil() || !operand.IsAArgument().IsNil() { if !operand.IsAInstruction().IsNil() || !operand.IsAArgument().IsNil() {
operand = locals[fn.locals[operand]].toLLVMValue(operand.Type(), mem) var err error
operand, err = locals[fn.locals[operand]].toLLVMValue(operand.Type(), mem)
if err != nil {
return r.errorAt(inst, err)
}
} }
operands[i] = operand operands[i] = operand
} }

Просмотреть файл

@ -314,7 +314,7 @@ type value interface {
asRawValue(*runner) rawValue asRawValue(*runner) rawValue
Uint() uint64 Uint() uint64
Int() int64 Int() int64
toLLVMValue(llvm.Type, *memoryView) llvm.Value toLLVMValue(llvm.Type, *memoryView) (llvm.Value, error)
String() string String() string
} }
@ -405,25 +405,25 @@ func (v literalValue) Int() int64 {
} }
} }
func (v literalValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value { func (v literalValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
switch llvmType.TypeKind() { switch llvmType.TypeKind() {
case llvm.IntegerTypeKind: case llvm.IntegerTypeKind:
switch value := v.value.(type) { switch value := v.value.(type) {
case uint64: case uint64:
return llvm.ConstInt(llvmType, value, false) return llvm.ConstInt(llvmType, value, false), nil
case uint32: case uint32:
return llvm.ConstInt(llvmType, uint64(value), false) return llvm.ConstInt(llvmType, uint64(value), false), nil
case uint16: case uint16:
return llvm.ConstInt(llvmType, uint64(value), false) return llvm.ConstInt(llvmType, uint64(value), false), nil
case uint8: case uint8:
return llvm.ConstInt(llvmType, uint64(value), false) return llvm.ConstInt(llvmType, uint64(value), false), nil
default: default:
panic("inpterp: unknown literal type") return llvm.Value{}, errors.New("interp: unknown literal type")
} }
case llvm.DoubleTypeKind: case llvm.DoubleTypeKind:
return llvm.ConstFloat(llvmType, math.Float64frombits(v.value.(uint64))) return llvm.ConstFloat(llvmType, math.Float64frombits(v.value.(uint64))), nil
case llvm.FloatTypeKind: case llvm.FloatTypeKind:
return llvm.ConstFloat(llvmType, float64(math.Float32frombits(v.value.(uint32)))) return llvm.ConstFloat(llvmType, float64(math.Float32frombits(v.value.(uint32)))), nil
default: default:
return v.asRawValue(mem.r).toLLVMValue(llvmType, mem) return v.asRawValue(mem.r).toLLVMValue(llvmType, mem)
} }
@ -507,7 +507,7 @@ func (v pointerValue) llvmValue(mem *memoryView) llvm.Value {
// toLLVMValue returns the LLVM value for this pointer, which may be a GEP or // toLLVMValue returns the LLVM value for this pointer, which may be a GEP or
// bitcast. The llvm.Type parameter is optional, if omitted the pointer type may // bitcast. The llvm.Type parameter is optional, if omitted the pointer type may
// be different than expected. // be different than expected.
func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value { func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
// Obtain the llvmValue, creating it if it doesn't exist yet. // Obtain the llvmValue, creating it if it doesn't exist yet.
llvmValue := v.llvmValue(mem) llvmValue := v.llvmValue(mem)
if llvmValue.IsNil() { if llvmValue.IsNil() {
@ -518,7 +518,10 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
if obj.llvmType.IsNil() { if obj.llvmType.IsNil() {
// Create an initializer without knowing the global type. // Create an initializer without knowing the global type.
// This is probably the result of a runtime.alloc call. // This is probably the result of a runtime.alloc call.
initializer := obj.buffer.asRawValue(mem.r).rawLLVMValue(mem) initializer, err := obj.buffer.asRawValue(mem.r).rawLLVMValue(mem)
if err != nil {
return llvm.Value{}, err
}
globalType := initializer.Type() globalType := initializer.Type()
llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName) llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName)
llvmValue.SetInitializer(initializer) llvmValue.SetInitializer(initializer)
@ -537,9 +540,12 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
// Set the initializer for the global. Do this after creation to avoid // Set the initializer for the global. Do this after creation to avoid
// infinite recursion between creating the global and creating the // infinite recursion between creating the global and creating the
// contents of the global (if the global contains itself). // contents of the global (if the global contains itself).
initializer := obj.buffer.toLLVMValue(globalType, mem) initializer, err := obj.buffer.toLLVMValue(globalType, mem)
if err != nil {
return llvm.Value{}, err
}
if checks && initializer.Type() != globalType { if checks && initializer.Type() != globalType {
panic("allocated value does not match allocated type") return llvm.Value{}, errors.New("interp: allocated value does not match allocated type")
} }
llvmValue.SetInitializer(initializer) llvmValue.SetInitializer(initializer)
} }
@ -552,7 +558,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
} }
if llvmType.IsNil() { if llvmType.IsNil() {
return llvmValue return llvmValue, nil
} }
if llvmType.TypeKind() != llvm.PointerTypeKind { if llvmType.TypeKind() != llvm.PointerTypeKind {
@ -564,7 +570,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
// This can be worked around by simply converting to a raw value, // This can be worked around by simply converting to a raw value,
// rawValue knows how to create such structs. // rawValue knows how to create such structs.
if v.offset() != 0 { if v.offset() != 0 {
panic("offset set without known pointer type") return llvm.Value{}, errors.New("interp: offset set without known pointer type")
} }
return v.asRawValue(mem.r).toLLVMValue(llvmType, mem) return v.asRawValue(mem.r).toLLVMValue(llvmType, mem)
} }
@ -575,14 +581,14 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
if v.offset() != 0 { if v.offset() != 0 {
// This should never happen, if offset is non-zero, the types // This should never happen, if offset is non-zero, the types
// shouldn't match. // shouldn't match.
panic("offset set while there is no way to convert the type") return llvm.Value{}, errors.New("interp: offset set while there is no way to convert the type")
} }
return llvmValue return llvmValue, nil
} }
if v.offset() == 0 { if v.offset() == 0 {
// Offset is zero, so we can just bitcast to get a correct pointer. // Offset is zero, so we can just bitcast to get a correct pointer.
return llvm.ConstBitCast(llvmValue, llvmType) return llvm.ConstBitCast(llvmValue, llvmType), nil
} }
// We need to make a constant GEP for pointer arithmetic. // We need to make a constant GEP for pointer arithmetic.
@ -606,11 +612,11 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
offset -= int64(mem.r.targetData.ElementOffset(objectElementType, element)) offset -= int64(mem.r.targetData.ElementOffset(objectElementType, element))
objectElementType = objectElementType.StructElementTypes()[element] objectElementType = objectElementType.StructElementTypes()[element]
default: default:
panic("pointer index with something other than a struct or array?") return llvm.Value{}, errors.New("interp: pointer index with something other than a struct or array?")
} }
} }
if offset < 0 { if offset < 0 {
panic("offset has somehow gone negative, this should be impossible") return llvm.Value{}, errors.New("interp: offset has somehow gone negative, this should be impossible")
} }
// Finally do the gep, using the above computed indices. // Finally do the gep, using the above computed indices.
@ -618,9 +624,9 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
// the bits of the pointer are now correct, just not the type). // the bits of the pointer are now correct, just not the type).
gep := llvm.ConstInBoundsGEP(llvmValue, indices) gep := llvm.ConstInBoundsGEP(llvmValue, indices)
if gep.Type() != llvmType { if gep.Type() != llvmType {
return llvm.ConstBitCast(gep, llvmType) return llvm.ConstBitCast(gep, llvmType), nil
} }
return gep return gep, nil
} }
// mapValue implements a Go map which is created at compile time and stored as a // mapValue implements a Go map which is created at compile time and stored as a
@ -713,7 +719,11 @@ func (b *mapBucket) create(ctx llvm.Context, nextBucket llvm.Value, mem *memoryV
// Create data for keys. // Create data for keys.
var keyValues []llvm.Value var keyValues []llvm.Value
for _, key := range b.keys { for _, key := range b.keys {
keyValues = append(keyValues, key.rawLLVMValue(mem)) keyValue, err := key.rawLLVMValue(mem)
if err != nil {
panic(err)
}
keyValues = append(keyValues, keyValue)
} }
if len(b.keys) < 8 { if len(b.keys) < 8 {
keyValues = append(keyValues, llvm.ConstNull(llvm.ArrayType(int8Type, int(b.m.keySize)*(8-len(b.keys))))) keyValues = append(keyValues, llvm.ConstNull(llvm.ArrayType(int8Type, int(b.m.keySize)*(8-len(b.keys)))))
@ -726,7 +736,11 @@ func (b *mapBucket) create(ctx llvm.Context, nextBucket llvm.Value, mem *memoryV
// Create data for values. // Create data for values.
var valueValues []llvm.Value var valueValues []llvm.Value
for _, value := range b.values { for _, value := range b.values {
valueValues = append(valueValues, value.rawLLVMValue(mem)) v, err := value.rawLLVMValue(mem)
if err != nil {
panic(err)
}
valueValues = append(valueValues, v)
} }
if len(b.values) < 8 { if len(b.values) < 8 {
valueValues = append(valueValues, llvm.ConstNull(llvm.ArrayType(int8Type, int(b.m.valueSize)*(8-len(b.values))))) valueValues = append(valueValues, llvm.ConstNull(llvm.ArrayType(int8Type, int(b.m.valueSize)*(8-len(b.values)))))
@ -750,9 +764,9 @@ func (b *mapBucket) create(ctx llvm.Context, nextBucket llvm.Value, mem *memoryV
return bucket return bucket
} }
func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) llvm.Value { func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) (llvm.Value, error) {
if !v.hashmap.IsNil() { if !v.hashmap.IsNil() {
return v.hashmap return v.hashmap, nil
} }
// Create a slice of buckets with all the keys and values in the hashmap. // Create a slice of buckets with all the keys and values in the hashmap.
@ -772,12 +786,12 @@ func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) llvm.Valu
copy(keyValue.buf[v.keySize/2:], literalValue{key.size}.asRawValue(v.r).buf) copy(keyValue.buf[v.keySize/2:], literalValue{key.size}.asRawValue(v.r).buf)
case rawValue: case rawValue:
if key.hasPointer() { if key.hasPointer() {
panic("todo: map key with pointer") return llvm.Value{}, errors.New("interp: todo: map key with pointer")
} }
data = key.buf data = key.buf
keyValue = key keyValue = key
default: default:
panic("unknown map key type") return llvm.Value{}, errors.New("interp: unknown map key type")
} }
buf := make([]byte, len(data)) buf := make([]byte, len(data))
for i, p := range data { for i, p := range data {
@ -821,7 +835,7 @@ func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) llvm.Valu
}) })
v.hashmap = hashmap v.hashmap = hashmap
return v.hashmap return v.hashmap, nil
} }
// putString does a map assign operation, assuming that the map is of type // putString does a map assign operation, assuming that the map is of type
@ -1018,7 +1032,7 @@ func (v rawValue) equal(rhs rawValue) bool {
// goes. The resulting value does not have a specified type, but it will be the // goes. The resulting value does not have a specified type, but it will be the
// same size and have the same bytes if it was created with a provided LLVM type // same size and have the same bytes if it was created with a provided LLVM type
// (through toLLVMValue). // (through toLLVMValue).
func (v rawValue) rawLLVMValue(mem *memoryView) llvm.Value { func (v rawValue) rawLLVMValue(mem *memoryView) (llvm.Value, error) {
var structFields []llvm.Value var structFields []llvm.Value
ctx := mem.r.mod.Context() ctx := mem.r.mod.Context()
int8Type := ctx.Int8Type() int8Type := ctx.Int8Type()
@ -1042,7 +1056,10 @@ func (v rawValue) rawLLVMValue(mem *memoryView) llvm.Value {
for i := uint32(0); i < uint32(len(v.buf)); { for i := uint32(0); i < uint32(len(v.buf)); {
if v.buf[i] > 255 { if v.buf[i] > 255 {
addBytes() addBytes()
field := pointerValue{v.buf[i]}.toLLVMValue(llvm.Type{}, mem) field, err := pointerValue{v.buf[i]}.toLLVMValue(llvm.Type{}, mem)
if err != nil {
return llvm.Value{}, err
}
elementType := field.Type().ElementType() elementType := field.Type().ElementType()
if elementType.TypeKind() == llvm.StructTypeKind { if elementType.TypeKind() == llvm.StructTypeKind {
// There are some special pointer types that should be used as a // There are some special pointer types that should be used as a
@ -1065,12 +1082,12 @@ func (v rawValue) rawLLVMValue(mem *memoryView) llvm.Value {
// Return the created data. // Return the created data.
if len(structFields) == 1 { if len(structFields) == 1 {
return structFields[0] return structFields[0], nil
} }
return ctx.ConstStruct(structFields, false) return ctx.ConstStruct(structFields, false), nil
} }
func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value { func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
isZero := true isZero := true
for _, p := range v.buf { for _, p := range v.buf {
if p != 0 { if p != 0 {
@ -1079,7 +1096,7 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value {
} }
} }
if isZero { if isZero {
return llvm.ConstNull(llvmType) return llvm.ConstNull(llvmType), nil
} }
switch llvmType.TypeKind() { switch llvmType.TypeKind() {
case llvm.IntegerTypeKind: case llvm.IntegerTypeKind:
@ -1088,7 +1105,11 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return llvm.ConstPtrToInt(ptr.toLLVMValue(llvm.Type{}, mem), llvmType) v, err := ptr.toLLVMValue(llvm.Type{}, mem)
if err != nil {
return llvm.Value{}, err
}
return llvm.ConstPtrToInt(v, llvmType), nil
} }
var n uint64 var n uint64
switch llvmType.IntTypeWidth() { switch llvmType.IntTypeWidth() {
@ -1108,7 +1129,7 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value {
default: default:
panic("unknown integer size") panic("unknown integer size")
} }
return llvm.ConstInt(llvmType, n, false) return llvm.ConstInt(llvmType, n, false), nil
case llvm.StructTypeKind: case llvm.StructTypeKind:
fieldTypes := llvmType.StructElementTypes() fieldTypes := llvmType.StructElementTypes()
fields := make([]llvm.Value, len(fieldTypes)) fields := make([]llvm.Value, len(fieldTypes))
@ -1117,12 +1138,16 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value {
field := rawValue{ field := rawValue{
buf: v.buf[offset:], buf: v.buf[offset:],
} }
fields[i] = field.toLLVMValue(fieldType, mem) var err error
fields[i], err = field.toLLVMValue(fieldType, mem)
if err != nil {
return llvm.Value{}, err
}
} }
if llvmType.StructName() != "" { if llvmType.StructName() != "" {
return llvm.ConstNamedStruct(llvmType, fields) return llvm.ConstNamedStruct(llvmType, fields), nil
} }
return llvmType.Context().ConstStruct(fields, false) return llvmType.Context().ConstStruct(fields, false), nil
case llvm.ArrayTypeKind: case llvm.ArrayTypeKind:
numElements := llvmType.ArrayLength() numElements := llvmType.ArrayLength()
childType := llvmType.ElementType() childType := llvmType.ElementType()
@ -1133,27 +1158,34 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value {
field := rawValue{ field := rawValue{
buf: v.buf[offset:], buf: v.buf[offset:],
} }
fields[i] = field.toLLVMValue(childType, mem) var err error
fields[i], err = field.toLLVMValue(childType, mem)
if err != nil {
return llvm.Value{}, err
}
if checks && fields[i].Type() != childType { if checks && fields[i].Type() != childType {
panic("child type doesn't match") panic("child type doesn't match")
} }
} }
return llvm.ConstArray(childType, fields) return llvm.ConstArray(childType, fields), nil
case llvm.PointerTypeKind: case llvm.PointerTypeKind:
if v.buf[0] > 255 { if v.buf[0] > 255 {
// This is a regular pointer. // This is a regular pointer.
llvmValue := pointerValue{v.buf[0]}.toLLVMValue(llvm.Type{}, mem) llvmValue, err := pointerValue{v.buf[0]}.toLLVMValue(llvm.Type{}, mem)
if err != nil {
return llvm.Value{}, err
}
if llvmValue.Type() != llvmType { if llvmValue.Type() != llvmType {
llvmValue = llvm.ConstBitCast(llvmValue, llvmType) llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
} }
return llvmValue return llvmValue, nil
} }
// This is either a null pointer or a raw pointer for memory-mapped I/O // This is either a null pointer or a raw pointer for memory-mapped I/O
// (such as 0xe000ed00). // (such as 0xe000ed00).
ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint() ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint()
if ptr == 0 { if ptr == 0 {
// Null pointer. // Null pointer.
return llvm.ConstNull(llvmType) return llvm.ConstNull(llvmType), nil
} }
var ptrValue llvm.Value // the underlying int var ptrValue llvm.Value // the underlying int
switch mem.r.pointerSize { switch mem.r.pointerSize {
@ -1164,19 +1196,19 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value {
case 2: case 2:
ptrValue = llvm.ConstInt(llvmType.Context().Int16Type(), ptr, false) ptrValue = llvm.ConstInt(llvmType.Context().Int16Type(), ptr, false)
default: default:
panic("unknown pointer size") return llvm.Value{}, errors.New("interp: unknown pointer size")
} }
return llvm.ConstIntToPtr(ptrValue, llvmType) return llvm.ConstIntToPtr(ptrValue, llvmType), nil
case llvm.DoubleTypeKind: case llvm.DoubleTypeKind:
b := rawValue{v.buf[:8]}.Uint() b := rawValue{v.buf[:8]}.Uint()
f := math.Float64frombits(b) f := math.Float64frombits(b)
return llvm.ConstFloat(llvmType, f) return llvm.ConstFloat(llvmType, f), nil
case llvm.FloatTypeKind: case llvm.FloatTypeKind:
b := uint32(rawValue{v.buf[:4]}.Uint()) b := uint32(rawValue{v.buf[:4]}.Uint())
f := math.Float32frombits(b) f := math.Float32frombits(b)
return llvm.ConstFloat(llvmType, float64(f)) return llvm.ConstFloat(llvmType, float64(f)), nil
default: default:
panic("todo: raw value to LLVM value: " + llvmType.String()) return llvm.Value{}, errors.New("interp: todo: raw value to LLVM value: " + llvmType.String())
} }
} }
@ -1365,8 +1397,8 @@ func (v localValue) Int() int64 {
panic("interp: localValue.Int") panic("interp: localValue.Int")
} }
func (v localValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Value { func (v localValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
return v.value return v.value, nil
} }
func (r *runner) getValue(llvmValue llvm.Value) value { func (r *runner) getValue(llvmValue llvm.Value) value {