Skip to content

Commit 9490789

Browse files
committed
compiler: bound aggregate call signatures
Plan internal aggregate parameter lowering from each complete function signature. Count scalar leaves, the context parameter, and any hidden aggregate-result pointer, then pass the largest aggregates indirectly until the signature fits within the 1,000-parameter limit. Keep the ABI policy target-independent and leave fitting signatures unchanged. Include the interface typecode when budgeting invoke signatures and keep parameter lowering consistent between concrete and interface calls. Preserve exported ABIs and diagnose exported methods that cannot use the internal interface ABI. Attach valid debug metadata to these diagnostic wrappers so that errors keep their source positions. Materialize indirect aggregate phi inputs in their predecessor blocks. Retain temporary argument-promotion guards through the ThinLTO pre-link pipeline, then remove the guards before final dead-code elimination. Validate final WebAssembly signatures that cannot be rewritten.
1 parent 7f1f99b commit 9490789

15 files changed

Lines changed: 832 additions & 125 deletions

builder/build.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
651651
if err != nil {
652652
return err
653653
}
654+
if strings.HasPrefix(config.Triple(), "wasm") {
655+
if err := compiler.ValidateWasmFunctionParameters(mod); err != nil {
656+
return err
657+
}
658+
}
654659

655660
// Make sure stack sizes are loaded from a separate section so they can be
656661
// modified after linking.

compiler/calls.go

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,6 @@ func (b *builder) createInvoke(fnType llvm.Type, fn llvm.Value, args []llvm.Valu
102102
return b.createCall(fnType, fn, args, name)
103103
}
104104

