nix-scripts/artiq-fast/pkgs/llvmlite-callsite.diff

186 lines
7.6 KiB
Diff

diff --git a/llvmlite/ir/builder.py b/llvmlite/ir/builder.py
index f18a8d8bd..b4958770e 100644
--- a/llvmlite/ir/builder.py
+++ b/llvmlite/ir/builder.py
@@ -872,14 +872,14 @@ def resume(self, landingpad):
# Call APIs
def call(self, fn, args, name='', cconv=None, tail=False, fastmath=(),
- attrs=()):
+ attrs=(), arg_attrs=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)
+ attrs=attrs, arg_attrs=arg_attrs)
self._insert(inst)
return inst
@@ -908,9 +908,11 @@ def store_reg(self, value, reg_type, reg_name, name=''):
return self.asm(ftype, "", "{%s}" % reg_name, [value], True, name)
def invoke(self, fn, args, normal_to, unwind_to,
- name='', cconv=None, tail=False):
+ name='', cconv=None, fastmath=(), attrs=(), arg_attrs=None):
inst = instructions.InvokeInstr(self.block, fn, args, normal_to,
- unwind_to, name=name, cconv=cconv)
+ unwind_to, name=name, cconv=cconv,
+ fastmath=fastmath, attrs=attrs,
+ arg_attrs=arg_attrs)
self._set_terminator(inst)
return inst
diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py
index 7e82ee032..f337c1586 100644
--- a/llvmlite/ir/instructions.py
+++ b/llvmlite/ir/instructions.py
@@ -5,7 +5,7 @@
from llvmlite.ir import types
from llvmlite.ir.values import (Block, Function, Value, NamedValue, Constant,
MetaDataArgument, MetaDataString, AttributeSet,
- Undefined)
+ Undefined, ArgumentAttributes)
from llvmlite.ir._utils import _HasMetadata
@@ -63,13 +63,20 @@ class FastMathFlags(AttributeSet):
class CallInstr(Instruction):
def __init__(self, parent, func, args, name='', cconv=None, tail=False,
- fastmath=(), attrs=()):
+ fastmath=(), attrs=(), arg_attrs=None):
self.cconv = (func.calling_convention
if cconv is None and isinstance(func, Function)
else cconv)
self.tail = tail
self.fastmath = FastMathFlags(fastmath)
self.attributes = CallInstrAttributes(attrs)
+ self.arg_attributes = {}
+ if arg_attrs:
+ for idx, attrs in arg_attrs.items():
+ if not (0 <= idx < len(args)):
+ raise ValueError("Invalid argument index {}"
+ .format(idx))
+ self.arg_attributes[idx] = ArgumentAttributes(attrs)
# Fix and validate arguments
args = list(args)
@@ -111,8 +118,13 @@ def called_function(self):
return self.callee
def _descr(self, buf, add_metadata):
- args = ', '.join(['{0} {1}'.format(a.type, a.get_reference())
- for a in self.args])
+ def descr_arg(i, a):
+ if i in self.arg_attributes:
+ attrs = ' '.join(self.arg_attributes[i]._to_list()) + ' '
+ else:
+ attrs = ''
+ return '{0} {1}{2}'.format(a.type, attrs, a.get_reference())
+ args = ', '.join([descr_arg(i, a) for i, a in enumerate(self.args)])
fnty = self.callee.function_type
# Only print function type if variable-argument
@@ -142,10 +154,12 @@ def descr(self, buf):
class InvokeInstr(CallInstr):
def __init__(self, parent, func, args, normal_to, unwind_to, name='',
- cconv=None):
+ cconv=None, fastmath=(), attrs=(), arg_attrs=None):
assert isinstance(normal_to, Block)
assert isinstance(unwind_to, Block)
- super(InvokeInstr, self).__init__(parent, func, args, name, cconv)
+ super(InvokeInstr, self).__init__(parent, func, args, name, cconv,
+ tail=False, fastmath=fastmath,
+ attrs=attrs, arg_attrs=arg_attrs)
self.opname = "invoke"
self.normal_to = normal_to
self.unwind_to = unwind_to
diff --git a/llvmlite/tests/test_ir.py b/llvmlite/tests/test_ir.py
index e97e528ac..ab5864719 100644
--- a/llvmlite/tests/test_ir.py
+++ b/llvmlite/tests/test_ir.py
@@ -1181,6 +1181,39 @@ def test_call_metadata(self):
call void @"llvm.dbg.declare"(metadata i32* %"a", metadata !0, metadata !0)
""") # noqa E501
+ def test_call_attributes(self):
+ block = self.block(name='my_block')
+ builder = ir.IRBuilder(block)
+ fun_ty = ir.FunctionType(
+ ir.VoidType(), (int32.as_pointer(), int32, int32.as_pointer()))
+ fun = ir.Function(builder.function.module, fun_ty, 'fun')
+ fun.args[0].add_attribute('sret')
+ retval = builder.alloca(int32, name='retval')
+ other = builder.alloca(int32, name='other')
+ builder.call(
+ fun,
+ (retval, ir.Constant(int32, 42), other),
+ arg_attrs={
+ 0: ('sret', 'noalias'),
+ 2: 'noalias'
+ }
+ )
+ self.check_block(block, """\
+ my_block:
+ %"retval" = alloca i32
+ %"other" = alloca i32
+ call void @"fun"(i32* noalias sret %"retval", i32 42, i32* noalias %"other")
+ """) # noqa E501
+
+ def test_invalid_call_attributes(self):
+ block = self.block()
+ builder = ir.IRBuilder(block)
+ fun_ty = ir.FunctionType(ir.VoidType(), ())
+ fun = ir.Function(builder.function.module, fun_ty, 'fun')
+ with self.assertRaises(ValueError):
+ # The function has no arguments, so this should fail.
+ builder.call(fun, (), arg_attrs={0: 'sret'})
+
def test_invoke(self):
block = self.block(name='my_block')
builder = ir.IRBuilder(block)
@@ -1196,6 +1229,39 @@ def test_invoke(self):
to label %"normal" unwind label %"unwind"
""")
+ def test_invoke_attributes(self):
+ block = self.block(name='my_block')
+ builder = ir.IRBuilder(block)
+ fun_ty = ir.FunctionType(
+ ir.VoidType(), (int32.as_pointer(), int32, int32.as_pointer()))
+ fun = ir.Function(builder.function.module, fun_ty, 'fun')
+ fun.calling_convention = "fastcc"
+ fun.args[0].add_attribute('sret')
+ retval = builder.alloca(int32, name='retval')
+ other = builder.alloca(int32, name='other')
+ bb_normal = builder.function.append_basic_block(name='normal')
+ bb_unwind = builder.function.append_basic_block(name='unwind')
+ builder.invoke(
+ fun,
+ (retval, ir.Constant(int32, 42), other),
+ bb_normal,
+ bb_unwind,
+ cconv='fastcc',
+ fastmath='fast',
+ attrs='noinline',
+ arg_attrs={
+ 0: ('sret', 'noalias'),
+ 2: 'noalias'
+ }
+ )
+ self.check_block(block, """\
+ my_block:
+ %"retval" = alloca i32
+ %"other" = alloca i32
+ invoke fast fastcc void @"fun"(i32* noalias sret %"retval", i32 42, i32* noalias %"other") noinline
+ to label %"normal" unwind label %"unwind"
+ """) # noqa E501
+
def test_landingpad(self):
block = self.block(name='my_block')
builder = ir.IRBuilder(block)