diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py index 35e63f77f..40944f3a2 100644 --- a/llvmlite/ir/instructions.py +++ b/llvmlite/ir/instructions.py @@ -124,6 +124,7 @@ def replace_callee(self, newfunc): if newfunc.function_type != self.callee.function_type: raise TypeError("New function has incompatible type") self.callee = newfunc + self._clear_string_cache() @property def called_function(self): @@ -214,6 +215,7 @@ def set_weights(self, weights): operands.append(Constant(types.IntType(32), w)) md = self.module.add_metadata(operands) self.set_metadata("prof", md) + self._clear_string_cache() class Ret(Terminator): @@ -260,6 +262,7 @@ def address(self): def add_destination(self, block): assert isinstance(block, Block) self.destinations.append(block) + self._clear_string_cache() def descr(self, buf): destinations = ["label {0}".format(blk.get_reference()) @@ -288,6 +291,7 @@ def add_case(self, val, block): if not isinstance(val, Value): val = Constant(self.value.type, val) self.cases.append((val, block)) + self._clear_string_cache() def descr(self, buf): cases = ["{0} {1}, label {2}".format(val.type, val.get_reference(), @@ -580,10 +584,12 @@ def descr(self, buf): def add_incoming(self, value, block): assert isinstance(block, Block) self.incomings.append((value, block)) + self._clear_string_cache() def replace_usage(self, old, new): self.incomings = [((new if val is old else val), blk) for (val, blk) in self.incomings] + self._clear_string_cache() class ExtractElement(Instruction): @@ -829,6 +835,7 @@ def __init__(self, parent, typ, name='', cleanup=False): def add_clause(self, clause): assert isinstance(clause, _LandingPadClause) self.clauses.append(clause) + self._clear_string_cache() def descr(self, buf): fmt = "landingpad {type}{cleanup}{clauses}\n" diff --git a/llvmlite/tests/test_ir.py b/llvmlite/tests/test_ir.py index 82bcef352..be70d3a1e 100644 --- a/llvmlite/tests/test_ir.py +++ b/llvmlite/tests/test_ir.py @@ -943,9 +943,10 @@ def test_misc_ops(self): def test_phi(self): block = self.block(name='my_block') builder = ir.IRBuilder(block) - a, b = builder.function.args[:2] + a, b, c = builder.function.args[:3] bb2 = builder.function.append_basic_block('b2') bb3 = builder.function.append_basic_block('b3') + bb4 = builder.function.append_basic_block('b4') phi = builder.phi(int32, 'my_phi', flags=('fast',)) phi.add_incoming(a, bb2) phi.add_incoming(b, bb3) @@ -954,6 +955,16 @@ def test_phi(self): my_block: %"my_phi" = phi fast i32 [%".1", %"b2"], [%".2", %"b3"] """) + phi.add_incoming(a, bb4) + self.check_block(block, """\ + my_block: + %"my_phi" = phi fast i32 [%".1", %"b2"], [%".2", %"b3"], [%".1", %"b4"] + """) # noqa E501 + phi.replace_usage(a, c) + self.check_block(block, """\ + my_block: + %"my_phi" = phi fast i32 [%".3", %"b2"], [%".2", %"b3"], [%".3", %"b4"] + """) # noqa E501 def test_mem_ops(self): block = self.block(name='my_block') @@ -1209,6 +1220,7 @@ def test_cbranch_weights(self): bb_true = builder.function.append_basic_block(name='b_true') bb_false = builder.function.append_basic_block(name='b_false') br = builder.cbranch(ir.Constant(int1, False), bb_true, bb_false) + self.assertNotIn('branch_weights', str(br)) br.set_weights([5, 42]) self.assertTrue(block.is_terminated) self.check_block(block, """\ @@ -1224,6 +1236,7 @@ def test_branch_indirect(self): builder = ir.IRBuilder(block) bb_1 = builder.function.append_basic_block(name='b_1') bb_2 = builder.function.append_basic_block(name='b_2') + bb_3 = builder.function.append_basic_block(name='b_3') indirectbr = builder.branch_indirect( ir.BlockAddress(builder.function, bb_1)) indirectbr.add_destination(bb_1) @@ -1233,6 +1246,11 @@ def test_branch_indirect(self): my_block: indirectbr i8* blockaddress(@"my_func", %"b_1"), [label %"b_1", label %"b_2"] """) # noqa E501 + indirectbr.add_destination(bb_3) + self.check_block(block, """\ + my_block: + indirectbr i8* blockaddress(@"my_func", %"b_1"), [label %"b_1", label %"b_2", label %"b_3"] + """) # noqa E501 def test_returns(self): def check(block, expected_ir): @@ -1281,6 +1299,7 @@ def test_switch(self): bb_onzero = builder.function.append_basic_block(name='onzero') bb_onone = builder.function.append_basic_block(name='onone') bb_ontwo = builder.function.append_basic_block(name='ontwo') + bb_onfour = builder.function.append_basic_block(name='onfour') bb_else = builder.function.append_basic_block(name='otherwise') sw = builder.switch(a, bb_else) sw.add_case(ir.Constant(int32, 0), bb_onzero) @@ -1292,6 +1311,11 @@ def test_switch(self): my_block: switch i32 %".1", label %"otherwise" [i32 0, label %"onzero" i32 1, label %"onone" i32 2, label %"ontwo"] """) # noqa E501 + sw.add_case(ir.Constant(int32, 4), bb_onfour) + self.check_block(block, """\ + my_block: + switch i32 %".1", label %"otherwise" [i32 0, label %"onzero" i32 1, label %"onone" i32 2, label %"ontwo" i32 4, label %"onfour"] + """) # noqa E501 def test_call(self): block = self.block(name='my_block') @@ -1461,9 +1485,11 @@ def test_landingpad(self): block = self.block(name='my_block') builder = ir.IRBuilder(block) lp = builder.landingpad(ir.LiteralStructType([int32, - int8.as_pointer()]), 'lp') + int8.as_pointer()]), + cleanup=True, name='lp') int_typeinfo = ir.GlobalVariable(builder.function.module, - int8.as_pointer(), "_ZTIi") + int8.as_pointer(), + "_ZTIi") int_typeinfo.global_constant = True lp.add_clause(ir.CatchClause(int_typeinfo)) lp.add_clause(ir.FilterClause(ir.Constant(ir.ArrayType( @@ -1471,9 +1497,21 @@ def test_landingpad(self): builder.resume(lp) self.check_block(block, """\ my_block: - %"lp" = landingpad {i32, i8*} + %"lp" = landingpad {i32, i8*} cleanup + catch i8** @"_ZTIi" + filter [1 x i8**] [i8** @"_ZTIi"] + resume {i32, i8*} %"lp" + """) + d_typeinfo = ir.GlobalVariable(builder.function.module, + int8.as_pointer(), "_ZTId") + d_typeinfo.global_constant = True + lp.add_clause(ir.CatchClause(d_typeinfo)) + self.check_block(block, """\ + my_block: + %"lp" = landingpad {i32, i8*} cleanup catch i8** @"_ZTIi" filter [1 x i8**] [i8** @"_ZTIi"] + catch i8** @"_ZTId" resume {i32, i8*} %"lp" """) @@ -2621,8 +2659,10 @@ def test_call_transform(self): builder.position_at_end(foo.append_basic_block()) call = builder.call(foo, ()) self.assertEqual(call.callee, foo) + self.assertIn("call void @\"foo\"()", str(mod)) modified = ir.replace_all_calls(mod, foo, bar) self.assertIn(call, modified) + self.assertNotIn("call void @\"foo\"()", str(mod)) self.assertNotEqual(call.callee, foo) self.assertEqual(call.callee, bar)