diff --git a/builder/sizes_test.go b/builder/sizes_test.go index 650a5fbb5..bda5e0760 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -43,7 +43,7 @@ func TestBinarySize(t *testing.T) { // microcontrollers {"hifive1b", "examples/echo", 4600, 280, 0, 2268}, {"microbit", "examples/serial", 2908, 388, 8, 2272}, - {"wioterminal", "examples/pininterrupt", 6140, 1484, 116, 6832}, + {"wioterminal", "examples/pininterrupt", 6140, 1484, 116, 6824}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/interp/interpreter.go b/interp/interpreter.go index 512d93eb7..20d56c69e 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -287,9 +287,17 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent // Get the object layout, if it is available. llvmLayoutType := r.getLLVMTypeFromLayout(operands[2]) + // Get the alignment of the memory to be allocated. + alignment := 0 // use default alignment if unset + alignAttr := inst.llvmInst.GetCallSiteEnumAttribute(0, llvm.AttributeKindID("align")) + if !alignAttr.IsNil() { + alignment = int(alignAttr.GetEnumValue()) + } + // Create the object. alloc := object{ globalName: r.pkgName + "$alloc", + align: alignment, llvmLayoutType: llvmLayoutType, buffer: newRawValue(uint32(size)), size: uint32(size), @@ -646,6 +654,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent globalName: r.pkgName + "$alloca", buffer: newRawValue(uint32(size)), size: uint32(size), + align: inst.llvmInst.Alignment(), } index := len(r.objects) r.objects = append(r.objects, alloca) diff --git a/interp/memory.go b/interp/memory.go index 176228fdc..3b36a80b3 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -42,6 +42,7 @@ type object struct { globalName string // name, if not yet created (not guaranteed to be the final name) buffer value // buffer with value as given by interp, nil if external size uint32 // must match buffer.len(), if available + align int // alignment of the object (may be 0 if unknown) constant bool // true if this is a constant global marked uint8 // 0 means unmarked, 1 means external read, 2 means external write } @@ -593,6 +594,12 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val // runtime.alloc. // First allocate a new global for this object. obj := mem.get(v.index()) + alignment := obj.align + if alignment == 0 { + // Unknown alignment, perhaps from a direct call to runtime.alloc in + // the runtime. Use a conservative default instead. + alignment = mem.r.maxAlign + } if obj.llvmType.IsNil() && obj.llvmLayoutType.IsNil() { // Create an initializer without knowing the global type. // This is probably the result of a runtime.alloc call. @@ -603,7 +610,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val globalType := initializer.Type() llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName) llvmValue.SetInitializer(initializer) - llvmValue.SetAlignment(mem.r.maxAlign) + llvmValue.SetAlignment(alignment) obj.llvmGlobal = llvmValue mem.put(v.index(), obj) } else { @@ -642,11 +649,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val return llvm.Value{}, errors.New("interp: allocated value does not match allocated type") } llvmValue.SetInitializer(initializer) - if obj.llvmType.IsNil() { - // The exact type isn't known (only the layout), so use the - // alignment that would normally be expected from runtime.alloc. - llvmValue.SetAlignment(mem.r.maxAlign) - } + llvmValue.SetAlignment(alignment) } // It should be included in r.globals because otherwise markExternal