build: separate compiler and libs
This commit is contained in:
791
compiler/ssa/di.go
Normal file
791
compiler/ssa/di.go
Normal file
@@ -0,0 +1,791 @@
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"path/filepath"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llvm"
|
||||
)
|
||||
|
||||
type Positioner interface {
|
||||
Position(pos token.Pos) token.Position
|
||||
}
|
||||
|
||||
type aDIBuilder struct {
|
||||
di *llvm.DIBuilder
|
||||
prog Program
|
||||
types map[Type]DIType
|
||||
positioner Positioner
|
||||
m llvm.Module // Add this field
|
||||
}
|
||||
|
||||
type diBuilder = *aDIBuilder
|
||||
|
||||
func newDIBuilder(prog Program, pkg Package, positioner Positioner) diBuilder {
|
||||
m := pkg.mod
|
||||
ctx := m.Context()
|
||||
|
||||
b := &aDIBuilder{
|
||||
di: llvm.NewDIBuilder(m),
|
||||
prog: prog,
|
||||
types: make(map[*aType]DIType),
|
||||
positioner: positioner,
|
||||
m: m, // Initialize the m field
|
||||
}
|
||||
|
||||
b.addNamedMetadataOperand("llvm.module.flags", 2, "Debug Info Version", 3)
|
||||
b.addNamedMetadataOperand("llvm.module.flags", 7, "Dwarf Version", 4)
|
||||
b.addNamedMetadataOperand("llvm.module.flags", 1, "wchar_size", 4)
|
||||
b.addNamedMetadataOperand("llvm.module.flags", 8, "PIC Level", 2)
|
||||
b.addNamedMetadataOperand("llvm.module.flags", 7, "uwtable", 1)
|
||||
b.addNamedMetadataOperand("llvm.module.flags", 7, "frame-pointer", 1)
|
||||
|
||||
// Add llvm.ident metadata
|
||||
identNode := ctx.MDNode([]llvm.Metadata{
|
||||
ctx.MDString("LLGo Compiler"),
|
||||
})
|
||||
m.AddNamedMetadataOperand("llvm.ident", identNode)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// New method to add named metadata operand
|
||||
func (b diBuilder) addNamedMetadataOperand(name string, intValue int, stringValue string, intValue2 int) {
|
||||
ctx := b.m.Context()
|
||||
b.m.AddNamedMetadataOperand(name,
|
||||
ctx.MDNode([]llvm.Metadata{
|
||||
llvm.ConstInt(ctx.Int32Type(), uint64(intValue), false).ConstantAsMetadata(),
|
||||
ctx.MDString(stringValue),
|
||||
llvm.ConstInt(ctx.Int32Type(), uint64(intValue2), false).ConstantAsMetadata(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aCompilationUnit struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type CompilationUnit = *aCompilationUnit
|
||||
|
||||
func (c CompilationUnit) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta {
|
||||
return &aDIScopeMeta{c.ll}
|
||||
}
|
||||
|
||||
var DWARF_LANG_C llvm.DwarfLang = 0x2
|
||||
var DWARF_LANG_GO llvm.DwarfLang = 0x16
|
||||
|
||||
func (b diBuilder) createCompileUnit(filename, dir string) CompilationUnit {
|
||||
return &aCompilationUnit{ll: b.di.CreateCompileUnit(llvm.DICompileUnit{
|
||||
// TODO(lijie): use C language for now, change after Go plugin of LLDB is ready
|
||||
Language: DWARF_LANG_C - 1,
|
||||
File: filename,
|
||||
Dir: dir,
|
||||
Producer: "LLGo",
|
||||
Optimized: true,
|
||||
RuntimeVersion: 1,
|
||||
})}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDIScopeMeta struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DIScopeMeta = *aDIScopeMeta
|
||||
|
||||
type DIScope interface {
|
||||
scopeMeta(b diBuilder, pos token.Position) DIScopeMeta
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDIFile struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DIFile = *aDIFile
|
||||
|
||||
func (b diBuilder) createFile(filename string) DIFile {
|
||||
dir, file := filepath.Split(filename)
|
||||
return &aDIFile{ll: b.di.CreateFile(file, dir)}
|
||||
}
|
||||
|
||||
func (f DIFile) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta {
|
||||
return &aDIScopeMeta{b.file(pos.Filename).ll}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDIType struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DIType = *aDIType
|
||||
|
||||
func (b diBuilder) createType(name string, ty Type, pos token.Position) DIType {
|
||||
var typ llvm.Metadata
|
||||
switch t := ty.RawType().(type) {
|
||||
case *types.Basic:
|
||||
if t.Kind() == types.UnsafePointer {
|
||||
typ = b.di.CreatePointerType(llvm.DIPointerType{
|
||||
Name: name,
|
||||
SizeInBits: b.prog.SizeOf(b.prog.rawType(t)) * 8,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(t) * 8),
|
||||
})
|
||||
return &aDIType{typ}
|
||||
}
|
||||
|
||||
var encoding llvm.DwarfTypeEncoding
|
||||
if t.Info()&types.IsBoolean != 0 {
|
||||
encoding = llvm.DW_ATE_boolean
|
||||
} else if t.Info()&types.IsUnsigned != 0 {
|
||||
encoding = llvm.DW_ATE_unsigned
|
||||
} else if t.Info()&types.IsInteger != 0 {
|
||||
encoding = llvm.DW_ATE_signed
|
||||
} else if t.Info()&types.IsFloat != 0 {
|
||||
encoding = llvm.DW_ATE_float
|
||||
} else if t.Info()&types.IsComplex != 0 {
|
||||
return b.createComplexType(ty)
|
||||
} else if t.Info()&types.IsString != 0 {
|
||||
return b.createStringType()
|
||||
} else {
|
||||
panic(fmt.Errorf("can't create debug info of basic type: %v, %T", ty.RawType(), ty.RawType()))
|
||||
}
|
||||
|
||||
typ = b.di.CreateBasicType(llvm.DIBasicType{
|
||||
Name: name,
|
||||
SizeInBits: b.prog.SizeOf(b.prog.rawType(t)) * 8,
|
||||
Encoding: encoding,
|
||||
})
|
||||
case *types.Pointer:
|
||||
return b.createPointerType(name, b.prog.rawType(t.Elem()), pos)
|
||||
case *types.Named:
|
||||
// Create typedef type for named types
|
||||
return b.createTypedefType(name, ty, pos)
|
||||
case *types.Interface:
|
||||
ty := b.prog.rtType("Iface")
|
||||
return b.createInterfaceType(name, ty)
|
||||
case *types.Slice:
|
||||
ty := b.prog.rtType("Slice")
|
||||
tyElem := b.prog.rawType(t.Elem())
|
||||
return b.createSliceType(name, ty, tyElem)
|
||||
case *types.Struct:
|
||||
return b.createStructType(name, ty, pos)
|
||||
case *types.Signature:
|
||||
tyFn := b.prog.Closure(t)
|
||||
return b.createFuncPtrType(name, tyFn, pos)
|
||||
case *types.Array:
|
||||
return b.createArrayType(ty, t.Len())
|
||||
case *types.Chan:
|
||||
return b.createChanType(name, ty, pos)
|
||||
case *types.Map:
|
||||
ty := b.prog.rtType("Map")
|
||||
return b.createMapType(name, ty, pos)
|
||||
case *types.Tuple:
|
||||
return b.createTupleType(name, ty, pos)
|
||||
default:
|
||||
panic(fmt.Errorf("can't create debug info of type: %v, %T", ty.RawType(), ty.RawType()))
|
||||
}
|
||||
return &aDIType{typ}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDIFunction struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DIFunction = *aDIFunction
|
||||
|
||||
func (p Function) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta {
|
||||
return &aDIScopeMeta{p.diFunc.ll}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDIGlobalVariableExpression struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DIGlobalVariableExpression = *aDIGlobalVariableExpression
|
||||
|
||||
func (b diBuilder) createGlobalVariableExpression(scope DIScope, pos token.Position, name, linkageName string, ty Type, isLocalToUnit bool) DIGlobalVariableExpression {
|
||||
return &aDIGlobalVariableExpression{
|
||||
ll: b.di.CreateGlobalVariableExpression(
|
||||
scope.scopeMeta(b, pos).ll,
|
||||
llvm.DIGlobalVariableExpression{
|
||||
Name: name,
|
||||
LinkageName: linkageName,
|
||||
File: b.file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
Type: b.diType(ty, pos).ll,
|
||||
LocalToUnit: isLocalToUnit,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(ty.RawType()) * 8),
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDILexicalBlock struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DILexicalBlock = *aDILexicalBlock
|
||||
|
||||
func (l *aDILexicalBlock) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta {
|
||||
return &aDIScopeMeta{l.ll}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDIVar struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DIVar = *aDIVar
|
||||
|
||||
func (b diBuilder) createParameterVariable(scope DIScope, pos token.Position, name string, argNo int, ty DIType) DIVar {
|
||||
return &aDIVar{
|
||||
ll: b.di.CreateParameterVariable(
|
||||
scope.scopeMeta(b, pos).ll,
|
||||
llvm.DIParameterVariable{
|
||||
Name: name,
|
||||
File: b.file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
ArgNo: argNo,
|
||||
Type: ty.ll,
|
||||
AlwaysPreserve: true,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (b diBuilder) createAutoVariable(scope DIScope, pos token.Position, name string, ty DIType) DIVar {
|
||||
return &aDIVar{
|
||||
ll: b.di.CreateAutoVariable(
|
||||
scope.scopeMeta(b, pos).ll,
|
||||
llvm.DIAutoVariable{
|
||||
Name: name,
|
||||
File: b.file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
Type: ty.ll,
|
||||
AlwaysPreserve: true,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (b diBuilder) createTypedefType(name string, ty Type, pos token.Position) DIType {
|
||||
underlyingType := b.diType(b.prog.rawType(ty.RawType().(*types.Named).Underlying()), pos)
|
||||
typ := b.di.CreateTypedef(llvm.DITypedef{
|
||||
Name: name,
|
||||
Type: underlyingType.ll,
|
||||
File: b.file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(ty.RawType()) * 8),
|
||||
})
|
||||
return &aDIType{typ}
|
||||
}
|
||||
|
||||
func (b diBuilder) createStringType() DIType {
|
||||
ty := b.prog.rtType("String")
|
||||
return b.doCreateStructType("string", ty, token.Position{}, func(ditStruct DIType) []llvm.Metadata {
|
||||
return []llvm.Metadata{
|
||||
b.createMemberType("data", ty, b.prog.CStr(), 0),
|
||||
b.createMemberType("len", ty, b.prog.Uint(), 1),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createArrayType(ty Type, l int64) DIType {
|
||||
tyElem := b.prog.rawType(ty.RawType().(*types.Array).Elem())
|
||||
return &aDIType{ll: b.di.CreateArrayType(llvm.DIArrayType{
|
||||
SizeInBits: b.prog.SizeOf(ty) * 8,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(ty.RawType()) * 8),
|
||||
ElementType: b.diType(tyElem, token.Position{}).ll,
|
||||
Subscripts: []llvm.DISubrange{{
|
||||
Count: l,
|
||||
}},
|
||||
})}
|
||||
}
|
||||
|
||||
func (b diBuilder) createSliceType(name string, ty, tyElem Type) DIType {
|
||||
pos := token.Position{}
|
||||
diElemTyPtr := b.prog.Pointer(tyElem)
|
||||
|
||||
return b.doCreateStructType(name, ty, pos, func(ditStruct DIType) []llvm.Metadata {
|
||||
return []llvm.Metadata{
|
||||
b.createMemberTypeEx("data", ty, diElemTyPtr, 0, pos, 0),
|
||||
b.createMemberTypeEx("len", ty, b.prog.Uint(), 1, pos, 0),
|
||||
b.createMemberTypeEx("cap", ty, b.prog.Uint(), 2, pos, 0),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createInterfaceType(name string, ty Type) DIType {
|
||||
tyRaw := ty.RawType().Underlying()
|
||||
tyIntr := b.prog.rawType(tyRaw)
|
||||
tyType := b.prog.VoidPtr()
|
||||
tyData := b.prog.VoidPtr()
|
||||
|
||||
return b.doCreateStructType(name, tyIntr, token.Position{}, func(ditStruct DIType) []llvm.Metadata {
|
||||
return []llvm.Metadata{
|
||||
b.createMemberType("type", ty, tyType, 0),
|
||||
b.createMemberType("data", ty, tyData, 1),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createMemberType(name string, tyStruct, tyField Type, idxField int) llvm.Metadata {
|
||||
return b.createMemberTypeEx(name, tyStruct, tyField, idxField, token.Position{}, 0)
|
||||
}
|
||||
|
||||
func (b diBuilder) createMemberTypeEx(name string, tyStruct, tyField Type, idxField int, pos token.Position, flags int) llvm.Metadata {
|
||||
return b.di.CreateMemberType(
|
||||
b.diType(tyStruct, pos).ll,
|
||||
llvm.DIMemberType{
|
||||
Name: name,
|
||||
SizeInBits: b.prog.SizeOf(tyField) * 8,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(tyField.RawType()) * 8),
|
||||
OffsetInBits: b.prog.OffsetOf(tyStruct, idxField) * 8,
|
||||
Type: b.diType(tyField, pos).ll,
|
||||
Flags: flags,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (b diBuilder) createMapType(name string, tyMap Type, pos token.Position) DIType {
|
||||
// ty := tyMap.RawType().(*types.Map)
|
||||
// tk := b.prog.rawType(ty.Key())
|
||||
// tv := b.prog.rawType(ty.Elem())
|
||||
tyCount := b.prog.Int()
|
||||
return b.doCreateStructType(name, tyMap, pos, func(ditStruct DIType) []llvm.Metadata {
|
||||
return []llvm.Metadata{
|
||||
b.createMemberType("count", tyMap, tyCount, 0),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createChanType(name string, t Type, pos token.Position) DIType {
|
||||
return b.doCreateStructType(name, t, pos, func(ditStruct DIType) []llvm.Metadata {
|
||||
return []llvm.Metadata{}
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createComplexType(t Type) DIType {
|
||||
var tfield Type
|
||||
var tyName string
|
||||
if t.RawType().(*types.Basic).Kind() == types.Complex128 {
|
||||
tfield = b.prog.Float64()
|
||||
tyName = "complex128"
|
||||
} else {
|
||||
tfield = b.prog.Float32()
|
||||
tyName = "complex64"
|
||||
}
|
||||
return b.doCreateStructType(tyName, t, token.Position{}, func(ditStruct DIType) []llvm.Metadata {
|
||||
return []llvm.Metadata{
|
||||
b.createMemberType("real", t, tfield, 0),
|
||||
b.createMemberType("imag", t, tfield, 1),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createPointerType(name string, ty Type, pos token.Position) DIType {
|
||||
ptrType := b.prog.VoidPtr()
|
||||
return &aDIType{ll: b.di.CreatePointerType(llvm.DIPointerType{
|
||||
Name: name,
|
||||
Pointee: b.diType(ty, pos).ll,
|
||||
SizeInBits: b.prog.SizeOf(ptrType) * 8,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(ptrType.RawType())) * 8,
|
||||
})}
|
||||
}
|
||||
|
||||
func (b diBuilder) doCreateStructType(name string, ty Type, pos token.Position, fn func(ty DIType) []llvm.Metadata) (ret DIType) {
|
||||
structType := ty.RawType().Underlying()
|
||||
|
||||
scope := b.file(pos.Filename)
|
||||
ret = &aDIType{b.di.CreateReplaceableCompositeType(
|
||||
scope.ll,
|
||||
llvm.DIReplaceableCompositeType{
|
||||
Tag: dwarf.TagStructType,
|
||||
Name: name,
|
||||
File: b.file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
SizeInBits: b.prog.SizeOf(ty) * 8,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(structType) * 8),
|
||||
},
|
||||
)}
|
||||
b.types[ty] = ret
|
||||
|
||||
fields := fn(ret)
|
||||
|
||||
st := b.di.CreateStructType(
|
||||
scope.ll,
|
||||
llvm.DIStructType{
|
||||
Name: name,
|
||||
File: b.file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
SizeInBits: b.prog.SizeOf(ty) * 8,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(structType) * 8),
|
||||
Elements: fields,
|
||||
},
|
||||
)
|
||||
ret.ll.ReplaceAllUsesWith(st)
|
||||
ret.ll = st
|
||||
return
|
||||
}
|
||||
|
||||
func (b diBuilder) createStructType(name string, ty Type, pos token.Position) (ret DIType) {
|
||||
structType := ty.RawType().(*types.Struct)
|
||||
return b.doCreateStructType(name, ty, pos, func(ditStruct DIType) []llvm.Metadata {
|
||||
fields := make([]llvm.Metadata, structType.NumFields())
|
||||
for i := 0; i < structType.NumFields(); i++ {
|
||||
field := structType.Field(i)
|
||||
tyField := b.prog.rawType(field.Type())
|
||||
flags := 0
|
||||
pos := b.positioner.Position(field.Pos())
|
||||
fields[i] = b.createMemberTypeEx(field.Name(), ty, tyField, i, pos, flags)
|
||||
}
|
||||
return fields
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createTupleType(name string, ty Type, pos token.Position) DIType {
|
||||
tupleType := ty.RawType().(*types.Tuple)
|
||||
if tupleType.Len() == 0 {
|
||||
return &aDIType{}
|
||||
}
|
||||
if tupleType.Len() == 1 {
|
||||
t := b.prog.rawType(tupleType.At(0).Type())
|
||||
return b.diType(t, pos)
|
||||
}
|
||||
return b.doCreateStructType(name, ty, pos, func(ditStruct DIType) []llvm.Metadata {
|
||||
fields := make([]llvm.Metadata, ty.RawType().(*types.Tuple).Len())
|
||||
for i := 0; i < ty.RawType().(*types.Tuple).Len(); i++ {
|
||||
field := ty.RawType().(*types.Tuple).At(i)
|
||||
tyField := b.prog.rawType(field.Type())
|
||||
fields[i] = b.createMemberTypeEx(field.Name(), ty, tyField, i, pos, 0)
|
||||
}
|
||||
return fields
|
||||
})
|
||||
}
|
||||
|
||||
func (b diBuilder) createFuncPtrType(name string, ty Type, pos token.Position) DIType {
|
||||
ptr := b.prog.VoidPtr()
|
||||
return &aDIType{ll: b.di.CreatePointerType(llvm.DIPointerType{
|
||||
Name: name,
|
||||
Pointee: b.diType(ptr, pos).ll,
|
||||
SizeInBits: b.prog.SizeOf(ptr) * 8,
|
||||
AlignInBits: uint32(b.prog.sizes.Alignof(ptr.RawType()) * 8),
|
||||
})}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
func (b diBuilder) dbgDeclare(v Expr, dv DIVar, scope DIScope, pos token.Position, expr DIExpression, blk BasicBlock) {
|
||||
loc := llvm.DebugLoc{
|
||||
Line: uint(pos.Line),
|
||||
Col: uint(pos.Column),
|
||||
Scope: scope.scopeMeta(b, pos).ll,
|
||||
}
|
||||
b.di.InsertDeclareAtEnd(
|
||||
v.impl,
|
||||
dv.ll,
|
||||
expr.ll,
|
||||
loc,
|
||||
blk.last,
|
||||
)
|
||||
}
|
||||
|
||||
func (b diBuilder) dbgValue(v Expr, dv DIVar, scope DIScope, pos token.Position, expr DIExpression, blk BasicBlock) {
|
||||
loc := llvm.DebugLoc{
|
||||
Line: uint(pos.Line),
|
||||
Col: uint(pos.Column),
|
||||
Scope: scope.scopeMeta(b, pos).ll,
|
||||
}
|
||||
b.di.InsertValueAtEnd(
|
||||
v.impl,
|
||||
dv.ll,
|
||||
expr.ll,
|
||||
loc,
|
||||
blk.last,
|
||||
)
|
||||
}
|
||||
|
||||
func (b diBuilder) diType(t Type, pos token.Position) DIType {
|
||||
name := t.RawType().String()
|
||||
return b.diTypeEx(name, t, pos)
|
||||
}
|
||||
|
||||
func (b diBuilder) diTypeEx(name string, t Type, pos token.Position) DIType {
|
||||
if ty, ok := b.types[t]; ok {
|
||||
return ty
|
||||
}
|
||||
ty := b.createType(name, t, pos)
|
||||
b.types[t] = ty
|
||||
return ty
|
||||
}
|
||||
|
||||
func (b diBuilder) varParam(scope DIScope, pos token.Position, varName string, vt DIType, argNo int) DIVar {
|
||||
return b.createParameterVariable(
|
||||
scope,
|
||||
pos,
|
||||
varName,
|
||||
argNo,
|
||||
vt,
|
||||
)
|
||||
}
|
||||
|
||||
func (b diBuilder) varAuto(scope DIScope, pos token.Position, varName string, vt DIType) DIVar {
|
||||
return b.createAutoVariable(scope, pos, varName, vt)
|
||||
}
|
||||
|
||||
func (b diBuilder) file(filename string) DIFile {
|
||||
return b.createFile(filename)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type aDIExpression struct {
|
||||
ll llvm.Metadata
|
||||
}
|
||||
|
||||
type DIExpression = *aDIExpression
|
||||
|
||||
func (b diBuilder) createExpression(ops []uint64) DIExpression {
|
||||
return &aDIExpression{b.di.CreateExpression(ops)}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Copy to alloca'd memory to get declareable address.
|
||||
func (b Builder) constructDebugAddr(v Expr) (dbgPtr Expr, dbgVal Expr, exists bool) {
|
||||
if v, ok := b.dbgVars[v]; ok {
|
||||
return v.ptr, v.val, true
|
||||
}
|
||||
t := v.Type.RawType().Underlying()
|
||||
dbgPtr, dbgVal = b.doConstructDebugAddr(v, t)
|
||||
dbgExpr := dbgExpr{dbgPtr, dbgVal}
|
||||
b.dbgVars[v] = dbgExpr
|
||||
b.dbgVars[dbgVal] = dbgExpr
|
||||
return dbgPtr, dbgVal, false
|
||||
}
|
||||
|
||||
func (b Builder) doConstructDebugAddr(v Expr, t types.Type) (dbgPtr Expr, dbgVal Expr) {
|
||||
var ty Type
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
if t.Info()&types.IsComplex != 0 {
|
||||
if t.Kind() == types.Complex128 {
|
||||
ty = b.Prog.Complex128()
|
||||
} else {
|
||||
ty = b.Prog.Complex64()
|
||||
}
|
||||
} else if t.Info()&types.IsString != 0 {
|
||||
ty = b.Prog.rtType("String")
|
||||
} else {
|
||||
ty = v.Type
|
||||
}
|
||||
case *types.Struct:
|
||||
ty = v.Type
|
||||
case *types.Slice:
|
||||
ty = b.Prog.Type(b.Prog.rtType("Slice").RawType().Underlying(), InGo)
|
||||
case *types.Signature:
|
||||
ty = b.Prog.Closure(t)
|
||||
case *types.Named:
|
||||
ty = b.Prog.Type(t.Underlying(), InGo)
|
||||
case *types.Map:
|
||||
ty = b.Prog.Type(b.Prog.rtType("Map").RawType().Underlying(), InGo)
|
||||
default:
|
||||
ty = v.Type
|
||||
}
|
||||
dbgPtr = b.AllocaT(ty)
|
||||
dbgPtr.Type = b.Prog.Pointer(v.Type)
|
||||
b.Store(dbgPtr, v)
|
||||
dbgVal = b.Load(dbgPtr)
|
||||
return dbgPtr, dbgVal
|
||||
}
|
||||
|
||||
func (b Builder) di() diBuilder {
|
||||
return b.Pkg.di
|
||||
}
|
||||
|
||||
func (b Builder) DIParam(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
||||
b.DIValue(variable, v, dv, scope, pos, blk)
|
||||
}
|
||||
|
||||
func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
||||
expr := b.di().createExpression(nil)
|
||||
b.di().dbgDeclare(v, dv, scope, pos, expr, blk)
|
||||
}
|
||||
|
||||
func (b Builder) DIValue(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
|
||||
ty := v.Type.RawType().Underlying()
|
||||
if !needConstructAddr(ty) {
|
||||
expr := b.di().createExpression(nil)
|
||||
b.di().dbgValue(v, dv, scope, pos, expr, blk)
|
||||
} else {
|
||||
dbgPtr, _, _ := b.constructDebugAddr(v)
|
||||
expr := b.di().createExpression([]uint64{opDeref})
|
||||
b.di().dbgValue(dbgPtr, dv, scope, pos, expr, blk)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
opDeref = 0x06
|
||||
)
|
||||
|
||||
func needConstructAddr(t types.Type) bool {
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
if t.Info()&types.IsComplex != 0 {
|
||||
return true
|
||||
} else if t.Info()&types.IsString != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
case *types.Pointer:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (b Builder) DIVarParam(scope DIScope, pos token.Position, varName string, vt Type, argNo int) DIVar {
|
||||
t := b.di().diType(vt, pos)
|
||||
return b.di().varParam(scope, pos, varName, t, argNo)
|
||||
}
|
||||
|
||||
func (b Builder) DIVarAuto(scope DIScope, pos token.Position, varName string, vt Type) DIVar {
|
||||
t := b.di().diType(vt, pos)
|
||||
return b.di().varAuto(scope, pos, varName, t)
|
||||
}
|
||||
|
||||
// hack for types.Scope
|
||||
type hackScope struct {
|
||||
parent *types.Scope
|
||||
children []*types.Scope
|
||||
number int // parent.children[number-1] is this scope; 0 if there is no parent
|
||||
elems map[string]types.Object // lazily allocated
|
||||
pos, end token.Pos // scope extent; may be invalid
|
||||
comment string // for debugging only
|
||||
isFunc bool // set if this is a function scope (internal use only)
|
||||
}
|
||||
|
||||
func isFunc(scope *types.Scope) bool {
|
||||
hs := (*hackScope)(unsafe.Pointer(scope))
|
||||
return hs.isFunc
|
||||
}
|
||||
|
||||
func (b Builder) DIScope(f Function, scope *types.Scope) DIScope {
|
||||
if cachedScope, ok := b.diScopeCache[scope]; ok {
|
||||
return cachedScope
|
||||
}
|
||||
pos := b.di().positioner.Position(scope.Pos())
|
||||
// skip package and universe scope
|
||||
// if scope.Parent().Parent() == nil {
|
||||
// return b.di().file(pos.Filename)
|
||||
// }
|
||||
|
||||
var result DIScope
|
||||
if isFunc(scope) {
|
||||
// TODO(lijie): should check scope == function scope
|
||||
result = f
|
||||
} else {
|
||||
parentScope := b.DIScope(f, scope.Parent())
|
||||
result = &aDILexicalBlock{b.di().di.CreateLexicalBlock(parentScope.scopeMeta(b.di(), pos).ll, llvm.DILexicalBlock{
|
||||
File: b.di().file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
Column: pos.Column,
|
||||
})}
|
||||
}
|
||||
|
||||
b.diScopeCache[scope] = result
|
||||
return result
|
||||
}
|
||||
|
||||
const (
|
||||
MD_dbg = 0
|
||||
)
|
||||
|
||||
func (b Builder) DIGlobal(v Expr, name string, pos token.Position) {
|
||||
if _, ok := b.Pkg.glbDbgVars[v]; ok {
|
||||
return
|
||||
}
|
||||
gv := b.di().createGlobalVariableExpression(
|
||||
b.Pkg.cu,
|
||||
pos,
|
||||
name,
|
||||
name,
|
||||
v.Type,
|
||||
false,
|
||||
)
|
||||
v.impl.AddMetadata(MD_dbg, gv.ll)
|
||||
b.Pkg.glbDbgVars[v] = true
|
||||
}
|
||||
|
||||
func (b Builder) DISetCurrentDebugLocation(diScope DIScope, pos token.Position) {
|
||||
b.impl.SetCurrentDebugLocation(
|
||||
uint(pos.Line),
|
||||
uint(pos.Column),
|
||||
diScope.scopeMeta(b.di(), pos).ll,
|
||||
llvm.Metadata{},
|
||||
)
|
||||
}
|
||||
|
||||
func (b Builder) DebugFunction(f Function, pos token.Position, bodyPos token.Position) {
|
||||
p := f
|
||||
if p.diFunc == nil {
|
||||
sig := p.Type.raw.Type.(*types.Signature)
|
||||
rt := p.Prog.Type(sig.Results(), InGo)
|
||||
paramTypes := make([]llvm.Metadata, len(p.params)+1)
|
||||
paramTypes[0] = b.di().diType(rt, pos).ll
|
||||
for i, t := range p.params {
|
||||
paramTypes[i+1] = b.di().diType(t, pos).ll
|
||||
}
|
||||
diFuncType := b.di().di.CreateSubroutineType(llvm.DISubroutineType{
|
||||
File: b.di().file(pos.Filename).ll,
|
||||
Parameters: paramTypes,
|
||||
})
|
||||
dif := llvm.DIFunction{
|
||||
Type: diFuncType,
|
||||
Name: p.Name(),
|
||||
LinkageName: p.Name(),
|
||||
File: b.di().file(pos.Filename).ll,
|
||||
Line: pos.Line,
|
||||
ScopeLine: bodyPos.Line,
|
||||
IsDefinition: true,
|
||||
LocalToUnit: true,
|
||||
Optimized: true,
|
||||
}
|
||||
p.diFunc = &aDIFunction{
|
||||
b.di().di.CreateFunction(b.di().file(pos.Filename).ll, dif),
|
||||
}
|
||||
p.impl.SetSubprogram(p.diFunc.ll)
|
||||
}
|
||||
b.impl.SetCurrentDebugLocation(
|
||||
uint(bodyPos.Line),
|
||||
uint(bodyPos.Column),
|
||||
p.diFunc.ll,
|
||||
f.impl.InstructionDebugLoc(),
|
||||
)
|
||||
}
|
||||
|
||||
func (b Builder) Param(idx int) Expr {
|
||||
p := b.Func.Param(idx)
|
||||
if v, ok := b.dbgVars[p]; ok {
|
||||
return v.val
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user