forked from M-Labs/nix-scripts
186 lines
7.6 KiB
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)
|