Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions numba/core/debuginfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@

class AbstractDIBuilder(metaclass=abc.ABCMeta):
@abc.abstractmethod
def mark_variable(self, builder, allocavalue, name, lltype, size, loc):
def mark_variable(self, builder, allocavalue, name, lltype, size, line):
"""Emit debug info for the variable.
"""
pass

@abc.abstractmethod
def mark_location(self, builder, loc):
def mark_location(self, builder, line):
"""Emit source location information to the given IRBuilder.
"""
pass

@abc.abstractmethod
def mark_subprogram(self, function, name, loc):
def mark_subprogram(self, function, name, line):
"""Emit source location information for the given function.
"""
pass
Expand All @@ -47,13 +47,13 @@ class DummyDIBuilder(AbstractDIBuilder):
def __init__(self, module, filepath):
pass

def mark_variable(self, builder, allocavalue, name, lltype, size, loc):
def mark_variable(self, builder, allocavalue, name, lltype, size, line):
pass

def mark_location(self, builder, loc):
def mark_location(self, builder, line):
pass

def mark_subprogram(self, function, name, loc):
def mark_subprogram(self, function, name, line):
pass

def initialize(self):
Expand Down Expand Up @@ -117,7 +117,7 @@ def _var_type(self, lltype, size):
})
return mdtype

def mark_variable(self, builder, allocavalue, name, lltype, size, loc):
def mark_variable(self, builder, allocavalue, name, lltype, size, line):
m = self.module
fnty = ir.FunctionType(ir.VoidType(), [ir.MetaDataType()] * 3)
decl = cgutils.get_or_insert_function(m, fnty, 'llvm.dbg.declare')
Expand All @@ -129,19 +129,19 @@ def mark_variable(self, builder, allocavalue, name, lltype, size, loc):
'arg': 0,
'scope': self.subprograms[-1],
'file': self.difile,
'line': loc.line,
'line': line,
'type': mdtype,
})
mdexpr = m.add_debug_info('DIExpression', {})

return builder.call(decl, [allocavalue, mdlocalvar, mdexpr])

def mark_location(self, builder, loc):
builder.debug_metadata = self._add_location(loc.line)
def mark_location(self, builder, line):
builder.debug_metadata = self._add_location(line)

def mark_subprogram(self, function, name, loc):
def mark_subprogram(self, function, name, line):
di_subp = self._add_subprogram(name=name, linkagename=function.name,
line=loc.line)
line=line)
function.set_metadata("dbg", di_subp)
# disable inlining for this function for easier debugging
function.attributes.add('noinline')
Expand Down Expand Up @@ -274,26 +274,26 @@ class NvvmDIBuilder(DIBuilder):
# Used in mark_location to remember last lineno to avoid duplication
_last_lineno = None

def mark_variable(self, builder, allocavalue, name, lltype, size, loc):
def mark_variable(self, builder, allocavalue, name, lltype, size, line):
# unsupported
pass

def mark_location(self, builder, loc):
def mark_location(self, builder, line):
# Avoid duplication
if self._last_lineno == loc.line:
if self._last_lineno == line:
return
self._last_lineno = loc.line
self._last_lineno = line
# Add call to an inline asm to mark line location
asmty = ir.FunctionType(ir.VoidType(), [])
asm = ir.InlineAsm(asmty, "// dbg {}".format(loc.line), "",
asm = ir.InlineAsm(asmty, "// dbg {}".format(line), "",
side_effect=True)
call = builder.call(asm, [])
md = self._di_location(loc.line)
md = self._di_location(line)
call.set_metadata('numba.dbg', md)

def mark_subprogram(self, function, name, loc):
def mark_subprogram(self, function, name, line):
self._add_subprogram(name=name, linkagename=function.name,
line=loc.line)
line=line)

#
# Helper methods to create the metadata nodes.
Expand Down
6 changes: 3 additions & 3 deletions numba/core/lowering.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def pre_lower(self):
self.pyapi = None
self.debuginfo.mark_subprogram(function=self.builder.function,
name=self.fndesc.qualname,
loc=self.func_ir.loc)
line=self.func_ir.loc.line)

