Skip to content
Permalink
 
 
Cannot retrieve contributors at this time
155 lines (123 sloc) 4.74 KB
"""
Register external C functions necessary for Numba code generation.
"""
import sys
from llvmlite import ir
import llvmlite.binding as ll
from numba.core import utils, intrinsics
from numba import _helperlib
def _add_missing_symbol(symbol, addr):
"""Add missing symbol into LLVM internal symtab
"""
if not ll.address_of_symbol(symbol):
ll.add_symbol(symbol, addr)
def _get_msvcrt_symbol(symbol):
"""
Under Windows, look up a symbol inside the C runtime
and return the raw pointer value as an integer.
"""
from ctypes import cdll, cast, c_void_p
f = getattr(cdll.msvcrt, symbol)
return cast(f, c_void_p).value
def compile_multi3(context):
"""
Compile the multi3() helper function used by LLVM
for 128-bit multiplication on 32-bit platforms.
"""
codegen = context.codegen()
library = codegen.create_library("multi3")
ir_mod = library.create_ir_module("multi3")
i64 = ir.IntType(64)
i128 = ir.IntType(128)
lower_mask = ir.Constant(i64, 0xffffffff)
_32 = ir.Constant(i64, 32)
_64 = ir.Constant(i128, 64)
fn_type = ir.FunctionType(i128, [i128, i128])
fn = ir.Function(ir_mod, fn_type, name="multi3")
a, b = fn.args
bb = fn.append_basic_block()
builder = ir.IRBuilder(bb)
# This implementation mimicks compiler-rt's.
al = builder.trunc(a, i64)
bl = builder.trunc(b, i64)
ah = builder.trunc(builder.ashr(a, _64), i64)
bh = builder.trunc(builder.ashr(b, _64), i64)
# Compute {rh, rl} = al * bl (unsigned 64-bit multiplication)
# rl = (al & 0xffffffff) * (bl & 0xffffffff)
rl = builder.mul(builder.and_(al, lower_mask), builder.and_(bl, lower_mask))
# t = rl >> 32
t = builder.lshr(rl, _32)
# rl &= 0xffffffff
rl = builder.and_(rl, lower_mask)
# t += (al >> 32) * (bl & 0xffffffff)
t = builder.add(t, builder.mul(builder.lshr(al, _32),
builder.and_(bl, lower_mask)))
# rl += t << 32
rl = builder.add(rl, builder.shl(t, _32))
# rh = t >> 32
rh = builder.lshr(t, _32)
# t = rl >> 32
t = builder.lshr(rl, _32)
# rl &= 0xffffffff
rl = builder.and_(rl, lower_mask)
# t += (bl >> 32) * (al & 0xffffffff)
t = builder.add(t, builder.mul(builder.lshr(bl, _32),
builder.and_(al, lower_mask)))
# rl += t << 32
rl = builder.add(rl, builder.shl(t, _32))
# rh += t >> 32
rh = builder.add(rh, builder.lshr(t, _32))
# rh += (al >> 32) * (bl >> 32)
rh = builder.add(rh, builder.mul(builder.lshr(al, _32),
builder.lshr(bl, _32)))
# rh += (bh * al) + (bl * ah)
rh = builder.add(rh, builder.mul(bh, al))
rh = builder.add(rh, builder.mul(bl, ah))
# r = rl + (rh << 64)
r = builder.zext(rl, i128)
r = builder.add(r, builder.shl(builder.zext(rh, i128), _64))
builder.ret(r)
library.add_ir_module(ir_mod)
library.finalize()
return library
class _Installer(object):
_installed = False
def install(self, context):
"""
Install the functions into LLVM. This only needs to be done once,
as the mappings are persistent during the process lifetime.
"""
if not self._installed:
self._do_install(context)
self._installed = True
class _ExternalMathFunctions(_Installer):
"""
Map the math functions from the C runtime library into the LLVM
execution environment.
"""
def _do_install(self, context):
is32bit = utils.MACHINE_BITS == 32
c_helpers = _helperlib.c_helpers
if sys.platform.startswith('win32') and is32bit:
# For Windows XP _ftol2 is not defined, we will just use
# _ftol as a replacement.
# On Windows 7, this is not necessary but will work anyway.
ftol = _get_msvcrt_symbol("_ftol")
_add_missing_symbol("_ftol2", ftol)
elif sys.platform.startswith('linux') and is32bit:
_add_missing_symbol("__fixunsdfdi", c_helpers["fptoui"])
_add_missing_symbol("__fixunssfdi", c_helpers["fptouif"])
if is32bit:
# Make the library immortal
self._multi3_lib = compile_multi3(context)
ptr = self._multi3_lib.get_pointer_to_function("multi3")
assert ptr
_add_missing_symbol("__multi3", ptr)
# List available C-math
for fname in intrinsics.INTR_MATH:
# Force binding from CPython's C runtime library.
# (under Windows, different versions of the C runtime can
# be loaded at the same time, for example msvcrt100 by
# CPython and msvcrt120 by LLVM)
ll.add_symbol(fname, c_helpers[fname])
c_math_functions = _ExternalMathFunctions()
You can’t perform that action at this time.