Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add operand bundle tag support and file system support. #1056

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
17 changes: 17 additions & 0 deletions docs/source/user-guide/binding/file-system.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
===========
File system
===========

.. currentmodule:: llvmlite.binding

.. function:: getDeviceForFile(path)

Gets the llvm::sys::fs::UniqueID associated with the given file path
and then returns the device associated with that path through a call to
LLVM's getDevice method on that UniqueID.

.. function:: getFileIdForFile(path)

Gets the llvm::sys::fs::UniqueID associated with the given file path
and then returns the file ID associated with that path through a call to
LLVM's getFile method on that UniqueID.
1 change: 1 addition & 0 deletions docs/source/user-guide/binding/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ implement Numba_'s JIT compiler.
optimization-passes
analysis-utilities
pass_timings
file-system
misc
examples

8 changes: 6 additions & 2 deletions docs/source/user-guide/ir/ir-builder.rst
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ Function call
---------------

.. method:: IRBuilder.call(fn, args, name='', cconv=None, tail=None, \
fastmath=(), attrs=(), arg_attrs=None)
fastmath=(), attrs=(), arg_attrs=None, tags=None)

Call function *fn* with arguments *args*, a sequence of values.

Expand Down Expand Up @@ -548,6 +548,10 @@ Function call
the attributes to attach to the respective argument at this call site.
If an index is not present in the dictionary, or *arg_attrs* is missing
entirely, no attributes are emitted for the given argument.
* *tags* is a string containing an LLVM operand bundle to
associate with this call.
For more information about operand bundles, see the
`official LLVM documentation <http://llvm.org/docs/LangRef.html#operand-bundles>`_.

If some attributes, such as ``sret``, are specified at the function
declaration, they must also be specified at each call site for
Expand Down Expand Up @@ -682,7 +686,7 @@ Inline assembler
* *name* is the optional name of the returned LLVM value.

For more information about these parameters, see the
`official LLVM documentation <http://llvm.org/docs/LangRef.html#inline-asm-constraint-string>`_.
`LLVM operand bundle documentation <http://llvm.org/docs/LangRef.html#inline-asm-constraint-string>`_.

EXAMPLE: Adding 2 64-bit values on x86::

Expand Down
14 changes: 14 additions & 0 deletions docs/source/user-guide/ir/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,17 @@ Other types

NOTE: This class was previously called "MetaData," but it was
renamed for clarity.


.. class:: TokenType

The type for tokens which, from the LLVM language reference, are used
when a value is associated with an instruction but all uses of the
value must not attempt to introspect or obscure it. One use of this
is to associate matching pseudo-calls that demarcate a region of code.

EXAMPLE::

token_type = ir.TokenType()
start_region_fnty = ir.FunctionType(token_type, (...))
end_region_fnty = ir.FunctionType(ir.Type.void(), (token_type,))
2 changes: 1 addition & 1 deletion ffi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ endif()
add_library(llvmlite SHARED assembly.cpp bitcode.cpp core.cpp initfini.cpp
module.cpp value.cpp executionengine.cpp transforms.cpp type.cpp
passmanagers.cpp targets.cpp dylib.cpp linker.cpp object_file.cpp
custom_passes.cpp orcjit.cpp memorymanager.cpp)
custom_passes.cpp orcjit.cpp file_system.cpp memorymanager.cpp)

# Find the libraries that correspond to the LLVM components
# that we wish to use.
Expand Down
2 changes: 1 addition & 1 deletion ffi/Makefile.freebsd
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ INCLUDE = core.h
SRC = assembly.cpp bitcode.cpp core.cpp initfini.cpp module.cpp value.cpp \
executionengine.cpp transforms.cpp passmanagers.cpp type.cpp targets.cpp \
dylib.cpp linker.cpp object_file.cpp orcjit.cpp custom_passes.cpp \
memorymanager.cpp
memorymanager.cpp file_system.cpp
OUTPUT = libllvmlite.so

all: $(OUTPUT)
Expand Down
3 changes: 2 additions & 1 deletion ffi/Makefile.linux
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ LIBS = $(LLVM_LIBS)
INCLUDE = core.h
OBJ = assembly.o bitcode.o core.o initfini.o module.o value.o \
executionengine.o transforms.o passmanagers.o targets.o type.o dylib.o \
linker.o object_file.o custom_passes.o orcjit.o memorymanager.o
linker.o object_file.o custom_passes.o orcjit.o memorymanager.o \
file_system.o
OUTPUT = libllvmlite.so

