From bac2042cdfea4b2346bbfff34e6228800bdbce12 Mon Sep 17 00:00:00 2001 From: Nia Waldvogel Date: Wed, 8 Jul 2026 13:03:00 -0400 Subject: [PATCH] compiler: consistently pass layout and alignment to createAlloc --- compiler/compiler.go | 3 +-- compiler/defer.go | 5 +++-- compiler/func.go | 2 +- compiler/gc.go | 5 +---- compiler/goroutine.go | 2 +- compiler/interface.go | 2 +- compiler/llvm.go | 5 +++-- compiler/testdata/defer-cortex-m-qemu.ll | 4 ++-- compiler/testdata/gc.ll | 2 +- compiler/testdata/goroutine-cortex-m-qemu-tasks.ll | 6 +++--- compiler/testdata/goroutine-wasm-asyncify.ll | 6 +++--- 11 files changed, 20 insertions(+), 22 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index ec553e196d..03bc16bf67 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -2415,8 +2415,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) { } sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap") layoutValue := b.createObjectLayout(llvmElemType, expr.Pos()) - slicePtr := b.createAlloc(sliceSize, layoutValue, 0, "makeslice.buf") - slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign))) + slicePtr := b.createAlloc(sliceSize, layoutValue, elemAlign, "makeslice.buf") // Extend or truncate if necessary. This is safe as we've already done // the bounds check. diff --git a/compiler/defer.go b/compiler/defer.go index 3a91f87677..6385b506d1 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -504,8 +504,9 @@ func (b *builder) createDefer(instr *ssa.Defer) { // This may be hit a variable number of times, so use a heap allocation. size := b.targetData.TypeAllocSize(deferredCallType) sizeValue := llvm.ConstInt(b.uintptrType, size, false) - nilPtr := llvm.ConstNull(b.dataPtrType) - alloca = b.createAlloc(sizeValue, nilPtr, 0, "defer.alloc.call") + layoutValue := b.createObjectLayout(deferredCallType, instr.Pos()) + align := b.targetData.ABITypeAlignment(deferredCallType) + alloca = b.createAlloc(sizeValue, layoutValue, align, "defer.alloc.call") } if b.NeedsStackObjects { b.trackPointer(alloca) diff --git a/compiler/func.go b/compiler/func.go index 665d7ddd09..ed5808c72f 100644 --- a/compiler/func.go +++ b/compiler/func.go @@ -112,7 +112,7 @@ func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) { // Store the bound variables in a single object, allocating it on the heap // if necessary. - context := b.emitPointerPack(boundVars) + context := b.emitPointerPack(boundVars, expr.Pos()) // Create the closure. _, fn := b.getFunction(f) diff --git a/compiler/gc.go b/compiler/gc.go index 40785ee7ab..a6b6d9f51b 100644 --- a/compiler/gc.go +++ b/compiler/gc.go @@ -29,10 +29,7 @@ func (b *builder) createAlloc(sizeValue, layoutValue llvm.Value, align int, comm // Make the runtime call. call := b.createRuntimeCall(allocFunc, []llvm.Value{sizeValue, layoutValue}, comment) - if align != 0 { - // TODO: make sure all callsites set the correct alignment. - call.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))) - } + call.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))) return call } diff --git a/compiler/goroutine.go b/compiler/goroutine.go index 30c8ef2426..291afe1d1a 100644 --- a/compiler/goroutine.go +++ b/compiler/goroutine.go @@ -100,7 +100,7 @@ func (b *builder) createGo(instr *ssa.Go) { prefix = b.fn.RelString(nil) } - paramBundle := b.emitPointerPack(params) + paramBundle := b.emitPointerPack(params, instr.Pos()) var stackSize llvm.Value callee := b.createGoroutineStartWrapper(funcType, funcPtr, prefix, hasContext, false, instr.Pos()) if b.AutomaticStackSize { diff --git a/compiler/interface.go b/compiler/interface.go index 3908a69d18..5b1b53b5ca 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -84,7 +84,7 @@ const ( // // An interface value is a {typecode, value} tuple named runtime._interface. func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.Pos) llvm.Value { - itfValue := b.emitPointerPack([]llvm.Value{val}) + itfValue := b.emitPointerPack([]llvm.Value{val}, pos) itfType := b.getTypeCode(typ) itf := llvm.Undef(b.getLLVMRuntimeType("_interface")) itf = b.CreateInsertValue(itf, itfType, 0, "") diff --git a/compiler/llvm.go b/compiler/llvm.go index 8a31ede086..d3ba3537cc 100644 --- a/compiler/llvm.go +++ b/compiler/llvm.go @@ -54,7 +54,7 @@ func (b *builder) emitLifetimeEnd(ptr, size llvm.Value) { // pointer value directly. It returns the pointer with the packed data. // If the values are all constants, they are be stored in a constant global and // deduplicated. -func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value { +func (b *builder) emitPointerPack(values []llvm.Value, pos token.Pos) llvm.Value { valueTypes := make([]llvm.Type, len(values)) for i, value := range values { valueTypes[i] = value.Type() @@ -128,8 +128,9 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value { // Packed data is bigger than a pointer, so allocate it on the heap. sizeValue := llvm.ConstInt(b.uintptrType, size, false) + layoutValue := b.createObjectLayout(packedType, pos) align := b.targetData.ABITypeAlignment(packedType) - packedAlloc := b.createAlloc(sizeValue, llvm.ConstNull(b.dataPtrType), align, "") + packedAlloc := b.createAlloc(sizeValue, layoutValue, align, "") if b.NeedsStackObjects { b.trackPointer(packedAlloc) } diff --git a/compiler/testdata/defer-cortex-m-qemu.ll b/compiler/testdata/defer-cortex-m-qemu.ll index 852fcff7bd..550f817f4e 100644 --- a/compiler/testdata/defer-cortex-m-qemu.ll +++ b/compiler/testdata/defer-cortex-m-qemu.ll @@ -278,7 +278,7 @@ entry: for.body: ; preds = %for.body, %entry %defer.next = load ptr, ptr %deferPtr, align 4 - %defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4 + %defer.alloc.call = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 135 to ptr), ptr undef) #4 store i32 0, ptr %defer.alloc.call, align 4 %defer.alloc.call.repack1 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4 store ptr %defer.next, ptr %defer.alloc.call.repack1, align 4 @@ -330,7 +330,7 @@ for.loop: ; preds = %for.body, %entry for.body: ; preds = %for.loop %defer.next = load ptr, ptr %deferPtr, align 4 - %defer.alloc.call = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #4 + %defer.alloc.call = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 135 to ptr), ptr undef) #4 store i32 0, ptr %defer.alloc.call, align 4 %defer.alloc.call.repack13 = getelementptr inbounds nuw i8, ptr %defer.alloc.call, i32 4 store ptr %defer.next, ptr %defer.alloc.call.repack13, align 4 diff --git a/compiler/testdata/gc.ll b/compiler/testdata/gc.ll index e2b0090698..194c7913a6 100644 --- a/compiler/testdata/gc.ll +++ b/compiler/testdata/gc.ll @@ -131,7 +131,7 @@ entry: define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3 + %0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3 store double %v.r, ptr %0, align 8 %.repack1 = getelementptr inbounds nuw i8, ptr %0, i32 8 diff --git a/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll b/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll index a1e81a9b1b..cfec582ce5 100644 --- a/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll +++ b/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll @@ -60,7 +60,7 @@ define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #0 entry: %n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #11 store i32 3, ptr %n, align 4 - %0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11 + %0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 133 to ptr), ptr undef) #11 store i32 5, ptr %0, align 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4 store ptr %n, ptr %1, align 4 @@ -102,7 +102,7 @@ declare void @runtime.printunlock(ptr) #1 ; Function Attrs: nounwind define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #0 { entry: - %0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11 + %0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 391 to ptr), ptr undef) #11 store i32 5, ptr %0, align 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4 store ptr %fn.context, ptr %1, align 4 @@ -157,7 +157,7 @@ declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #1 ; Function Attrs: nounwind define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #0 { entry: - %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11 + %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr nonnull inttoptr (i32 713 to ptr), ptr undef) #11 store ptr %itf.value, ptr %0, align 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4 store ptr @"main$string", ptr %1, align 4 diff --git a/compiler/testdata/goroutine-wasm-asyncify.ll b/compiler/testdata/goroutine-wasm-asyncify.ll index 137b601f77..59cbdf18ab 100644 --- a/compiler/testdata/goroutine-wasm-asyncify.ll +++ b/compiler/testdata/goroutine-wasm-asyncify.ll @@ -66,7 +66,7 @@ entry: store i32 3, ptr %n, align 4 call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #11 call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #11 - %0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #11 + %0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 133 to ptr), ptr undef) #11 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11 store i32 5, ptr %0, align 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4 @@ -110,7 +110,7 @@ declare void @runtime.printunlock(ptr) #0 define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #11 + %0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 391 to ptr), ptr undef) #11 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11 store i32 5, ptr %0, align 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4 @@ -167,7 +167,7 @@ declare void @runtime.chanClose(ptr dereferenceable_or_null(36), ptr) #0 define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #11 + %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr nonnull inttoptr (i32 713 to ptr), ptr undef) #11 call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #11 store ptr %itf.value, ptr %0, align 4 %1 = getelementptr inbounds nuw i8, ptr %0, i32 4