compiler: refactor creation of functions
Этот коммит содержится в:
родитель
ad992e2456
коммит
c8b5042870
2 изменённых файлов: 107 добавлений и 97 удалений
|
@ -82,13 +82,14 @@ func expandFormalParamType(t llvm.Type) []llvm.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand an argument type to a list of offsets from the start of the object.
|
// expandFormalParamOffsets returns a list of offsets from the start of an
|
||||||
// Used together with expandFormalParam to get the offset of each value from the
|
// object of type t after it would have been split up by expandFormalParam. This
|
||||||
// start of the non-expanded value.
|
// is useful for debug information, where it is necessary to know the offset
|
||||||
func (c *Compiler) expandFormalParamOffsets(t llvm.Type) []uint64 {
|
// from the start of the combined object.
|
||||||
|
func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
|
||||||
switch t.TypeKind() {
|
switch t.TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
fields := c.flattenAggregateTypeOffsets(t)
|
fields := b.flattenAggregateTypeOffsets(t)
|
||||||
if len(fields) <= MaxFieldsPerParam {
|
if len(fields) <= MaxFieldsPerParam {
|
||||||
return fields
|
return fields
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,10 +163,13 @@ func flattenAggregateType(t llvm.Type) []llvm.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the offsets from the start of the object if this object type were
|
// flattenAggregateTypeOffset returns the offsets from the start of an object of
|
||||||
// flattened like in flattenAggregate. Used together with flattenAggregate to
|
// type t if this object were flattened like in flattenAggregate. Used together
|
||||||
// know the start indices of each value in the non-flattened object.
|
// with flattenAggregate to know the start indices of each value in the
|
||||||
func (c *Compiler) flattenAggregateTypeOffsets(t llvm.Type) []uint64 {
|
// non-flattened object.
|
||||||
|
//
|
||||||
|
// Note: this is an implementation detail, use expandFormalParamOffsets instead.
|
||||||
|
func (c *compilerContext) flattenAggregateTypeOffsets(t llvm.Type) []uint64 {
|
||||||
switch t.TypeKind() {
|
switch t.TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
fields := make([]uint64, 0, t.StructElementTypesCount())
|
fields := make([]uint64, 0, t.StructElementTypesCount())
|
||||||
|
@ -217,25 +221,28 @@ func (b *builder) flattenAggregate(v llvm.Value) []llvm.Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collapse a list of fields into its original value.
|
// collapseFormalParam combines an aggregate object back into the original
|
||||||
func (c *Compiler) collapseFormalParam(t llvm.Type, fields []llvm.Value) llvm.Value {
|
// value. This is used to join multiple LLVM parameters into a single Go value
|
||||||
param, remaining := c.collapseFormalParamInternal(t, fields)
|
// in the function entry block.
|
||||||
|
func (b *builder) collapseFormalParam(t llvm.Type, fields []llvm.Value) llvm.Value {
|
||||||
|
param, remaining := b.collapseFormalParamInternal(t, fields)
|
||||||
if len(remaining) != 0 {
|
if len(remaining) != 0 {
|
||||||
panic("failed to expand back all fields")
|
panic("failed to expand back all fields")
|
||||||
}
|
}
|
||||||
return param
|
return param
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns (value, remainingFields). Used by collapseFormalParam.
|
// collapseFormalParamInternal is an implementation detail of
|
||||||
func (c *Compiler) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value) (llvm.Value, []llvm.Value) {
|
// collapseFormalParam: it works by recursing until there are no fields left.
|
||||||
|
func (b *builder) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value) (llvm.Value, []llvm.Value) {
|
||||||
switch t.TypeKind() {
|
switch t.TypeKind() {
|
||||||
case llvm.StructTypeKind:
|
case llvm.StructTypeKind:
|
||||||
if len(flattenAggregateType(t)) <= MaxFieldsPerParam {
|
if len(flattenAggregateType(t)) <= MaxFieldsPerParam {
|
||||||
value := llvm.ConstNull(t)
|
value := llvm.ConstNull(t)
|
||||||
for i, subtyp := range t.StructElementTypes() {
|
for i, subtyp := range t.StructElementTypes() {
|
||||||
structField, remaining := c.collapseFormalParamInternal(subtyp, fields)
|
structField, remaining := b.collapseFormalParamInternal(subtyp, fields)
|
||||||
fields = remaining
|
fields = remaining
|
||||||
value = c.builder.CreateInsertValue(value, structField, i, "")
|
value = b.CreateInsertValue(value, structField, i, "")
|
||||||
}
|
}
|
||||||
return value, fields
|
return value, fields
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -297,7 +297,7 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
if frame.fn.Blocks == nil {
|
if frame.fn.Blocks == nil {
|
||||||
continue // external function
|
continue // external function
|
||||||
}
|
}
|
||||||
c.parseFunc(frame)
|
frame.createFunctionDefinition()
|
||||||
}
|
}
|
||||||
|
|
||||||
// After all packages are imported, add a synthetic initializer function
|
// After all packages are imported, add a synthetic initializer function
|
||||||
|
@ -689,40 +689,40 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
|
||||||
// getLocalVariable returns a debug info entry for a local variable, which may
|
// getLocalVariable returns a debug info entry for a local variable, which may
|
||||||
// either be a parameter or a regular variable. It will create a new metadata
|
// either be a parameter or a regular variable. It will create a new metadata
|
||||||
// entry if there isn't one for the variable yet.
|
// entry if there isn't one for the variable yet.
|
||||||
func (c *Compiler) getLocalVariable(frame *Frame, variable *types.Var) llvm.Metadata {
|
func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata {
|
||||||
if dilocal, ok := frame.dilocals[variable]; ok {
|
if dilocal, ok := b.dilocals[variable]; ok {
|
||||||
// DILocalVariable was already created, return it directly.
|
// DILocalVariable was already created, return it directly.
|
||||||
return dilocal
|
return dilocal
|
||||||
}
|
}
|
||||||
|
|
||||||
pos := c.ir.Program.Fset.Position(variable.Pos())
|
pos := b.ir.Program.Fset.Position(variable.Pos())
|
||||||
|
|
||||||
// Check whether this is a function parameter.
|
// Check whether this is a function parameter.
|
||||||
for i, param := range frame.fn.Params {
|
for i, param := range b.fn.Params {
|
||||||
if param.Object().(*types.Var) == variable {
|
if param.Object().(*types.Var) == variable {
|
||||||
// Yes it is, create it as a function parameter.
|
// Yes it is, create it as a function parameter.
|
||||||
dilocal := c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{
|
dilocal := b.dibuilder.CreateParameterVariable(b.difunc, llvm.DIParameterVariable{
|
||||||
Name: param.Name(),
|
Name: param.Name(),
|
||||||
File: c.getDIFile(pos.Filename),
|
File: b.getDIFile(pos.Filename),
|
||||||
Line: pos.Line,
|
Line: pos.Line,
|
||||||
Type: c.getDIType(variable.Type()),
|
Type: b.getDIType(variable.Type()),
|
||||||
AlwaysPreserve: true,
|
AlwaysPreserve: true,
|
||||||
ArgNo: i + 1,
|
ArgNo: i + 1,
|
||||||
})
|
})
|
||||||
frame.dilocals[variable] = dilocal
|
b.dilocals[variable] = dilocal
|
||||||
return dilocal
|
return dilocal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No, it's not a parameter. Create a regular (auto) variable.
|
// No, it's not a parameter. Create a regular (auto) variable.
|
||||||
dilocal := c.dibuilder.CreateAutoVariable(frame.difunc, llvm.DIAutoVariable{
|
dilocal := b.dibuilder.CreateAutoVariable(b.difunc, llvm.DIAutoVariable{
|
||||||
Name: variable.Name(),
|
Name: variable.Name(),
|
||||||
File: c.getDIFile(pos.Filename),
|
File: b.getDIFile(pos.Filename),
|
||||||
Line: pos.Line,
|
Line: pos.Line,
|
||||||
Type: c.getDIType(variable.Type()),
|
Type: b.getDIType(variable.Type()),
|
||||||
AlwaysPreserve: true,
|
AlwaysPreserve: true,
|
||||||
})
|
})
|
||||||
frame.dilocals[variable] = dilocal
|
b.dilocals[variable] = dilocal
|
||||||
return dilocal
|
return dilocal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,86 +845,89 @@ func (c *compilerContext) getDIFile(filename string) llvm.Metadata {
|
||||||
return c.difiles[filename]
|
return c.difiles[filename]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) parseFunc(frame *Frame) {
|
// createFunctionDefinition builds the LLVM IR implementation for this function.
|
||||||
if c.DumpSSA() {
|
// The function must be declared but not yet defined, otherwise this function
|
||||||
fmt.Printf("\nfunc %s:\n", frame.fn.Function)
|
// will create a diagnostic.
|
||||||
|
func (b *builder) createFunctionDefinition() {
|
||||||
|
if b.DumpSSA() {
|
||||||
|
fmt.Printf("\nfunc %s:\n", b.fn.Function)
|
||||||
}
|
}
|
||||||
if !frame.fn.LLVMFn.IsDeclaration() {
|
if !b.fn.LLVMFn.IsDeclaration() {
|
||||||
errValue := frame.fn.LLVMFn.Name() + " redeclared in this program"
|
errValue := b.fn.Name() + " redeclared in this program"
|
||||||
fnPos := getPosition(frame.fn.LLVMFn)
|
fnPos := getPosition(b.fn.LLVMFn)
|
||||||
if fnPos.IsValid() {
|
if fnPos.IsValid() {
|
||||||
errValue += "\n\tprevious declaration at " + fnPos.String()
|
errValue += "\n\tprevious declaration at " + fnPos.String()
|
||||||
}
|
}
|
||||||
c.addError(frame.fn.Pos(), errValue)
|
b.addError(b.fn.Pos(), errValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !frame.fn.IsExported() {
|
if !b.fn.IsExported() {
|
||||||
frame.fn.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
b.fn.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
||||||
frame.fn.LLVMFn.SetUnnamedAddr(true)
|
b.fn.LLVMFn.SetUnnamedAddr(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some functions have a pragma controlling the inlining level.
|
// Some functions have a pragma controlling the inlining level.
|
||||||
switch frame.fn.Inline() {
|
switch b.fn.Inline() {
|
||||||
case ir.InlineHint:
|
case ir.InlineHint:
|
||||||
// Add LLVM inline hint to functions with //go:inline pragma.
|
// Add LLVM inline hint to functions with //go:inline pragma.
|
||||||
inline := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("inlinehint"), 0)
|
inline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("inlinehint"), 0)
|
||||||
frame.fn.LLVMFn.AddFunctionAttr(inline)
|
b.fn.LLVMFn.AddFunctionAttr(inline)
|
||||||
case ir.InlineNone:
|
case ir.InlineNone:
|
||||||
// Add LLVM attribute to always avoid inlining this function.
|
// Add LLVM attribute to always avoid inlining this function.
|
||||||
noinline := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noinline"), 0)
|
noinline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("noinline"), 0)
|
||||||
frame.fn.LLVMFn.AddFunctionAttr(noinline)
|
b.fn.LLVMFn.AddFunctionAttr(noinline)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add debug info, if needed.
|
// Add debug info, if needed.
|
||||||
if c.Debug() {
|
if b.Debug() {
|
||||||
if frame.fn.Synthetic == "package initializer" {
|
if b.fn.Synthetic == "package initializer" {
|
||||||
// Package initializers have no debug info. Create some fake debug
|
// Package initializers have no debug info. Create some fake debug
|
||||||
// info to at least have *something*.
|
// info to at least have *something*.
|
||||||
frame.difunc = c.attachDebugInfoRaw(frame.fn, frame.fn.LLVMFn, "", "", 0)
|
b.difunc = b.attachDebugInfoRaw(b.fn, b.fn.LLVMFn, "", "", 0)
|
||||||
} else if frame.fn.Syntax() != nil {
|
} else if b.fn.Syntax() != nil {
|
||||||
// Create debug info file if needed.
|
// Create debug info file if needed.
|
||||||
frame.difunc = c.attachDebugInfo(frame.fn)
|
b.difunc = b.attachDebugInfo(b.fn)
|
||||||
}
|
}
|
||||||
pos := c.ir.Program.Fset.Position(frame.fn.Pos())
|
pos := b.ir.Program.Fset.Position(b.fn.Pos())
|
||||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{})
|
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-create all basic blocks in the function.
|
// Pre-create all basic blocks in the function.
|
||||||
for _, block := range frame.fn.DomPreorder() {
|
for _, block := range b.fn.DomPreorder() {
|
||||||
llvmBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, block.Comment)
|
llvmBlock := b.ctx.AddBasicBlock(b.fn.LLVMFn, block.Comment)
|
||||||
frame.blockEntries[block] = llvmBlock
|
b.blockEntries[block] = llvmBlock
|
||||||
frame.blockExits[block] = llvmBlock
|
b.blockExits[block] = llvmBlock
|
||||||
}
|
}
|
||||||
entryBlock := frame.blockEntries[frame.fn.Blocks[0]]
|
entryBlock := b.blockEntries[b.fn.Blocks[0]]
|
||||||
c.builder.SetInsertPointAtEnd(entryBlock)
|
b.SetInsertPointAtEnd(entryBlock)
|
||||||
|
|
||||||
// Load function parameters
|
// Load function parameters
|
||||||
llvmParamIndex := 0
|
llvmParamIndex := 0
|
||||||
for _, param := range frame.fn.Params {
|
for _, param := range b.fn.Params {
|
||||||
llvmType := c.getLLVMType(param.Type())
|
llvmType := b.getLLVMType(param.Type())
|
||||||
fields := make([]llvm.Value, 0, 1)
|
fields := make([]llvm.Value, 0, 1)
|
||||||
for range expandFormalParamType(llvmType) {
|
for range expandFormalParamType(llvmType) {
|
||||||
fields = append(fields, frame.fn.LLVMFn.Param(llvmParamIndex))
|
fields = append(fields, b.fn.LLVMFn.Param(llvmParamIndex))
|
||||||
llvmParamIndex++
|
llvmParamIndex++
|
||||||
}
|
}
|
||||||
frame.locals[param] = c.collapseFormalParam(llvmType, fields)
|
b.locals[param] = b.collapseFormalParam(llvmType, fields)
|
||||||
|
|
||||||
// Add debug information to this parameter (if available)
|
// Add debug information to this parameter (if available)
|
||||||
if c.Debug() && frame.fn.Syntax() != nil {
|
if b.Debug() && b.fn.Syntax() != nil {
|
||||||
dbgParam := c.getLocalVariable(frame, param.Object().(*types.Var))
|
dbgParam := b.getLocalVariable(param.Object().(*types.Var))
|
||||||
loc := c.builder.GetCurrentDebugLocation()
|
loc := b.GetCurrentDebugLocation()
|
||||||
if len(fields) == 1 {
|
if len(fields) == 1 {
|
||||||
expr := c.dibuilder.CreateExpression(nil)
|
expr := b.dibuilder.CreateExpression(nil)
|
||||||
c.dibuilder.InsertValueAtEnd(fields[0], dbgParam, expr, loc, entryBlock)
|
b.dibuilder.InsertValueAtEnd(fields[0], dbgParam, expr, loc, entryBlock)
|
||||||
} else {
|
} else {
|
||||||
fieldOffsets := c.expandFormalParamOffsets(llvmType)
|
fieldOffsets := b.expandFormalParamOffsets(llvmType)
|
||||||
for i, field := range fields {
|
for i, field := range fields {
|
||||||
expr := c.dibuilder.CreateExpression([]int64{
|
expr := b.dibuilder.CreateExpression([]int64{
|
||||||
0x1000, // DW_OP_LLVM_fragment
|
0x1000, // DW_OP_LLVM_fragment
|
||||||
int64(fieldOffsets[i]) * 8, // offset in bits
|
int64(fieldOffsets[i]) * 8, // offset in bits
|
||||||
int64(c.targetData.TypeAllocSize(field.Type())) * 8, // size in bits
|
int64(b.targetData.TypeAllocSize(field.Type())) * 8, // size in bits
|
||||||
})
|
})
|
||||||
c.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock)
|
b.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -933,44 +936,44 @@ func (c *Compiler) parseFunc(frame *Frame) {
|
||||||
// Load free variables from the context. This is a closure (or bound
|
// Load free variables from the context. This is a closure (or bound
|
||||||
// method).
|
// method).
|
||||||
var context llvm.Value
|
var context llvm.Value
|
||||||
if !frame.fn.IsExported() {
|
if !b.fn.IsExported() {
|
||||||
parentHandle := frame.fn.LLVMFn.LastParam()
|
parentHandle := b.fn.LLVMFn.LastParam()
|
||||||
parentHandle.SetName("parentHandle")
|
parentHandle.SetName("parentHandle")
|
||||||
context = llvm.PrevParam(parentHandle)
|
context = llvm.PrevParam(parentHandle)
|
||||||
context.SetName("context")
|
context.SetName("context")
|
||||||
}
|
}
|
||||||
if len(frame.fn.FreeVars) != 0 {
|
if len(b.fn.FreeVars) != 0 {
|
||||||
// Get a list of all variable types in the context.
|
// Get a list of all variable types in the context.
|
||||||
freeVarTypes := make([]llvm.Type, len(frame.fn.FreeVars))
|
freeVarTypes := make([]llvm.Type, len(b.fn.FreeVars))
|
||||||
for i, freeVar := range frame.fn.FreeVars {
|
for i, freeVar := range b.fn.FreeVars {
|
||||||
freeVarTypes[i] = c.getLLVMType(freeVar.Type())
|
freeVarTypes[i] = b.getLLVMType(freeVar.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load each free variable from the context pointer.
|
// Load each free variable from the context pointer.
|
||||||
// A free variable is always a pointer when this is a closure, but it
|
// A free variable is always a pointer when this is a closure, but it
|
||||||
// can be another type when it is a wrapper for a bound method (these
|
// can be another type when it is a wrapper for a bound method (these
|
||||||
// wrappers are generated by the ssa package).
|
// wrappers are generated by the ssa package).
|
||||||
for i, val := range c.emitPointerUnpack(context, freeVarTypes) {
|
for i, val := range b.emitPointerUnpack(context, freeVarTypes) {
|
||||||
frame.locals[frame.fn.FreeVars[i]] = val
|
b.locals[b.fn.FreeVars[i]] = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if frame.fn.Recover != nil {
|
if b.fn.Recover != nil {
|
||||||
// This function has deferred function calls. Set some things up for
|
// This function has deferred function calls. Set some things up for
|
||||||
// them.
|
// them.
|
||||||
frame.deferInitFunc()
|
b.deferInitFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill blocks with instructions.
|
// Fill blocks with instructions.
|
||||||
for _, block := range frame.fn.DomPreorder() {
|
for _, block := range b.fn.DomPreorder() {
|
||||||
if c.DumpSSA() {
|
if b.DumpSSA() {
|
||||||
fmt.Printf("%d: %s:\n", block.Index, block.Comment)
|
fmt.Printf("%d: %s:\n", block.Index, block.Comment)
|
||||||
}
|
}
|
||||||
c.builder.SetInsertPointAtEnd(frame.blockEntries[block])
|
b.SetInsertPointAtEnd(b.blockEntries[block])
|
||||||
frame.currentBlock = block
|
b.currentBlock = block
|
||||||
for _, instr := range block.Instrs {
|
for _, instr := range block.Instrs {
|
||||||
if instr, ok := instr.(*ssa.DebugRef); ok {
|
if instr, ok := instr.(*ssa.DebugRef); ok {
|
||||||
if !c.Debug() {
|
if !b.Debug() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
object := instr.Object()
|
object := instr.Object()
|
||||||
|
@ -984,35 +987,35 @@ func (c *Compiler) parseFunc(frame *Frame) {
|
||||||
// for example.
|
// for example.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dbgVar := c.getLocalVariable(frame, variable)
|
dbgVar := b.getLocalVariable(variable)
|
||||||
pos := c.ir.Program.Fset.Position(instr.Pos())
|
pos := b.ir.Program.Fset.Position(instr.Pos())
|
||||||
c.dibuilder.InsertValueAtEnd(frame.getValue(instr.X), dbgVar, c.dibuilder.CreateExpression(nil), llvm.DebugLoc{
|
b.dibuilder.InsertValueAtEnd(b.getValue(instr.X), dbgVar, b.dibuilder.CreateExpression(nil), llvm.DebugLoc{
|
||||||
Line: uint(pos.Line),
|
Line: uint(pos.Line),
|
||||||
Col: uint(pos.Column),
|
Col: uint(pos.Column),
|
||||||
Scope: frame.difunc,
|
Scope: b.difunc,
|
||||||
}, c.builder.GetInsertBlock())
|
}, b.GetInsertBlock())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c.DumpSSA() {
|
if b.DumpSSA() {
|
||||||
if val, ok := instr.(ssa.Value); ok && val.Name() != "" {
|
if val, ok := instr.(ssa.Value); ok && val.Name() != "" {
|
||||||
fmt.Printf("\t%s = %s\n", val.Name(), val.String())
|
fmt.Printf("\t%s = %s\n", val.Name(), val.String())
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\t%s\n", instr.String())
|
fmt.Printf("\t%s\n", instr.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame.createInstruction(instr)
|
b.createInstruction(instr)
|
||||||
}
|
}
|
||||||
if frame.fn.Name() == "init" && len(block.Instrs) == 0 {
|
if b.fn.Name() == "init" && len(block.Instrs) == 0 {
|
||||||
c.builder.CreateRetVoid()
|
b.CreateRetVoid()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve phi nodes
|
// Resolve phi nodes
|
||||||
for _, phi := range frame.phis {
|
for _, phi := range b.phis {
|
||||||
block := phi.ssa.Block()
|
block := phi.ssa.Block()
|
||||||
for i, edge := range phi.ssa.Edges {
|
for i, edge := range phi.ssa.Edges {
|
||||||
llvmVal := frame.getValue(edge)
|
llvmVal := b.getValue(edge)
|
||||||
llvmBlock := frame.blockExits[block.Preds[i]]
|
llvmBlock := b.blockExits[block.Preds[i]]
|
||||||
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
|
phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче