|
| 1 | +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes |
| 2 | +; RUN: opt -S -passes=argpromotion < %s | FileCheck %s |
| 3 | + |
| 4 | +; In the following tests, the call to @callee may invalidate ptr %test_c and so |
| 5 | +; prohibit removing loads of %test_c following the call, preventing Argument |
| 6 | +; Promotion of %test_c in the general case. |
| 7 | + |
| 8 | +; This is called by @caller_ptr_args, from which we cannot prove anything about |
| 9 | +; whether %test_c may alias %p and so we cannot promote %test_c. |
| 10 | +; |
| 11 | +define internal i32 @test_cannot_promote_1(ptr %p, ptr nocapture readonly %test_c) { |
| 12 | +; CHECK-LABEL: define {{[^@]+}}@test_cannot_promote_1 |
| 13 | +; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) { |
| 14 | +; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 15 | +; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]]) |
| 16 | +; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 17 | +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]] |
| 18 | +; CHECK-NEXT: ret i32 [[SUM]] |
| 19 | +; |
| 20 | + %res = call i32 @callee(ptr %p, ptr %test_c) |
| 21 | + |
| 22 | + %ltest_c = load i32, ptr %test_c |
| 23 | + |
| 24 | + %sum = add i32 %ltest_c, %res |
| 25 | + |
| 26 | + ret i32 %sum |
| 27 | +} |
| 28 | + |
| 29 | +; This is called by @caller_aliased_args, from which we can see that %test_c may |
| 30 | +; alias %p and so we cannot promote %test_c. |
| 31 | +; |
| 32 | +define internal i32 @test_cannot_promote_2(ptr %p, ptr nocapture readonly %test_c) { |
| 33 | +; CHECK-LABEL: define {{[^@]+}}@test_cannot_promote_2 |
| 34 | +; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) { |
| 35 | +; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 36 | +; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]]) |
| 37 | +; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 38 | +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]] |
| 39 | +; CHECK-NEXT: ret i32 [[SUM]] |
| 40 | +; |
| 41 | + %res = call i32 @callee(ptr %p, ptr %test_c) |
| 42 | + |
| 43 | + %ltest_c = load i32, ptr %test_c |
| 44 | + |
| 45 | + %sum = add i32 %ltest_c, %res |
| 46 | + |
| 47 | + ret i32 %sum |
| 48 | +} |
| 49 | + |
| 50 | +; This is called by @caller_safe_args_1, but also from @caller_aliased_args, so |
| 51 | +; we cannot promote %test_c. |
| 52 | +; |
| 53 | +define internal i32 @test_cannot_promote_3(ptr %p, ptr nocapture readonly %test_c) { |
| 54 | +; CHECK-LABEL: define {{[^@]+}}@test_cannot_promote_3 |
| 55 | +; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) { |
| 56 | +; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 57 | +; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]]) |
| 58 | +; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 59 | +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]] |
| 60 | +; CHECK-NEXT: ret i32 [[SUM]] |
| 61 | +; |
| 62 | + %res = call i32 @callee(ptr %p, ptr %test_c) |
| 63 | + |
| 64 | + %ltest_c = load i32, ptr %test_c |
| 65 | + |
| 66 | + %sum = add i32 %ltest_c, %res |
| 67 | + |
| 68 | + ret i32 %sum |
| 69 | +} |
| 70 | + |
| 71 | +; FIXME: We should perform ArgPromotion here! |
| 72 | +; |
| 73 | +; This is called only by @caller_safe_args_1, from which we can prove that |
| 74 | +; %test_c does not alias %p for any Call to the function, so we can promote it. |
| 75 | +; |
| 76 | +define internal i32 @test_can_promote_1(ptr %p, ptr nocapture readonly %test_c) { |
| 77 | +; CHECK-LABEL: define {{[^@]+}}@test_can_promote_1 |
| 78 | +; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) { |
| 79 | +; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 80 | +; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]]) |
| 81 | +; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 82 | +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]] |
| 83 | +; CHECK-NEXT: ret i32 [[SUM]] |
| 84 | +; |
| 85 | + %res = call i32 @callee(ptr %p, ptr %test_c) |
| 86 | + |
| 87 | + %ltest_c = load i32, ptr %test_c |
| 88 | + |
| 89 | + %sum = add i32 %ltest_c, %res |
| 90 | + |
| 91 | + ret i32 %sum |
| 92 | +} |
| 93 | + |
| 94 | +; FIXME: We should perform ArgPromotion here! |
| 95 | +; |
| 96 | +; This is called by multiple callers (@caller_safe_args_1, @caller_safe_args_2), |
| 97 | +; from which we can prove that %test_c does not alias %p for any Call to the |
| 98 | +; function, so we can promote it. |
| 99 | +; |
| 100 | +define internal i32 @test_can_promote_2(ptr %p, ptr nocapture readonly %test_c) { |
| 101 | +; CHECK-LABEL: define {{[^@]+}}@test_can_promote_2 |
| 102 | +; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) { |
| 103 | +; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 104 | +; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]]) |
| 105 | +; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4 |
| 106 | +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]] |
| 107 | +; CHECK-NEXT: ret i32 [[SUM]] |
| 108 | +; |
| 109 | + %res = call i32 @callee(ptr %p, ptr %test_c) |
| 110 | + |
| 111 | + %ltest_c = load i32, ptr %test_c |
| 112 | + |
| 113 | + %sum = add i32 %ltest_c, %res |
| 114 | + |
| 115 | + ret i32 %sum |
| 116 | +} |
| 117 | + |
| 118 | +; Called by @test_XXX |
| 119 | +define internal i32 @callee(ptr %p, ptr nocapture readonly %callee_c) { |
| 120 | +; CHECK-LABEL: define {{[^@]+}}@callee |
| 121 | +; CHECK-SAME: (ptr [[P:%.*]], i32 [[CALLEE_C_0_VAL:%.*]]) { |
| 122 | +; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4 |
| 123 | +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[A]], [[CALLEE_C_0_VAL]] |
| 124 | +; CHECK-NEXT: store i32 [[SUM]], ptr [[P]], align 4 |
| 125 | +; CHECK-NEXT: ret i32 [[SUM]] |
| 126 | +; |
| 127 | + %a = load i32, ptr %p |
| 128 | + |
| 129 | + %lcallee_c = load i32, ptr %callee_c |
| 130 | + |
| 131 | + %sum = add i32 %a, %lcallee_c |
| 132 | + |
| 133 | + store i32 %sum, ptr %p |
| 134 | + |
| 135 | + ret i32 %sum |
| 136 | +} |
| 137 | + |
| 138 | +; Calls @test_cannot_promote_1 |
| 139 | +define i32 @caller_ptr_args(i64 %n, ptr %p1, ptr %p2) { |
| 140 | +; CHECK-LABEL: define {{[^@]+}}@caller_ptr_args |
| 141 | +; CHECK-SAME: (i64 [[N:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) { |
| 142 | +; CHECK-NEXT: call void @memset(ptr [[P1]], i64 0, i64 [[N]]) |
| 143 | +; CHECK-NEXT: store i32 5, ptr [[P2]], align 4 |
| 144 | +; CHECK-NEXT: [[RES:%.*]] = call i32 @test_cannot_promote_1(ptr [[P1]], ptr [[P2]]) |
| 145 | +; CHECK-NEXT: ret i32 [[RES]] |
| 146 | +; |
| 147 | + call void @memset(ptr %p1, i64 0, i64 %n) |
| 148 | + |
| 149 | + store i32 5, ptr %p2 |
| 150 | + |
| 151 | + %res = call i32 @test_cannot_promote_1(ptr %p1, ptr %p2) |
| 152 | + |
| 153 | + ret i32 %res |
| 154 | +} |
| 155 | + |
| 156 | +; Calls @test_cannot_promote_2 |
| 157 | +; Calls @test_cannot_promote_3 |
| 158 | +define i32 @caller_aliased_args() { |
| 159 | +; CHECK-LABEL: define {{[^@]+}}@caller_aliased_args() { |
| 160 | +; CHECK-NEXT: [[CALLER_C:%.*]] = alloca i32, align 4 |
| 161 | +; CHECK-NEXT: store i32 5, ptr [[CALLER_C]], align 4 |
| 162 | +; CHECK-NEXT: [[RES1:%.*]] = call i32 @test_cannot_promote_2(ptr [[CALLER_C]], ptr [[CALLER_C]]) |
| 163 | +; CHECK-NEXT: [[RES2:%.*]] = call i32 @test_cannot_promote_3(ptr [[CALLER_C]], ptr [[CALLER_C]]) |
| 164 | +; CHECK-NEXT: [[RES:%.*]] = add i32 [[RES1]], [[RES2]] |
| 165 | +; CHECK-NEXT: ret i32 [[RES]] |
| 166 | +; |
| 167 | + %caller_c = alloca i32 |
| 168 | + store i32 5, ptr %caller_c |
| 169 | + |
| 170 | + %res1 = call i32 @test_cannot_promote_2(ptr %caller_c, ptr %caller_c) |
| 171 | + %res2 = call i32 @test_cannot_promote_3(ptr %caller_c, ptr %caller_c) |
| 172 | + |
| 173 | + %res = add i32 %res1, %res2 |
| 174 | + |
| 175 | + ret i32 %res |
| 176 | +} |
| 177 | + |
| 178 | +; Calls @test_cannot_promote_3 |
| 179 | +; Calls @test_can_promote_1 |
| 180 | +; Calls @test_can_promote_2 |
| 181 | +define i32 @caller_safe_args_1(i64 %n) { |
| 182 | +; CHECK-LABEL: define {{[^@]+}}@caller_safe_args_1 |
| 183 | +; CHECK-SAME: (i64 [[N:%.*]]) { |
| 184 | +; CHECK-NEXT: [[P:%.*]] = alloca [5 x double], i64 [[N]], align 8 |
| 185 | +; CHECK-NEXT: call void @memset(ptr [[P]], i64 0, i64 [[N]]) |
| 186 | +; CHECK-NEXT: [[CALLER_C:%.*]] = alloca i32, align 4 |
| 187 | +; CHECK-NEXT: store i32 5, ptr [[CALLER_C]], align 4 |
| 188 | +; CHECK-NEXT: [[RES1:%.*]] = call i32 @test_cannot_promote_3(ptr [[P]], ptr [[CALLER_C]]) |
| 189 | +; CHECK-NEXT: [[RES2:%.*]] = call i32 @test_can_promote_1(ptr [[P]], ptr [[CALLER_C]]) |
| 190 | +; CHECK-NEXT: [[RES3:%.*]] = call i32 @test_can_promote_2(ptr [[P]], ptr [[CALLER_C]]) |
| 191 | +; CHECK-NEXT: [[RES12:%.*]] = add i32 [[RES1]], [[RES2]] |
| 192 | +; CHECK-NEXT: [[RES:%.*]] = add i32 [[RES12]], [[RES3]] |
| 193 | +; CHECK-NEXT: ret i32 [[RES]] |
| 194 | +; |
| 195 | + %p = alloca [5 x double], i64 %n |
| 196 | + call void @memset(ptr %p, i64 0, i64 %n) |
| 197 | + |
| 198 | + %caller_c = alloca i32 |
| 199 | + store i32 5, ptr %caller_c |
| 200 | + |
| 201 | + %res1 = call i32 @test_cannot_promote_3(ptr %p, ptr %caller_c) |
| 202 | + %res2 = call i32 @test_can_promote_1(ptr %p, ptr %caller_c) |
| 203 | + %res3 = call i32 @test_can_promote_2(ptr %p, ptr %caller_c) |
| 204 | + |
| 205 | + %res12 = add i32 %res1, %res2 |
| 206 | + %res = add i32 %res12, %res3 |
| 207 | + |
| 208 | + ret i32 %res |
| 209 | +} |
| 210 | + |
| 211 | +; Calls @test_can_promote_2 |
| 212 | +define i32 @caller_safe_args_2(i64 %n, ptr %p) { |
| 213 | +; CHECK-LABEL: define {{[^@]+}}@caller_safe_args_2 |
| 214 | +; CHECK-SAME: (i64 [[N:%.*]], ptr [[P:%.*]]) { |
| 215 | +; CHECK-NEXT: call void @memset(ptr [[P]], i64 0, i64 [[N]]) |
| 216 | +; CHECK-NEXT: [[CALLER_C:%.*]] = alloca i32, align 4 |
| 217 | +; CHECK-NEXT: store i32 5, ptr [[CALLER_C]], align 4 |
| 218 | +; CHECK-NEXT: [[RES:%.*]] = call i32 @test_can_promote_2(ptr [[P]], ptr [[CALLER_C]]) |
| 219 | +; CHECK-NEXT: ret i32 [[RES]] |
| 220 | +; |
| 221 | + call void @memset(ptr %p, i64 0, i64 %n) |
| 222 | + |
| 223 | + %caller_c = alloca i32 |
| 224 | + store i32 5, ptr %caller_c |
| 225 | + |
| 226 | + %res = call i32 @test_can_promote_2(ptr %p, ptr %caller_c) |
| 227 | + |
| 228 | + ret i32 %res |
| 229 | +} |
| 230 | + |
| 231 | +declare void @memset(ptr, i64, i64) |
0 commit comments