def post_lower(self):
"""
Expand Down Expand Up @@ -320,7 +320,7 @@ def post_block(self, block):

def lower_inst(self, inst):
# Set debug location for all subsequent LL instructions
self.debuginfo.mark_location(self.builder, self.loc)
self.debuginfo.mark_location(self.builder, self.loc.line)
self.debug_print(str(inst))
if isinstance(inst, ir.Assign):
ty = self.typeof(inst.target.name)
Expand Down Expand Up @@ -1309,7 +1309,7 @@ def alloca_lltype(self, name, lltype):
sizeof = self.context.get_abi_sizeof(lltype)
self.debuginfo.mark_variable(self.builder, aptr, name=name,
lltype=lltype, size=sizeof,
loc=self.loc)
line=self.loc.line)
return aptr

def incref(self, typ, val):
Expand Down
7 changes: 6 additions & 1 deletion numba/cuda/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,11 @@ def compile_ptx(pyfunc, args, debug=False, device=False, fastmath=False,
else:
fname = cres.fndesc.llvm_func_name
tgt = cres.target_context
filename = cres.type_annotation.filename
linenum = int(cres.type_annotation.linenum)
lib, kernel = tgt.prepare_cuda_kernel(cres.library, fname,
cres.signature.args, debug,
nvvm_options)
nvvm_options, filename, linenum)

cc = cc or config.CUDA_DEFAULT_PTX_CC
ptx = lib.get_asm_str(cc=cc)
Expand Down Expand Up @@ -479,8 +481,11 @@ def __init__(self, py_func, argtypes, link=None, debug=False, inline=False,
}

tgt_ctx = cres.target_context
filename = cres.type_annotation.filename

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird that I have to get the source file name from the type annotation at this stage, but I think the function IR is now lost (it was never saved after the pipeline finished).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably in the self.py_func.__code__.co_filename and cres.fndesc.lookup_module.__file__ too if they are preferable? IIRC the compile result doesn't hold reference to the IR as the IR could hold reference to e.g. globals, some of which might be large (e.g. NumPy arrays) and this would create memory pressure etc.

linenum = int(cres.type_annotation.linenum)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the line number being a string in the type annotation is a minor problem, as LLVM expects line numbers to be integers (e.g. 5), not strings ("5").

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foo.py_func.__code__.co_firstlineno might help, as might inspect module?

lib, kernel = tgt_ctx.prepare_cuda_kernel(cres.library, fname, args,
debug, nvvm_options,
filename, linenum,
max_registers)

if not link:
Expand Down
17 changes: 14 additions & 3 deletions numba/cuda/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def mangler(self, name, argtypes):
return itanium_mangler.mangle(name, argtypes)

def prepare_cuda_kernel(self, codelib, func_name, argtypes, debug,
nvvm_options, max_registers=None):
nvvm_options, filename, linenum,
max_registers=None):
"""
Adapt a code library ``codelib`` with the numba compiled CUDA kernel
with name ``fname`` and arguments ``argtypes`` for NVVM.
Expand All @@ -134,6 +135,8 @@ def prepare_cuda_kernel(self, codelib, func_name, argtypes, debug,
argtypes: An iterable of the types of arguments to the kernel.
debug: Whether to compile with debug.
nvvm_options: Dict of NVVM options used when compiling the new library.
filename: The source filename that the function is contained in.
linenum: The source line that the function is on.
Comment on lines +147 to +148

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if someone materialized a function from a string?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filename is <string> and linenum is the line in the string on which the function began - I think this is normal / expected?

max_registers: The max_registers argument for the code library.
"""
kernel_name = itanium_mangler.prepend_namespace(func_name, ns='cudapy')
Expand All @@ -143,11 +146,12 @@ def prepare_cuda_kernel(self, codelib, func_name, argtypes, debug,
max_registers=max_registers)
library.add_linking_library(codelib)
wrapper = self.generate_kernel_wrapper(library, kernel_name, func_name,
argtypes, debug)
argtypes, debug, filename,
linenum)
return library, wrapper

def generate_kernel_wrapper(self, library, kernel_name, func_name,
argtypes, debug):
argtypes, debug, filename, linenum):
"""
Generate the kernel wrapper in the given ``library``.
The function being wrapped have the name ``fname`` and argument types
Expand All @@ -166,6 +170,11 @@ def generate_kernel_wrapper(self, library, kernel_name, func_name,
wrapfn = ir.Function(wrapper_module, wrapfnty, prefixed)
builder = ir.IRBuilder(wrapfn.append_basic_block(''))

if debug:
debuginfo = self.DIBuilder(module=wrapper_module, filepath=filename)
debuginfo.mark_subprogram(wrapfn, kernel_name, linenum)
debuginfo.mark_location(builder, linenum)

# Define error handling variables
def define_error_gv(postfix):
name = wrapfn.name + postfix
Expand Down Expand Up @@ -225,6 +234,8 @@ def define_error_gv(postfix):

nvvm.set_cuda_kernel(wrapfn)
library.add_ir_module(wrapper_module)
if debug:
debuginfo.finalize()
library.finalize()
wrapfn = library.get_function(wrapfn.name)
return wrapfn
Expand Down