Index: test/Transforms/NaCl/expand-tls-constexpr.ll |
diff --git a/test/Transforms/NaCl/expand-tls-constexpr.ll b/test/Transforms/NaCl/expand-tls-constexpr.ll |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b7ab25369208b994227313322edd9dbedd0acec3 |
--- /dev/null |
+++ b/test/Transforms/NaCl/expand-tls-constexpr.ll |
@@ -0,0 +1,152 @@ |
+; RUN: opt < %s -nacl-expand-tls-constant-expr -S | FileCheck %s |
+ |
+@tvar = thread_local global i32 0 |
+ |
+ |
+define i32 @test_converting_ptrtoint() { |
+ ret i32 ptrtoint (i32* @tvar to i32) |
+} |
+; CHECK: define i32 @test_converting_ptrtoint() |
+; CHECK: %expanded = ptrtoint i32* @tvar to i32 |
+; CHECK: ret i32 %expanded |
+ |
+ |
+define i32 @test_converting_add() { |
+ ret i32 add (i32 ptrtoint (i32* @tvar to i32), i32 4) |
+} |
+; CHECK: define i32 @test_converting_add() |
+; CHECK: %expanded1 = ptrtoint i32* @tvar to i32 |
+; CHECK: %expanded = add i32 %expanded1, 4 |
+; CHECK: ret i32 %expanded |
+ |
+ |
+define i32 @test_converting_multiple_operands() { |
+ ret i32 add (i32 ptrtoint (i32* @tvar to i32), |
+ i32 ptrtoint (i32* @tvar to i32)) |
+} |
+; CHECK: define i32 @test_converting_multiple_operands() |
+; CHECK: %expanded1 = ptrtoint i32* @tvar to i32 |
+; CHECK: %expanded = add i32 %expanded1, %expanded1 |
+; CHECK: ret i32 %expanded |
+ |
+ |
+define i32 @test_allocating_new_var_name(i32 %expanded) { |
+ %result = add i32 %expanded, ptrtoint (i32* @tvar to i32) |
+ ret i32 %result |
+} |
+; CHECK: define i32 @test_allocating_new_var_name(i32 %expanded) |
+; CHECK: %expanded1 = ptrtoint i32* @tvar to i32 |
+; CHECK: %result = add i32 %expanded, %expanded1 |
+; CHECK: ret i32 %result |
+ |
+ |
+define i8* @test_converting_bitcast() { |
+ ret i8* bitcast (i32* @tvar to i8*) |
+} |
+; CHECK: define i8* @test_converting_bitcast() |
+; CHECK: %expanded = bitcast i32* @tvar to i8* |
+; CHECK: ret i8* %expanded |
+ |
+ |
+define i32* @test_converting_getelementptr() { |
+ ; Use an index >1 to ensure that "inbounds" is not added automatically. |
+ ret i32* getelementptr (i32* @tvar, i32 2) |
+} |
+; CHECK: define i32* @test_converting_getelementptr() |
+; CHECK: %expanded = getelementptr i32* @tvar, i32 2 |
+; CHECK: ret i32* %expanded |
+ |
+ |
+; This is identical to @test_converting_getelementptr(). |
+; We need to check that both copies of getelementptr are fixed. |
+define i32* @test_converting_getelementptr_copy() { |
+ ret i32* getelementptr (i32* @tvar, i32 2) |
+} |
+; CHECK: define i32* @test_converting_getelementptr_copy() |
+; CHECK: %expanded = getelementptr i32* @tvar, i32 2 |
+; CHECK: ret i32* %expanded |
+ |
+ |
+define i32* @test_converting_getelementptr_inbounds() { |
+ ret i32* getelementptr inbounds (i32* @tvar, i32 2) |
+} |
+; CHECK: define i32* @test_converting_getelementptr_inbounds() |
+; CHECK: %expanded = getelementptr inbounds i32* @tvar, i32 2 |
+; CHECK: ret i32* %expanded |
+ |
+ |
+define i32* @test_converting_phi(i1 %cmp) { |
+entry: |
+ br i1 %cmp, label %return, label %else |
+ |
+else: |
+ br label %return |
+ |
+return: |
+ %result = phi i32* [ getelementptr (i32* @tvar, i32 1), %entry ], [ null, %else ] |
+ ret i32* %result |
+} |
+; The converted ConstantExprs get pushed back into the PHI node's |
+; incoming block, which might be suboptimal but works in all cases. |
+; CHECK: define i32* @test_converting_phi(i1 %cmp) |
+; CHECK: entry: |
+; CHECK: %expanded = getelementptr inbounds i32* @tvar, i32 1 |
+; CHECK: else: |
+; CHECK: return: |
+; CHECK: %result = phi i32* [ %expanded, %entry ], [ null, %else ] |
+ |
+ |
+@addr1 = global i8* blockaddress(@test_converting_phi_with_indirectbr, %return) |
+@addr2 = global i8* blockaddress(@test_converting_phi_with_indirectbr, %else) |
+define i32* @test_converting_phi_with_indirectbr(i8* %addr) { |
+entry: |
+ indirectbr i8* %addr, [ label %return, label %else ] |
+ |
+else: |
+ br label %return |
+ |
+return: |
+ %result = phi i32* [ getelementptr (i32* @tvar, i32 1), %entry ], [ null, %else ] |
+ ret i32* %result |
+} |
+; CHECK: define i32* @test_converting_phi_with_indirectbr(i8* %addr) |
+; CHECK: entry: |
+; CHECK: %expanded = getelementptr inbounds i32* @tvar, i32 1 |
+; CHECK: return: |
+; CHECK: %result = phi i32* [ %expanded, %entry ], [ null, %else ] |
+ |
+ |
+; This tests that ExpandTlsConstantExpr correctly handles a PHI node |
+; that contains the same ConstantExpr twice. Using |
+; replaceAllUsesWith() is not correct on a PHI node when the new |
+; instruction has to be added to an incoming block. |
+define i32 @test_converting_phi_twice(i1 %arg) { |
+ br i1 %arg, label %iftrue, label %iffalse |
+iftrue: |
+ br label %exit |
+iffalse: |
+ br label %exit |
+exit: |
+ %result = phi i32 [ ptrtoint (i32* @tvar to i32), %iftrue ], |
+ [ ptrtoint (i32* @tvar to i32), %iffalse ] |
+ ret i32 %result |
+} |
+; CHECK: define i32 @test_converting_phi_twice(i1 %arg) |
+; CHECK: iftrue: |
+; CHECK: %expanded{{.*}} = ptrtoint i32* @tvar to i32 |
+; CHECK: iffalse: |
+; CHECK: %expanded{{.*}} = ptrtoint i32* @tvar to i32 |
+; CHECK: exit: |
+; CHECK: %result = phi i32 [ %expanded1, %iftrue ], [ %expanded, %iffalse ] |
+ |
+ |
+define i32 @test_converting_phi_multiple_entry(i1 %arg) { |
+entry: |
+ br i1 %arg, label %done, label %done |
+done: |
+ %result = phi i32 [ ptrtoint (i32* @tvar to i32), %entry ], |
+ [ ptrtoint (i32* @tvar to i32), %entry ] |
+ ret i32 %result |
+} |
+; CHECK: define i32 @test_converting_phi_multiple_entry(i1 %arg) |
+; CHECK: %result = phi i32 [ %expanded, %entry ], [ %expanded, %entry ] |