Add basic block and instruction position descriptors

This commit is contained in:
Mark Florisson 2013-01-21 20:58:32 -06:00
commit 3b75974731
2 changed files with 97 additions and 22 deletions

View file

@ -13,6 +13,7 @@ from llvm import _dwarf
int32_t = llvm.core.Type.int(32)
bool_t = llvm.core.Type.int(1)
p_int32_t = llvm.core.Type.pointer(int32_t)
i32 = functools.partial(llvm.core.Constant.int, int32_t)
i1 = functools.partial(llvm.core.Constant.int, bool_t)
@ -94,12 +95,16 @@ class DebugInfoDescriptor(object):
idx2name = None # { "field_idx" : field_name }
name2idx = None # { "field_name" : field_idx }
# Whether the debug descriptor is allowed to be incomplete
# The policy seems unclear ?
accept_optional_data = False
def __init__(self, *args, **kwargs):
self.class_init()
self.metadata_cache = {}
operands = list(args)
if kwargs:
if kwargs or not self.accept_optional_data:
operands = build_operand_list(self.type_descriptors,
self.idx2name, operands, kwargs)
@ -184,6 +189,12 @@ class MDList(DebugInfoDescriptor):
self.type_descriptors = [desc("op", get_md)] * len(operands)
super(MDList, self).__init__(*operands)
class NULLDescriptor(DebugInfoDescriptor):
type_descriptors = []
def build_metadata(self, llvm_module):
return llvm.core.Constant.null(p_int32_t)
class CompileUnitDescriptor(DebugInfoDescriptor):
"""
@ -205,6 +216,8 @@ class CompileUnitDescriptor(DebugInfoDescriptor):
}
"""
accept_optional_data = True
type_descriptors = [
desc("tag", get_i32),
desc("unused", get_i32),
@ -254,7 +267,7 @@ class FileDescriptor(DebugInfoDescriptor):
# Positional argument list starts here:
desc("source_filename", get_mdstr),
desc("source_filedir", get_mdstr),
desc("compile_unit", get_md),
desc("compile_unit", get_md, default=NULLDescriptor()),
]
def __init__(self, *args, **kwargs):
@ -297,12 +310,14 @@ class SubprogramDescriptor(DebugInfoDescriptor):
}
"""
accept_optional_data = True
type_descriptors = [
desc("tag", get_i32),
desc("unused", get_i32),
# Positional argument list starts here:
desc("compile_unit", get_md),
desc("file_desc", get_md),
desc("name", get_mdstr),
desc("display_name", get_mdstr),
desc("mips_linkage_name", get_mdstr),
@ -327,3 +342,42 @@ class SubprogramDescriptor(DebugInfoDescriptor):
_dwarf.DW_TAG_subprogram + _dwarf.LLVMDebugVersion, # Tag
0, # Unused
*args, **kwargs)
class BlockDescriptor(DebugInfoDescriptor):
"""
!3 = metadata !{
i32, ;; Tag = 11 + LLVMDebugVersion (DW_TAG_lexical_block)
metadata,;; Reference to context descriptor
i32, ;; Line number
i32 ;; Column number
}
"""
type_descriptors = [
desc("tag", get_i32),
# Positional argument list starts here:
desc("context_descr", get_md), # FileDescr | BlockDescr |
# SubprogDescr | ComputeUnit
desc("line_number", get_i32),
desc("col_number", get_i32),
]
def __init__(self, *args, **kwargs):
super(BlockDescriptor, self).__init__(
_dwarf.DW_TAG_lexical_block + _dwarf.LLVMDebugVersion,
*args, **kwargs)
class PositionInfoDescriptor(DebugInfoDescriptor):
"""
line number, column number, scope, and original scope
"""
type_descriptors = [
desc("line_number", get_i32),
desc("col_number", get_i32),
desc("context_descr", get_md), # Scope of instruction
# (FileDescr etc)
desc("original_context_descr", get_md, # The original scope if inlined
default=NULLDescriptor()),
]

View file

@ -31,21 +31,15 @@ class TestDebugInfo(unittest.TestCase):
bb = square.append_basic_block('entry')
bldr = Builder.new(bb)
compile_unit = debuginfo.CompileUnitDescriptor(
# DW_LANG_Python segfaults:
# llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*):
# Assertion `Str && "StringRef cannot be built from a NULL argument"'
# _dwarf.DW_LANG_Python,
_dwarf.DW_LANG_C89,
"test_debug_info.py",
os.path.expanduser("~"),
"my_cool_compiler",
)
source_filename = "test_debug_info.py"
source_filedir = os.path.expanduser("~")
filedesc = debuginfo.FileDescriptor.from_compileunit(compile_unit)
# Debug info for our file
filedesc = debuginfo.FileDescriptor(source_filename, source_filedir)
# Debug info for our function
subprogram = debuginfo.SubprogramDescriptor(
compile_unit,
filedesc,
"some_function",
"some_function",
"some_function",
@ -56,26 +50,53 @@ class TestDebugInfo(unittest.TestCase):
)
subprograms = debuginfo.MDList([subprogram])
# compile_unit.add_metadata("subprograms", subprograms)
compile_unit.define(mod)
subprogram.define(mod)
# Debug info for our basic blocks
blockdescr1 = debuginfo.BlockDescriptor(subprogram, 2, 4) # lineno, col
blockdescr2 = debuginfo.BlockDescriptor(blockdescr1, 3, 4) # lineno, col
# Debug info for our instructions
posinfo1 = debuginfo.PositionInfoDescriptor(2, 4, blockdescr1)
posinfo2 = debuginfo.PositionInfoDescriptor(2, 4, blockdescr2)
# Debug info for our module
compile_unit = debuginfo.CompileUnitDescriptor(
# DW_LANG_Python segfaults:
# llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*):
# Assertion `Str && "StringRef cannot be built from a NULL argument"'
# _dwarf.DW_LANG_Python,
_dwarf.DW_LANG_C89,
source_filename,
source_filedir,
"my_cool_compiler",
subprograms=subprograms,
)
# Define our module debug data
compile_unit.define(mod)
# Build some instructions
value = square.args[0]
result = bldr.fmul(value, value)
bldr.ret(result)
ret = bldr.ret(result)
print mod
# Annotate instructions with source position
result.set_metadata("dbg", posinfo1.get_metadata(mod))
ret.set_metadata("dbg", posinfo2.get_metadata(mod))
# ... Aaaand, test...
# print mod
modstr = str(mod)
# Test compile unit
self.assertIn("my_cool_compiler", modstr)
self.assertIn("test_debug_info.py", modstr)
self.assertIn(os.path.expanduser("~"), modstr)
self.assertIn(source_filename, modstr)
self.assertIn(source_filedir, modstr)
self.assertIn("my_cool_compiler", modstr)
# Test subprogram
self.assertIn("some_function", modstr)
self.assertIn("float (float)* @square", modstr)
if __name__ == '__main__':
# TestDebugInfo("test_dwarf_constants").debug()