forked from M-Labs/artiq
LLVMIRGenerator: emit debug information.
This commit is contained in:
parent
4f02f6e667
commit
c63ec70c53
|
@ -3,6 +3,7 @@
|
||||||
into LLVM intermediate representation.
|
into LLVM intermediate representation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
from pythonparser import ast, diagnostic
|
from pythonparser import ast, diagnostic
|
||||||
from llvmlite_artiq import ir as ll
|
from llvmlite_artiq import ir as ll
|
||||||
from .. import types, builtins, ir
|
from .. import types, builtins, ir
|
||||||
|
@ -14,7 +15,147 @@ lli8 = ll.IntType(8)
|
||||||
lli32 = ll.IntType(32)
|
lli32 = ll.IntType(32)
|
||||||
lldouble = ll.DoubleType()
|
lldouble = ll.DoubleType()
|
||||||
llptr = ll.IntType(8).as_pointer()
|
llptr = ll.IntType(8).as_pointer()
|
||||||
llemptyptr = ll.LiteralStructType( []).as_pointer()
|
llmetadata = ll.MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
DW_LANG_Python = 0x0014
|
||||||
|
DW_TAG_compile_unit = 17
|
||||||
|
DW_TAG_subroutine_type = 21
|
||||||
|
DW_TAG_file_type = 41
|
||||||
|
DW_TAG_subprogram = 46
|
||||||
|
|
||||||
|
def memoize(generator):
|
||||||
|
def memoized(self, *args):
|
||||||
|
result = self.cache.get((generator,) + args, None)
|
||||||
|
if result is None:
|
||||||
|
return generator(self, *args)
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
return memoized
|
||||||
|
|
||||||
|
class DebugInfoEmitter:
|
||||||
|
def __init__(self, llmodule):
|
||||||
|
self.llmodule = llmodule
|
||||||
|
self.cache = {}
|
||||||
|
self.subprograms = []
|
||||||
|
|
||||||
|
def emit(self, operands):
|
||||||
|
def map_operand(operand):
|
||||||
|
if operand is None:
|
||||||
|
return ll.Constant(llmetadata, None)
|
||||||
|
elif isinstance(operand, str):
|
||||||
|
return ll.MetaDataString(self.llmodule, operand)
|
||||||
|
elif isinstance(operand, bool):
|
||||||
|
return ll.Constant(lli1, operand)
|
||||||
|
elif isinstance(operand, int):
|
||||||
|
return ll.Constant(lli32, operand)
|
||||||
|
elif isinstance(operand, (list, tuple)):
|
||||||
|
return self.emit(operand)
|
||||||
|
elif isinstance(operand, ll.Value):
|
||||||
|
return operand
|
||||||
|
else:
|
||||||
|
print(operand)
|
||||||
|
assert False
|
||||||
|
return self.llmodule.add_metadata(list(map(map_operand, operands)))
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def emit_filename(self, source_buffer):
|
||||||
|
source_dir, source_file = os.path.split(source_buffer.name)
|
||||||
|
return self.emit([source_file, source_dir])
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def emit_compile_unit(self, source_buffer, llsubprograms):
|
||||||
|
return self.emit([
|
||||||
|
DW_TAG_compile_unit,
|
||||||
|
self.emit_filename(source_buffer), # filename
|
||||||
|
DW_LANG_Python, # source language
|
||||||
|
"ARTIQ", # producer
|
||||||
|
False, # optimized?
|
||||||
|
"", # linker flags
|
||||||
|
0, # runtime version
|
||||||
|
[], # enum types
|
||||||
|
[], # retained types
|
||||||
|
llsubprograms, # subprograms
|
||||||
|
[], # global variables
|
||||||
|
[], # imported entities
|
||||||
|
"", # split debug filename
|
||||||
|
2, # kind (full=1, lines only=2)
|
||||||
|
])
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def emit_file(self, source_buffer):
|
||||||
|
return self.emit([
|
||||||
|
DW_TAG_file_type,
|
||||||
|
self.emit_filename(source_buffer), # filename
|
||||||
|
])
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def emit_subroutine_type(self, typ):
|
||||||
|
return self.emit([
|
||||||
|
DW_TAG_subroutine_type,
|
||||||
|
None, # filename
|
||||||
|
None, # context descriptor
|
||||||
|
"", # name
|
||||||
|
0, # line number
|
||||||
|
0, # (i64) size in bits
|
||||||
|
0, # (i64) alignment in bits
|
||||||
|
0, # (i64) offset in bits
|
||||||
|
0, # flags
|
||||||
|
None, # derived from
|
||||||
|
[None], # members
|
||||||
|
0, # runtime languages
|
||||||
|
None, # base type with vtable pointer
|
||||||
|
None, # template parameters
|
||||||
|
None # unique identifier
|
||||||
|
])
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def emit_subprogram(self, func, llfunc):
|
||||||
|
source_buffer = func.loc.source_buffer
|
||||||
|
display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type))
|
||||||
|
subprogram = self.emit([
|
||||||
|
DW_TAG_subprogram,
|
||||||
|
self.emit_filename(source_buffer), # filename
|
||||||
|
self.emit_file(source_buffer), # context descriptor
|
||||||
|
func.name, # name
|
||||||
|
display_name, # display name
|
||||||
|
llfunc.name, # linkage name
|
||||||
|
func.loc.line(), # line number where defined
|
||||||
|
self.emit_subroutine_type(func.type), # type descriptor
|
||||||
|
func.is_internal, # local to compile unit?
|
||||||
|
True, # global is defined in the compile unit?
|
||||||
|
0, # virtuality
|
||||||
|
0, # index into a virtual function
|
||||||
|
None, # base type with vtable pointer
|
||||||
|
0, # flags
|
||||||
|
False, # optimized?
|
||||||
|
llfunc, # LLVM function
|
||||||
|
None, # template parameters
|
||||||
|
None, # function declaration descriptor
|
||||||
|
[], # function variables
|
||||||
|
func.loc.line(), # line number where scope begins
|
||||||
|
])
|
||||||
|
self.subprograms.append(subprogram)
|
||||||
|
return subprogram
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def emit_loc(self, loc, scope, inlined_scope=None):
|
||||||
|
return self.emit([
|
||||||
|
loc.line(), # line
|
||||||
|
loc.column(), # column
|
||||||
|
scope, # scope
|
||||||
|
inlined_scope, # inlined scope
|
||||||
|
])
|
||||||
|
|
||||||
|
def finalize(self, source_buffer):
|
||||||
|
llident = self.llmodule.add_named_metadata('llvm.ident')
|
||||||
|
llident.add(self.emit(["ARTIQ"]))
|
||||||
|
|
||||||
|
llflags = self.llmodule.add_named_metadata('llvm.module.flags')
|
||||||
|
llflags.add(self.emit([2, "Debug Info Version", 1]))
|
||||||
|
|
||||||
|
llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu')
|
||||||
|
llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.subprograms)))
|
||||||
|
|
||||||
|
|
||||||
class LLVMIRGenerator:
|
class LLVMIRGenerator:
|
||||||
|
@ -27,8 +168,8 @@ class LLVMIRGenerator:
|
||||||
self.llmodule.data_layout = target.data_layout
|
self.llmodule.data_layout = target.data_layout
|
||||||
self.llfunction = None
|
self.llfunction = None
|
||||||
self.llmap = {}
|
self.llmap = {}
|
||||||
self.llblock_map = {}
|
self.phis = []
|
||||||
self.fixups = []
|
self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
|
||||||
|
|
||||||
def llty_of_type(self, typ, bare=False, for_return=False):
|
def llty_of_type(self, typ, bare=False, for_return=False):
|
||||||
typ = typ.find()
|
typ = typ.find()
|
||||||
|
@ -200,6 +341,9 @@ class LLVMIRGenerator:
|
||||||
for func in functions:
|
for func in functions:
|
||||||
self.process_function(func)
|
self.process_function(func)
|
||||||
|
|
||||||
|
if any(functions):
|
||||||
|
self.debug_info_emitter.finalize(functions[0].loc.source_buffer)
|
||||||
|
|
||||||
return self.llmodule
|
return self.llmodule
|
||||||
|
|
||||||
def process_function(self, func):
|
def process_function(self, func):
|
||||||
|
@ -219,9 +363,10 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
self.llfunction.attributes.add('uwtable')
|
self.llfunction.attributes.add('uwtable')
|
||||||
|
|
||||||
self.llmap = {}
|
|
||||||
self.llbuilder = ll.IRBuilder()
|
self.llbuilder = ll.IRBuilder()
|
||||||
self.fixups = []
|
llblock_map = {}
|
||||||
|
|
||||||
|
disubprogram = self.debug_info_emitter.emit_subprogram(func, self.llfunction)
|
||||||
|
|
||||||
# First, map arguments.
|
# First, map arguments.
|
||||||
for arg, llarg in zip(func.arguments, self.llfunction.args):
|
for arg, llarg in zip(func.arguments, self.llfunction.args):
|
||||||
|
@ -240,27 +385,29 @@ class LLVMIRGenerator:
|
||||||
assert llinsn is not None
|
assert llinsn is not None
|
||||||
self.llmap[insn] = llinsn
|
self.llmap[insn] = llinsn
|
||||||
|
|
||||||
|
if insn.loc is not None:
|
||||||
|
diloc = self.debug_info_emitter.emit_loc(insn.loc, disubprogram)
|
||||||
|
llinsn.set_metadata('dbg', diloc)
|
||||||
|
|
||||||
# There is no 1:1 correspondence between ARTIQ and LLVM
|
# There is no 1:1 correspondence between ARTIQ and LLVM
|
||||||
# basic blocks, because sometimes we expand a single ARTIQ
|
# basic blocks, because sometimes we expand a single ARTIQ
|
||||||
# instruction so that the result spans several LLVM basic
|
# instruction so that the result spans several LLVM basic
|
||||||
# blocks. This only really matters for phis, which will
|
# blocks. This only really matters for phis, which will
|
||||||
# use a different map.
|
# use a different map.
|
||||||
self.llblock_map[block] = self.llbuilder.basic_block
|
llblock_map[block] = self.llbuilder.basic_block
|
||||||
|
|
||||||
# Fourth, fixup phis.
|
# Fourth, add incoming values to phis.
|
||||||
for fixup in self.fixups:
|
for phi, llphi in self.phis:
|
||||||
fixup()
|
for value, block in phi.incoming():
|
||||||
|
llphi.add_incoming(self.map(value), llblock_map[block])
|
||||||
finally:
|
finally:
|
||||||
self.llfunction = None
|
self.llfunction = None
|
||||||
self.llmap = None
|
self.llmap = {}
|
||||||
self.fixups = []
|
self.llphis = []
|
||||||
|
|
||||||
def process_Phi(self, insn):
|
def process_Phi(self, insn):
|
||||||
llinsn = self.llbuilder.phi(self.llty_of_type(insn.type), name=insn.name)
|
llinsn = self.llbuilder.phi(self.llty_of_type(insn.type), name=insn.name)
|
||||||
def fixup():
|
self.phis.append((insn, llinsn))
|
||||||
for value, block in insn.incoming():
|
|
||||||
llinsn.add_incoming(self.map(value), self.llblock_map[block])
|
|
||||||
self.fixups.append(fixup)
|
|
||||||
return llinsn
|
return llinsn
|
||||||
|
|
||||||
def llindex(self, index):
|
def llindex(self, index):
|
||||||
|
@ -793,8 +940,7 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
def process_LandingPad(self, insn):
|
def process_LandingPad(self, insn):
|
||||||
# Layout on return from landing pad: {%_Unwind_Exception*, %Exception*}
|
# Layout on return from landing pad: {%_Unwind_Exception*, %Exception*}
|
||||||
lllandingpadty = ll.LiteralStructType([llptr,
|
lllandingpadty = ll.LiteralStructType([llptr, llptr])
|
||||||
llptr])
|
|
||||||
lllandingpad = self.llbuilder.landingpad(lllandingpadty,
|
lllandingpad = self.llbuilder.landingpad(lllandingpadty,
|
||||||
self.llbuiltin("__artiq_personality"),
|
self.llbuiltin("__artiq_personality"),
|
||||||
cleanup=True)
|
cleanup=True)
|
||||||
|
|
Loading…
Reference in New Issue