105-
// Expand an argument type to a list that can be used in a function call
106-
// parameter list.
107-
func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
108-
if c.isIndirectAggregate(t) {
109-
return []paramInfo{{
110-
llvmType: c.dataPtrType,
111-
name: name,
112-
elemSize: c.targetData.TypeAllocSize(t),
113-
flags: paramIsGoParam | paramIsReadonly | paramIsIndirect,
114-
}}
115-
}
116-
return c.expandDirectFormalParamType(t, name, goType)
117-
}
118-
119105
func (c *compilerContext) expandDirectFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
120106
switch t.TypeKind() {
121107
case llvm.StructTypeKind:
@@ -130,34 +116,36 @@ func (c *compilerContext) expandDirectFormalParamType(t llvm.Type, name string,
130116
return []paramInfo{c.getParamInfo(t, name, goType)}
131117
}
132118

133-
func (c *compilerContext) storedParamType(t llvm.Type, exported bool) llvm.Type {
134-
if c.isIndirectParam(t, exported) {
119+
func (c *compilerContext) storedParamType(t llvm.Type) llvm.Type {
120+
if c.isIndirectAggregate(t) {
135121
return c.dataPtrType
136122
}
137123
return t
138124
}
139125

140-
func (c *compilerContext) isIndirectParam(t llvm.Type, exported bool) bool {
141-
return !exported && c.isIndirectAggregate(t)
142-
}
143-
144-
func (b *builder) appendStoredValueTypes(valueTypes []llvm.Type, values []ssa.Value, exported bool) []llvm.Type {
145-
for _, value := range values {
146-
valueTypes = append(valueTypes, b.storedParamType(b.getLLVMType(value.Type()), exported))
126+
func (b *builder) appendStoredParamTypes(valueTypes []llvm.Type, params []functionABIParam) []llvm.Type {
127+
for _, param := range params {
128+
if param.indirect {
129+
valueTypes = append(valueTypes, b.dataPtrType)
130+
} else {
131+
valueTypes = append(valueTypes, param.llvmType)
132+
}
147133
}
148134
return valueTypes
149135
}
150136

151-
func (b *builder) appendStoredParamTypes(valueTypes []llvm.Type, params []*types.Var, exported bool) []llvm.Type {
152-
for _, param := range params {
153-
valueTypes = append(valueTypes, b.storedParamType(b.getLLVMType(param.Type()), exported))
137+
func (b *builder) getCallArguments(values []ssa.Value, params []functionABIParam) []llvm.Value {
138+
args := make([]llvm.Value, len(values))
139+
for i, value := range values {
140+
args[i] = b.getCallArgument(value, params[i].indirect)
154141
}
155-
return valueTypes
142+
return args
156143
}
157144

158145
func (b *builder) prependIndirectResult(sig *types.Signature, exported bool, params []llvm.Value, name string) []llvm.Value {
159-
if resultType, indirect := b.hasIndirectResult(sig); !exported && indirect {
160-
return append([]llvm.Value{b.createIndirectStorage(resultType, name)}, params...)
146+
abi := b.getFunctionABI(sig, exported)
147+
if abi.indirectResult {
148+
return append([]llvm.Value{b.createIndirectStorage(abi.resultType, name)}, params...)
161149
}
162150
return params
163151
}
@@ -184,8 +172,8 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
184172

185173
// expandFormalParam splits a formal param value into pieces, so it can be
186174
// passed directly as part of a function call. For example, it splits up small
187-
// structs into individual fields. It is the equivalent of expandFormalParamType
188-
// for parameter values.
175+
// structs into individual fields. It is the equivalent of
176+
// expandDirectFormalParamType for parameter values.
189177
func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
190178
switch v.Type().TypeKind() {
191179
case llvm.StructTypeKind:

compiler/compiler.go

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ type compilerContext struct {
8787
program *ssa.Program
8888
diagnostics []error
8989
functionInfos map[*ssa.Function]functionInfo
90+
functionABIs map[functionABIKey]functionABI
9091
astComments map[string]*ast.CommentGroup
9192
embedGlobals map[string][]*loader.EmbedFile
9293
pkg *types.Package
@@ -107,6 +108,7 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C
107108
machine: machine,
108109
targetData: machine.CreateTargetData(),
109110
functionInfos: map[*ssa.Function]functionInfo{},
111+
functionABIs: map[functionABIKey]functionABI{},
110112
astComments: map[string]*ast.CommentGroup{},
111113
}
112114

@@ -789,18 +791,26 @@ func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata {
789791
return dilocal
790792
}
791793

792-
// attachDebugInfo adds debug info to a function declaration. It returns the
794+
// attachDebugInfo adds debug info to a function. It returns the
793795
// DISubprogram metadata node.
794796
func (c *compilerContext) attachDebugInfo(f *ssa.Function) llvm.Metadata {
795797
pos := c.program.Fset.Position(f.Syntax().Pos())
796798
_, fn := c.getFunction(f)
797799
return c.attachDebugInfoRaw(f, fn, "", pos.Filename, pos.Line)
798800
}
799801

800-
// attachDebugInfo adds debug info to a function declaration. It returns the
802+
// attachDebugInfoRaw adds debug info to a function. It returns the
801803
// DISubprogram metadata node. This method allows some more control over how
802804
// debug info is added to the function.
803805
func (c *compilerContext) attachDebugInfoRaw(f *ssa.Function, llvmFn llvm.Value, suffix, filename string, line int) llvm.Metadata {
806+
return c.attachDebugInfoRawWithDefinition(f, llvmFn, suffix, filename, line, true)
807+
}
808+
809+
func (c *compilerContext) attachDebugInfoDeclarationRaw(f *ssa.Function, llvmFn llvm.Value, suffix, filename string, line int) llvm.Metadata {
810+
return c.attachDebugInfoRawWithDefinition(f, llvmFn, suffix, filename, line, false)
811+
}
812+
813+
func (c *compilerContext) attachDebugInfoRawWithDefinition(f *ssa.Function, llvmFn llvm.Value, suffix, filename string, line int, isDefinition bool) llvm.Metadata {
804814
// Debug info for this function.
805815
params := getParams(f.Signature)
806816
diparams := make([]llvm.Metadata, 0, len(params))
@@ -819,7 +829,7 @@ func (c *compilerContext) attachDebugInfoRaw(f *ssa.Function, llvmFn llvm.Value,
819829
Line: line,
820830
Type: diFuncType,
821831
LocalToUnit: true,
822-
IsDefinition: true,
832+
IsDefinition: isDefinition,
823833
ScopeLine: 0,
824834
Flags: llvm.FlagPrototyped,
825835
Optimized: true,
@@ -1284,27 +1294,23 @@ func (b *builder) createFunctionStart(intrinsic bool) {
12841294
}
12851295

12861296
// Load function parameters
1297+
abi := b.getFunctionABI(b.fn.Signature, b.info.exported)
12871298
llvmParamIndex := 0
1288-
if _, indirectResult := b.hasIndirectResult(b.fn.Signature); indirectResult && !b.info.exported {
1299+
if abi.indirectResult {
12891300
b.indirectReturn = b.llvmFn.Param(llvmParamIndex)
12901301
b.indirectReturn.SetName("return")
12911302
llvmParamIndex++
12921303
}
1293-
for _, param := range b.fn.Params {
1294-
llvmType := b.getLLVMType(param.Type())
1295-
if b.isIndirectParam(llvmType, b.info.exported) {
1304+
for i, param := range b.fn.Params {
1305+
llvmType := abi.params[i].llvmType
1306+
if abi.params[i].indirect {
12961307
llvmParam := b.llvmFn.Param(llvmParamIndex)
12971308
llvmParam.SetName(param.Name())
12981309
b.indirectValues[param] = llvmParam
12991310
llvmParamIndex++
13001311
continue
13011312
}
1302-
var paramInfos []paramInfo
1303-
if b.info.exported {
1304-
paramInfos = b.expandDirectFormalParamType(llvmType, param.Name(), param.Type())
1305-
} else {
1306-
paramInfos = b.expandFormalParamType(llvmType, param.Name(), param.Type())
1307-
}
1313+
paramInfos := b.expandDirectFormalParamType(llvmType, param.Name(), param.Type())
13081314
fields := make([]llvm.Value, 0, 1)
13091315
for _, info := range paramInfos {
13101316
param := b.llvmFn.Param(llvmParamIndex)
@@ -1441,14 +1447,20 @@ func (b *builder) createFunction() {
14411447
}
14421448

14431449
// Resolve phi nodes
1450+
phiBuilder := b.ctx.NewBuilder()
1451+
originalBuilder := b.Builder
1452+
b.Builder = phiBuilder
14441453
for _, phi := range b.phis {
14451454
block := phi.ssa.Block()
14461455
for i, edge := range phi.ssa.Edges {
1447-
llvmVal := b.getCallArgument(edge, false)
14481456
llvmBlock := b.blockInfo[block.Preds[i].Index].exit
1457+
b.SetInsertPointBefore(llvmBlock.LastInstruction())
1458+
llvmVal := b.getCallArgument(edge, b.isIndirectAggregate(b.getLLVMType(edge.Type())))
14491459
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
14501460
}
14511461
}
1462+
b.Builder = originalBuilder
1463+
phiBuilder.Dispose()
14521464

14531465
if b.NeedsStackObjects {
14541466
// Track phi nodes.
@@ -1676,9 +1688,8 @@ func (b *builder) getValuePointer(value ssa.Value) llvm.Value {
16761688
return ptr
16771689
}
16781690

1679-
func (b *builder) getCallArgument(value ssa.Value, exported bool) llvm.Value {
1680-
paramType := b.getLLVMType(value.Type())
1681-
if b.isIndirectParam(paramType, exported) {
1691+
func (b *builder) getCallArgument(value ssa.Value, indirect bool) llvm.Value {
1692+
if indirect {
16821693
return b.getValuePointer(value)
16831694
}
16841695
return b.getValue(value, getPos(value))
@@ -2323,18 +2334,21 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
23232334
b.createNilCheck(instr.Value, callee, "fpcall")
23242335
}
23252336

2326-
var params []llvm.Value
2327-
for _, param := range instr.Args {
2328-
params = append(params, b.getCallArgument(param, exported))
2337+
abi := b.getFunctionABI(instr.Signature(), exported)
2338+
paramOffset := 0
2339+
if instr.IsInvoke() {
2340+
abi = b.getInterfaceFunctionABI(instr.Signature())
2341+
paramOffset = 1
23292342
}
2343+
params := b.getCallArguments(instr.Args, abi.params[paramOffset:])
23302344
if instr.IsInvoke() {
23312345
params = append([]llvm.Value{invokeReceiver}, params...)
23322346
params = append(params, invokeTypecode)
23332347
}
23342348

23352349
if !exported {
2336-
if resultType, indirectResult := b.hasIndirectResult(instr.Signature()); indirectResult {
2337-
result := b.createIndirectStorage(resultType, "call.result")
2350+
if abi.indirectResult {
2351+
result := b.createIndirectStorage(abi.resultType, "call.result")
23382352
params = append([]llvm.Value{result}, params...)
23392353
params = append(params, context)
23402354
b.createInvoke(calleeType, callee, params, "")
@@ -2715,7 +2729,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
27152729
return b.createMapIteratorNext(rangeVal, llvmRangeVal, it), nil
27162730
}
27172731
case *ssa.Phi:
2718-
phiType := b.storedParamType(b.getLLVMType(expr.Type()), false)
2732+
phiType := b.storedParamType(b.getLLVMType(expr.Type()))
27192733
phi := b.CreatePHI(phiType, "")
27202734
b.phis = append(b.phis, phiNode{expr, phi})
27212735
return phi, nil

0 commit comments

Comments
 (0)