mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-11 22:43:40 +00:00
compiler: pass large aggregates by pointer
LLVM ComputeValueVTs recursively expands arrays and structs into one value type per scalar leaf. SelectionDAG call lowering allocates data structures proportional to this count, which makes very large values exhaust memory or crash LLVM. Count scalar leaves and use pointers for internal parameters and results when the count exceeds 1024. A result pointer is the first parameter, and aggregate parameters point to read-only memory. Exported function types are unchanged. Keep these SSA values in memory and copy them with memcpy when needed. Handle calls, interfaces, maps, channels, selects, defers, goroutines, phis, and multiple results. Update the expected compiler IR and re-enable the native compress/flate tests.
This commit is contained in:
committed by
Damian Gryski
parent
3b7c9e24f5
commit
9e7d89d4d5
+46
-3
@@ -85,6 +85,10 @@ 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}, pos)
|
||||
return b.createMakeInterfaceFromPointer(itfValue, typ)
|
||||
}
|
||||
|
||||
func (b *builder) createMakeInterfaceFromPointer(itfValue llvm.Value, typ types.Type) llvm.Value {
|
||||
itfType := b.getTypeCode(typ)
|
||||
itf := llvm.Undef(b.getLLVMRuntimeType("_interface"))
|
||||
itf = b.CreateInsertValue(itf, itfType, 0, "")
|
||||
@@ -98,9 +102,16 @@ func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.
|
||||
// doesn't match the underlying type of the interface.
|
||||
func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type) llvm.Value {
|
||||
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
|
||||
if b.isIndirectAggregate(llvmType) {
|
||||
return valuePtr
|
||||
}
|
||||
return b.emitPointerUnpack(valuePtr, []llvm.Type{llvmType})[0]
|
||||
}
|
||||
|
||||
func (b *builder) extractValuePointerFromInterface(itf llvm.Value) llvm.Value {
|
||||
return b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
|
||||
}
|
||||
|
||||
func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value {
|
||||
pkgpathName := "reflect/types.type.pkgpath.empty"
|
||||
if pkgpath != "" {
|
||||
@@ -1067,6 +1078,21 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
if expr.CommaOk {
|
||||
nextBlock := b.insertBasicBlock("typeassert.next")
|
||||
b.currentBlockInfo.exit = nextBlock
|
||||
if b.isIndirectAggregate(assertedType) {
|
||||
resultType := b.getLLVMType(expr.Type())
|
||||
result := b.createIndirectStorage(resultType, "typeassert.result")
|
||||
b.zeroIndirectStorage(result, resultType)
|
||||
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
||||
|
||||
b.SetInsertPointAtEnd(okBlock)
|
||||
valuePtr := b.extractValuePointerFromInterface(itf)
|
||||
b.copyIndirectAggregate(b.CreateStructGEP(resultType, result, 0, ""), valuePtr, assertedType)
|
||||
b.CreateBr(nextBlock)
|
||||
|
||||
b.SetInsertPointAtEnd(nextBlock)
|
||||
b.CreateStore(commaOk, b.CreateStructGEP(resultType, result, 1, ""))
|
||||
return result
|
||||
}
|
||||
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
||||
|
||||
// Retrieve the value from the interface if the type assert was
|
||||
@@ -1206,6 +1232,9 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
|
||||
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
||||
c.addStandardDeclaredAttributes(llvmFn)
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-invoke", c.getMethodSignatureName(instr.Method)))
|
||||
if _, indirect := c.hasIndirectResult(sig); indirect {
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-indirect-result", "true"))
|
||||
}
|
||||
methods := c.getMethodsString(instr.Value.Type().Underlying().(*types.Interface))
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-methods", methods))
|
||||
}
|
||||
@@ -1251,6 +1280,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFnType
|
||||
// Get the expanded receiver type.
|
||||
receiverType := c.getLLVMType(fn.Signature.Recv().Type())
|
||||
var expandedReceiverType []llvm.Type
|
||||
receiverIndirect := c.isIndirectAggregate(receiverType)
|
||||
for _, info := range c.expandFormalParamType(receiverType, "", nil) {
|
||||
expandedReceiverType = append(expandedReceiverType, info.llvmType)
|
||||
}
|
||||
@@ -1265,7 +1295,13 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFnType
|
||||
}
|
||||
|
||||
// create wrapper function
|
||||
paramTypes := append([]llvm.Type{c.dataPtrType}, llvmFnType.ParamTypes()[len(expandedReceiverType):]...)
|
||||
resultOffset := 0
|
||||
if _, indirect := c.hasIndirectResult(fn.Signature); indirect {
|
||||
resultOffset = 1
|
||||
}
|
||||
paramTypes := append([]llvm.Type{}, llvmFnType.ParamTypes()[:resultOffset]...)
|
||||
paramTypes = append(paramTypes, c.dataPtrType)
|
||||
paramTypes = append(paramTypes, llvmFnType.ParamTypes()[resultOffset+len(expandedReceiverType):]...)
|
||||
wrapFnType := llvm.FunctionType(llvmFnType.ReturnType(), paramTypes, false)
|
||||
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
|
||||
c.addStandardAttributes(wrapper)
|
||||
@@ -1291,8 +1327,15 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFnType
|
||||
block := b.ctx.AddBasicBlock(wrapper, "entry")
|
||||
b.SetInsertPointAtEnd(block)
|
||||
|
||||
receiverValue := b.emitPointerUnpack(wrapper.Param(0), []llvm.Type{receiverType})[0]
|
||||
params := append(b.expandFormalParam(receiverValue), wrapper.Params()[1:]...)
|
||||
params := append([]llvm.Value{}, wrapper.Params()[:resultOffset]...)
|
||||
receiverParam := wrapper.Param(resultOffset)
|
||||
if receiverIndirect {
|
||||
params = append(params, receiverParam)
|
||||
} else {
|
||||
receiverValue := b.emitPointerUnpack(receiverParam, []llvm.Type{receiverType})[0]
|
||||
params = append(params, b.expandFormalParam(receiverValue)...)
|
||||
}
|
||||
params = append(params, wrapper.Params()[resultOffset+1:]...)
|
||||
if llvmFnType.ReturnType().TypeKind() == llvm.VoidTypeKind {
|
||||
b.CreateCall(llvmFnType, llvmFn, params, "")
|
||||
b.CreateRetVoid()
|
||||
|
||||
Reference in New Issue
Block a user