interp: align created globals

Use the alignment from the align attribute of the runtime.alloc call.
This is going to be a more accurate alignment, and is typically smaller
than the default.
This commit is contained in:
Ayke van Laethem
2024-11-20 13:15:21 +01:00
committed by Ron Evans
parent 5f252b3e16
commit ecc6d16f22
3 changed files with 19 additions and 7 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ func TestBinarySize(t *testing.T) {
// microcontrollers // microcontrollers
{"hifive1b", "examples/echo", 4600, 280, 0, 2268}, {"hifive1b", "examples/echo", 4600, 280, 0, 2268},
{"microbit", "examples/serial", 2908, 388, 8, 2272}, {"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 // TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the // wasm binaries are run through wasm-opt and therefore the
+9
View File
@@ -287,9 +287,17 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// Get the object layout, if it is available. // Get the object layout, if it is available.
llvmLayoutType := r.getLLVMTypeFromLayout(operands[2]) 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. // Create the object.
alloc := object{ alloc := object{
globalName: r.pkgName + "$alloc", globalName: r.pkgName + "$alloc",
align: alignment,
llvmLayoutType: llvmLayoutType, llvmLayoutType: llvmLayoutType,
buffer: newRawValue(uint32(size)), buffer: newRawValue(uint32(size)),
size: uint32(size), size: uint32(size),
@@ -646,6 +654,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
globalName: r.pkgName + "$alloca", globalName: r.pkgName + "$alloca",
buffer: newRawValue(uint32(size)), buffer: newRawValue(uint32(size)),
size: uint32(size), size: uint32(size),
align: inst.llvmInst.Alignment(),
} }
index := len(r.objects) index := len(r.objects)
r.objects = append(r.objects, alloca) r.objects = append(r.objects, alloca)
+9 -6
View File
@@ -42,6 +42,7 @@ type object struct {
globalName string // name, if not yet created (not guaranteed to be the final name) 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 buffer value // buffer with value as given by interp, nil if external
size uint32 // must match buffer.len(), if available 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 constant bool // true if this is a constant global
marked uint8 // 0 means unmarked, 1 means external read, 2 means external write 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. // runtime.alloc.
// First allocate a new global for this object. // First allocate a new global for this object.
obj := mem.get(v.index()) 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() { if obj.llvmType.IsNil() && obj.llvmLayoutType.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.
@@ -603,7 +610,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
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)
llvmValue.SetAlignment(mem.r.maxAlign) llvmValue.SetAlignment(alignment)
obj.llvmGlobal = llvmValue obj.llvmGlobal = llvmValue
mem.put(v.index(), obj) mem.put(v.index(), obj)
} else { } 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") return llvm.Value{}, errors.New("interp: allocated value does not match allocated type")
} }
llvmValue.SetInitializer(initializer) llvmValue.SetInitializer(initializer)
if obj.llvmType.IsNil() { llvmValue.SetAlignment(alignment)
// 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)
}
} }
// It should be included in r.globals because otherwise markExternal // It should be included in r.globals because otherwise markExternal