all: $(OUTPUT)
Expand Down
2 changes: 1 addition & 1 deletion ffi/Makefile.osx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ INCLUDE = core.h
SRC = assembly.cpp bitcode.cpp core.cpp initfini.cpp module.cpp value.cpp \
executionengine.cpp transforms.cpp passmanagers.cpp targets.cpp type.cpp \
dylib.cpp linker.cpp object_file.cpp custom_passes.cpp orcjit.cpp \
memorymanager.cpp
memorymanager.cpp file_system.cpp
OUTPUT = libllvmlite.dylib
MACOSX_DEPLOYMENT_TARGET ?= 10.9

Expand Down
27 changes: 27 additions & 0 deletions ffi/file_system.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "core.h"

#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Object.h"

#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/FileSystem.h"

#include <stdio.h>

extern "C" {

API_EXPORT(uint64_t)
LLVMPY_GetDeviceForFile(const char *path) {
llvm::sys::fs::UniqueID ID;
llvm::sys::fs::getUniqueID(path, ID);
return ID.getDevice();
}

API_EXPORT(uint64_t)
LLVMPY_GetFileIdForFile(const char *path) {
llvm::sys::fs::UniqueID ID;
llvm::sys::fs::getUniqueID(path, ID);
return ID.getFile();
}

} // end extern C
1 change: 1 addition & 0 deletions llvmlite/binding/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
from .object_file import *
from .context import *
from .orcjit import *
from .file_system import *
20 changes: 20 additions & 0 deletions llvmlite/binding/file_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from . import ffi
from ctypes import c_char_p, c_uint64
from .common import _encode_string


def getDeviceForFile(path):
cp = _encode_string(path)
return ffi.lib.LLVMPY_GetDeviceForFile(cp)


def getFileIdForFile(path):
cp = _encode_string(path)
return ffi.lib.LLVMPY_GetFileIdForFile(cp)


ffi.lib.LLVMPY_GetDeviceForFile.argtypes = [c_char_p]
ffi.lib.LLVMPY_GetDeviceForFile.restype = c_uint64

ffi.lib.LLVMPY_GetFileIdForFile.argtypes = [c_char_p]
ffi.lib.LLVMPY_GetFileIdForFile.restype = c_uint64
22 changes: 14 additions & 8 deletions llvmlite/ir/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,12 +771,17 @@ def store(self, value, ptr, align=None):
Store value to pointer, with optional guaranteed alignment:
*ptr = name
"""
if not isinstance(ptr.type, types.PointerType):
msg = "cannot store to value of type %s (%r): not a pointer"
raise TypeError(msg % (ptr.type, str(ptr)))
if ptr.type.pointee != value.type:
raise TypeError("cannot store %s to %s: mismatching types"
% (value.type, ptr.type))
if isinstance(ptr.type, types.TokenType):
if ptr.type != value.type:
raise TypeError("cannot store %s to %s: mismatching types"
% (value.type, ptr.type))
else:
if not isinstance(ptr.type, types.PointerType):
msg = "cannot store to value of type %s (%r): not a pointer"
raise TypeError(msg % (ptr.type, str(ptr)))
if ptr.type.pointee != value.type:
raise TypeError("cannot store %s to %s: mismatching types"
% (value.type, ptr.type))
st = instructions.StoreInstr(self.block, value, ptr)
st.align = align
self._insert(st)
Expand Down Expand Up @@ -873,14 +878,15 @@ def resume(self, landingpad):
# Call APIs

def call(self, fn, args, name='', cconv=None, tail=False, fastmath=(),
attrs=(), arg_attrs=None):
attrs=(), arg_attrs=None, tags=None):
"""
Call function *fn* with *args*:
name = fn(args...)
"""
inst = instructions.CallInstr(self.block, fn, args, name=name,
cconv=cconv, tail=tail, fastmath=fastmath,
attrs=attrs, arg_attrs=arg_attrs)
attrs=attrs, arg_attrs=arg_attrs,
tags=tags)
self._insert(inst)
return inst

Expand Down
16 changes: 12 additions & 4 deletions llvmlite/ir/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class FastMathFlags(AttributeSet):

class CallInstr(Instruction):
def __init__(self, parent, func, args, name='', cconv=None, tail=None,
fastmath=(), attrs=(), arg_attrs=None):
fastmath=(), attrs=(), arg_attrs=None, tags=None):
self.cconv = (func.calling_convention
if cconv is None and isinstance(func, Function)
else cconv)
Expand All @@ -83,6 +83,7 @@ def __init__(self, parent, func, args, name='', cconv=None, tail=None,
self.tail = tail
self.fastmath = FastMathFlags(fastmath)
self.attributes = CallInstrAttributes(attrs)
self.tags = tags
self.arg_attributes = {}
if arg_attrs:
for idx, attrs in arg_attrs.items():
Expand Down Expand Up @@ -161,15 +162,19 @@ def descr_arg(i, a):
fm_attrs = ' ' + ' '.join(self.fastmath._to_list(fnty.return_type))\
if self.fastmath else ''

buf.append("{tail}{op}{fastmath} {callee}({args}){attr}{meta}\n".format(
tag_attrs = ' ' + self.tags if self.tags else ''

msg = "{tail}{op}{fastmath} {callee}({args}){attr}{tags}{meta}\n"
buf.append(msg.format(
tail=tail_marker,
op=self.opname,
callee=callee_ref,
fastmath=fm_attrs,
callee=callee_ref,
args=args,
attr=fn_attrs,
tags=tag_attrs,
meta=(self._stringify_metadata(leading_comma=True)
if add_metadata else ""),
if add_metadata else "")
))

def descr(self, buf):
Expand Down Expand Up @@ -528,6 +533,9 @@ def descr(self, buf):
if self.metadata:
buf.append(self._stringify_metadata(leading_comma=True))

def get_decl(self):
return '{0} %"{1}"'.format(self.type, self._get_name())


class GEPInstr(Instruction):
def __init__(self, parent, ptr, indices, inbounds, name):
Expand Down
7 changes: 5 additions & 2 deletions llvmlite/ir/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def __init__(self, name='', context=context.global_context):
self.namedmetadata = {}
# Cache for metadata node deduplication
self._metadatacache = {}
self.device_triples = None

def _fix_metadata_operands(self, operands):
fixed_ops = []
Expand Down Expand Up @@ -236,8 +237,10 @@ def __repr__(self):
lines += [
'; ModuleID = "%s"' % (self.name,),
'target triple = "%s"' % (self.triple,),
'target datalayout = "%s"' % (self.data_layout,),
'']
'target datalayout = "%s"' % (self.data_layout,)]
if self.device_triples is not None:
lines += ['target device_triples = "%s"' % self.device_triples]
lines += ['']
# Body
lines += self._get_body_lines()
# Metadata
Expand Down
20 changes: 20 additions & 0 deletions llvmlite/ir/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,26 @@ def __hash__(self):
return hash(VoidType)


class TokenType(Type):
"""
The type for tokens. From the LLVM Language Reference.

