llvm_ir_generator: update debug info emission for LLVM 3.8.

This commit is contained in:
whitequark 2016-04-02 18:03:48 +00:00
parent 132b55d6be
commit b1f371e578
1 changed files with 59 additions and 95 deletions

View File

@ -42,126 +42,89 @@ def memoize(generator):
class DebugInfoEmitter: class DebugInfoEmitter:
def __init__(self, llmodule): def __init__(self, llmodule):
self.llmodule = llmodule self.llmodule = llmodule
self.llsubprograms = []
self.cache = {} self.cache = {}
self.subprograms = []
def emit(self, operands): def emit_metadata(self, operands):
def map_operand(operand): def map_operand(operand):
if operand is None: if operand is None:
return ll.Constant(llmetadata, None) return ll.Constant(llmetadata, None)
elif isinstance(operand, str): elif isinstance(operand, str):
return ll.MetaDataString(self.llmodule, operand) return ll.MetaDataString(self.llmodule, operand)
elif isinstance(operand, bool):
return ll.Constant(lli1, operand)
elif isinstance(operand, int): elif isinstance(operand, int):
return ll.Constant(lli32, operand) return ll.Constant(lli32, operand)
elif isinstance(operand, (list, tuple)): elif isinstance(operand, (list, tuple)):
return self.emit(operand) return self.emit_metadata(operand)
elif isinstance(operand, ll.Value):
return operand
else: else:
print(operand) assert isinstance(operand, ll.NamedValue)
assert False return operand
return self.llmodule.add_metadata(list(map(map_operand, operands))) return self.llmodule.add_metadata(list(map(map_operand, operands)))
@memoize def emit_debug_info(self, kind, operands, is_distinct=False):
def emit_filename(self, source_buffer): return self.llmodule.add_debug_info(kind, operands, is_distinct)
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 @memoize
def emit_file(self, source_buffer): def emit_file(self, source_buffer):
return self.emit([ source_dir, source_file = os.path.split(source_buffer.name)
DW_TAG_file_type, return self.emit_debug_info("DIFile", {
self.emit_filename(source_buffer), # filename "filename": source_file,
]) "directory": source_dir,
})
@memoize
def emit_compile_unit(self, source_buffer, llsubprograms):
return self.emit_debug_info("DICompileUnit", {
"language": ll.DIToken("DW_LANG_C99"),
"file": self.emit_file(source_buffer),
"producer": "ARTIQ",
"runtimeVersion": 0,
"emissionKind": 2, # full=1, lines only=2
"subprograms": self.emit_metadata(llsubprograms)
}, is_distinct=True)
@memoize @memoize
def emit_subroutine_type(self, typ): def emit_subroutine_type(self, typ):
return self.emit([ return self.emit_debug_info("DISubroutineType", {
DW_TAG_subroutine_type, "types": self.emit_metadata([None])
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 @memoize
def emit_subprogram(self, func, llfunc): def emit_subprogram(self, func, llfunc):
source_buffer = func.loc.source_buffer source_buffer = func.loc.source_buffer
display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type)) display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type))
subprogram = self.emit([ llsubprogram = self.emit_debug_info("DISubprogram", {
DW_TAG_subprogram, "name": func.name,
self.emit_filename(source_buffer), # filename "linkageName": llfunc.name,
self.emit_file(source_buffer), # context descriptor "type": self.emit_subroutine_type(func.type),
func.name, # name "file": self.emit_file(source_buffer),
display_name, # display name "line": func.loc.line(),
llfunc.name, # linkage name "scope": self.emit_file(source_buffer),
func.loc.line(), # line number where defined "scopeLine": func.loc.line(),
self.emit_subroutine_type(func.type), # type descriptor "isLocal": func.is_internal,
func.is_internal, # local to compile unit? "isDefinition": True,
True, # global is defined in the compile unit? "variables": self.emit_metadata([])
0, # virtuality }, is_distinct=True)
0, # index into a virtual function self.llsubprograms.append(llsubprogram)
None, # base type with vtable pointer return llsubprogram
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 @memoize
def emit_loc(self, loc, scope, inlined_scope=None): def emit_loc(self, loc, scope):
return self.emit([ return self.emit_debug_info("DILocation", {
loc.line(), # line "line": loc.line(),
loc.column(), # column "column": loc.column(),
scope, # scope "scope": scope
inlined_scope, # inlined scope })
])
def finalize(self, source_buffer): def finalize(self, source_buffer):
llident = self.llmodule.add_named_metadata('llvm.ident') llident = self.llmodule.add_named_metadata('llvm.ident')
llident.add(self.emit(["ARTIQ"])) llident.add(self.emit_metadata(["ARTIQ"]))
llflags = self.llmodule.add_named_metadata('llvm.module.flags') llflags = self.llmodule.add_named_metadata('llvm.module.flags')
llflags.add(self.emit([2, "Debug Info Version", 1])) llflags.add(self.emit_metadata([2, "Debug Info Version", 3]))
llflags.add(self.emit_metadata([2, "Dwarf Version", 4]))
llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu') llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu')
llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.subprograms))) llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.llsubprograms)))
class LLVMIRGenerator: class LLVMIRGenerator:
@ -578,6 +541,7 @@ class LLVMIRGenerator:
llblock_map = {} llblock_map = {}
disubprogram = self.debug_info_emitter.emit_subprogram(func, self.llfunction) disubprogram = self.debug_info_emitter.emit_subprogram(func, self.llfunction)
self.llfunction.set_metadata('dbg', disubprogram)
# First, map arguments. # First, map arguments.
if self.has_sret(func.type): if self.has_sret(func.type):
@ -683,15 +647,15 @@ class LLVMIRGenerator:
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)], llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)],
inbounds=True) inbounds=True)
llouterenv = self.llbuilder.load(llptr) llouterenv = self.llbuilder.load(llptr)
llouterenv.metadata['invariant.load'] = self.empty_metadata llouterenv.set_metadata('invariant.load', self.empty_metadata)
llouterenv.metadata['nonnull'] = self.empty_metadata llouterenv.set_metadata('nonnull', self.empty_metadata)
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
def mark_dereferenceable(self, load): def mark_dereferenceable(self, load):
assert isinstance(load, ll.LoadInstr) and isinstance(load.type, ll.PointerType) assert isinstance(load, ll.LoadInstr) and isinstance(load.type, ll.PointerType)
pointee_size = load.type.pointee.get_abi_size(self.lldatalayout, context=self.llcontext) pointee_size = load.type.pointee.get_abi_size(self.lldatalayout, context=self.llcontext)
metadata = self.llmodule.add_metadata([ll.Constant(lli64, pointee_size)]) metadata = self.llmodule.add_metadata([ll.Constant(lli64, pointee_size)])
load.metadata['dereferenceable'] = metadata load.set_metadata('dereferenceable', metadata)
def process_GetLocal(self, insn): def process_GetLocal(self, insn):
env = insn.environment() env = insn.environment()
@ -821,7 +785,7 @@ class LLVMIRGenerator:
inbounds=True, name="ptr.{}".format(insn.name)) inbounds=True, name="ptr.{}".format(insn.name))
llvalue = self.llbuilder.load(llptr, name="val.{}".format(insn.name)) llvalue = self.llbuilder.load(llptr, name="val.{}".format(insn.name))
if types.is_instance(typ) and attr in typ.constant_attributes: if types.is_instance(typ) and attr in typ.constant_attributes:
llvalue.metadata['invariant.load'] = self.empty_metadata llvalue.set_metadata('invariant.load', self.empty_metadata)
if isinstance(llvalue.type, ll.PointerType): if isinstance(llvalue.type, ll.PointerType):
self.mark_dereferenceable(llvalue) self.mark_dereferenceable(llvalue)
return llvalue return llvalue
@ -1065,8 +1029,8 @@ class LLVMIRGenerator:
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)], llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)],
inbounds=True) inbounds=True)
llouterenv = self.llbuilder.load(llptr) llouterenv = self.llbuilder.load(llptr)
llouterenv.metadata['invariant.load'] = self.empty_metadata llouterenv.set_metadata('invariant.load', self.empty_metadata)
llouterenv.metadata['nonnull'] = self.empty_metadata llouterenv.set_metadata('nonnull', self.empty_metadata)
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
else: else:
return llenv return llenv
@ -1325,7 +1289,7 @@ class LLVMIRGenerator:
# Never add TBAA nowrite metadata to a functon with sret! # Never add TBAA nowrite metadata to a functon with sret!
# This leads to miscompilations. # This leads to miscompilations.
if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags: if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags:
llcall.metadata['tbaa'] = self.tbaa_nowrite_call llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
return llresult return llresult
@ -1358,7 +1322,7 @@ class LLVMIRGenerator:
# See the comment in process_Call. # See the comment in process_Call.
if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags: if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags:
llcall.metadata['tbaa'] = self.tbaa_nowrite_call llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
return llcall return llcall