transform: add debug info in interface lowering pass

This is fake debug info. It doesn't point to a source location because
there is no source location. However, it helps to correctly attribute
code size usage to particular packages.

I've also updated builder/sizes.go with some debugging helpers.
This commit is contained in:
Ayke van Laethem
2021-11-04 03:27:44 +01:00
committed by Ron Evans
parent edcece33ca
commit 7caf0732fa
2 changed files with 91 additions and 3 deletions
+68 -3
View File
@@ -87,6 +87,8 @@ type lowerInterfacesPass struct {
mod llvm.Module
config *compileopts.Config
builder llvm.Builder
dibuilder *llvm.DIBuilder
difiles map[string]llvm.Metadata
ctx llvm.Context
uintptrType llvm.Type
types map[string]*typeInfo
@@ -109,11 +111,28 @@ func LowerInterfaces(mod llvm.Module, config *compileopts.Config) error {
signatures: make(map[string]*signatureInfo),
interfaces: make(map[string]*interfaceInfo),
}
if config.Debug() {
p.dibuilder = llvm.NewDIBuilder(mod)
defer p.dibuilder.Finalize()
p.difiles = make(map[string]llvm.Metadata)
}
return p.run()
}
// run runs the pass itself.
func (p *lowerInterfacesPass) run() error {
if p.dibuilder != nil {
p.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?)
File: "<unknown>",
Dir: "",
Producer: "TinyGo",
Optimized: true,
})
}
// Collect all type codes.
for global := p.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) {
if strings.HasPrefix(global.Name(), "reflect/types.type:") {
@@ -340,7 +359,6 @@ func (p *lowerInterfacesPass) getSignature(name string) *signatureInfo {
// types by the LLVM simplifycfg pass.
func (p *lowerInterfacesPass) defineInterfaceImplementsFunc(fn llvm.Value, itf *interfaceInfo) {
// Create the function and function signature.
// TODO: debug info
fn.Param(0).SetName("actualType")
fn.SetLinkage(llvm.InternalLinkage)
fn.SetUnnamedAddr(true)
@@ -351,6 +369,26 @@ func (p *lowerInterfacesPass) defineInterfaceImplementsFunc(fn llvm.Value, itf *
thenBlock := p.ctx.AddBasicBlock(fn, "then")
p.builder.SetInsertPointAtEnd(entry)
if p.dibuilder != nil {
difile := p.getDIFile("<Go interface assert>")
diFuncType := p.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
File: difile,
})
difunc := p.dibuilder.CreateFunction(difile, llvm.DIFunction{
Name: "(Go interface assert)",
File: difile,
Line: 0,
Type: diFuncType,
LocalToUnit: true,
IsDefinition: true,
ScopeLine: 0,
Flags: llvm.FlagPrototyped,
Optimized: true,
})
fn.SetSubprogram(difunc)
p.builder.SetCurrentDebugLocation(0, 0, difunc, llvm.Metadata{})
}
// Iterate over all possible types. Each iteration creates a new branch
// either to the 'then' block (success) or the .next block, for the next
// check.
@@ -390,8 +428,6 @@ func (p *lowerInterfacesPass) defineInterfaceMethodFunc(fn llvm.Value, itf *inte
fn.SetUnnamedAddr(true)
AddStandardAttributes(fn, p.config)
// TODO: debug info
// Collect the params that will be passed to the functions to call.
// These params exclude the receiver (which may actually consist of multiple
// parts).
@@ -408,6 +444,26 @@ func (p *lowerInterfacesPass) defineInterfaceMethodFunc(fn llvm.Value, itf *inte
entry := p.ctx.AddBasicBlock(fn, "entry")
p.builder.SetInsertPointAtEnd(entry)
if p.dibuilder != nil {
difile := p.getDIFile("<Go interface method>")
diFuncType := p.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
File: difile,
})
difunc := p.dibuilder.CreateFunction(difile, llvm.DIFunction{
Name: "(Go interface method)",
File: difile,
Line: 0,
Type: diFuncType,
LocalToUnit: true,
IsDefinition: true,
ScopeLine: 0,
Flags: llvm.FlagPrototyped,
Optimized: true,
})
fn.SetSubprogram(difunc)
p.builder.SetCurrentDebugLocation(0, 0, difunc, llvm.Metadata{})
}
// Define all possible functions that can be called.
for _, typ := range itf.types {
// Create type check (if/else).
@@ -467,3 +523,12 @@ func (p *lowerInterfacesPass) defineInterfaceMethodFunc(fn llvm.Value, itf *inte
}, "")
p.builder.CreateUnreachable()
}
func (p *lowerInterfacesPass) getDIFile(file string) llvm.Metadata {
difile, ok := p.difiles[file]
if !ok {
difile = p.dibuilder.CreateFile(file, "")
p.difiles[file] = difile
}
return difile
}