'The token type is used when a value is associated with an
instruction but all uses of the value must not attempt to
introspect or obscure it. As such, it is not appropriate
to have a phi or select of type token.'
"""

def _to_string(self):
return 'token'

def __eq__(self, other):
return isinstance(other, TokenType)

def __hash__(self):
return hash(TokenType)


class FunctionType(Type):
"""
The type for functions.
Expand Down
6 changes: 6 additions & 0 deletions llvmlite/tests/test_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,12 @@ def test_no_accidental_warnings(self):
cmdargs = [sys.executable, flags, "-c", code]
subprocess.check_call(cmdargs)

def test_getDeviceForFile(self):
self.assertTrue(llvm.getDeviceForFile(__file__) != 0)

def test_getFileIdForFile(self):
self.assertTrue(llvm.getFileIdForFile(__file__) != 0)


class TestModuleRef(BaseTest):

Expand Down
23 changes: 23 additions & 0 deletions llvmlite/tests/test_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,29 @@ def test_call_tail(self):
tail call void @"my_fun"()
""") # noqa E501

def test_call_tags(self):
block = self.block(name='my_block')
builder = ir.IRBuilder(block)
token_ty = ir.TokenType()
sfun_ty = ir.FunctionType(token_ty, ())
efun_ty = ir.FunctionType(ir.VoidType(), (token_ty,))
sfun = ir.Function(builder.function.module, sfun_ty, 'start_fun')
efun = ir.Function(builder.function.module, efun_ty, 'end_fun')
cres = builder.call(
sfun,
(),
tags="[\"SOME_STRING\"(), \"SOME_OTHER_STRING\"(i64* %\"$const1\")]"
)
builder.call(
efun,
(cres,)
)
self.check_block(block, """\
my_block:
%".6" = call token @"start_fun"() ["SOME_STRING"(), "SOME_OTHER_STRING"(i64* %"$const1")]
call void @"end_fun"(token %".6")
""") # noqa E501

def test_invalid_call_attributes(self):
block = self.block()
builder = ir.IRBuilder(block)
Expand Down