interp: fix alignment of untyped globals

During a run of interp, some memory (for example, memory allocated
through runtime.alloc) may not have a known LLVM type. This memory is
alllocated by creating an i8 array.
This does not necessarily work, as i8 has no alignment requirements
while the allocated object may have allocation requirements. Therefore,
the resulting global may have an alignment that is too loose.
This works on some microcontrollers but notably does not work on a
Cortex-M0 or Cortex-M0+, as all load/store operations must be aligned.

This commit fixes this by setting the alignment of untyped memory to the
maximum alignment. The determination of "maximum alignment" is not
great but should get the job done on most architectures.
This commit is contained in:
Ayke van Laethem
2020-12-27 00:18:05 +01:00
committed by Ron Evans
parent 30df912565
commit 5917b8baa2
2 changed files with 7 additions and 3 deletions
+4
View File
@@ -21,6 +21,8 @@ type runner struct {
targetData llvm.TargetData
builder llvm.Builder
pointerSize uint32 // cached pointer size from the TargetData
i8ptrType llvm.Type // often used type so created in advance
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
debug bool // log debug messages
pkgName string // package name of the currently executing package
functionCache map[llvm.Value]*function // cache of compiled functions
@@ -43,6 +45,8 @@ func Run(mod llvm.Module, debug bool) error {
start: time.Now(),
}
r.pointerSize = uint32(r.targetData.PointerSize())
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
r.maxAlign = r.targetData.PrefTypeAlignment(r.i8ptrType) // assume pointers are maximally aligned (this is not always the case)
initAll := mod.NamedFunction("runtime.initAll")
bb := initAll.EntryBasicBlock()
+3 -3
View File
@@ -522,6 +522,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu
globalType := initializer.Type()
llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName)
llvmValue.SetInitializer(initializer)
llvmValue.SetAlignment(mem.r.maxAlign)
obj.llvmGlobal = llvmValue
mem.put(v.index(), obj)
} else {
@@ -795,7 +796,6 @@ func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) llvm.Valu
// Convert these buckets into LLVM global variables.
ctx := v.r.mod.Context()
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
var nextBucket llvm.Value
for i := len(buckets) - 1; i >= 0; i-- {
bucket = buckets[i]
@@ -804,9 +804,9 @@ func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) llvm.Valu
}
firstBucket := nextBucket
if firstBucket.IsNil() {
firstBucket = llvm.ConstNull(i8ptrType)
firstBucket = llvm.ConstNull(mem.r.i8ptrType)
} else {
firstBucket = llvm.ConstBitCast(firstBucket, i8ptrType)
firstBucket = llvm.ConstBitCast(firstBucket, mem.r.i8ptrType)
}
// Create the hashmap itself, pointing to these buckets.