Index: test/Transforms/NaCl/expand-tls-phi.ll |
diff --git a/test/Transforms/NaCl/expand-tls-phi.ll b/test/Transforms/NaCl/expand-tls-phi.ll |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4aa0a7a32cc55670866ea63b9fdb337511e168df |
--- /dev/null |
+++ b/test/Transforms/NaCl/expand-tls-phi.ll |
@@ -0,0 +1,60 @@ |
+; RUN: opt < %s -nacl-expand-tls -S | FileCheck %s |
+ |
+ |
+@tvar = thread_local global i32 123 |
+ |
+define i32* @get_tvar(i1 %cmp) { |
+entry: |
+ br i1 %cmp, label %return, label %else |
+ |
+else: |
+ br label %return |
+ |
+return: |
+ %result = phi i32* [ @tvar, %entry ], [ null, %else ] |
+ ret i32* %result |
+} |
+; The TLS access gets pushed back into the PHI node's incoming block, |
+; which might be suboptimal but works in all cases. |
+; CHECK: define i32* @get_tvar(i1 %cmp) { |
+; CHECK: entry: |
+; CHECK: %field = getelementptr %tls_struct* %tls_struct, i32 -1, i32 0, i32 0 |
+; CHECK: else: |
+; CHECK: return: |
+; CHECK: %result = phi i32* [ %field, %entry ], [ null, %else ] |
+ |
+ |
+; This tests that ExpandTls correctly handles a PHI node that contains |
+; the same TLS variable twice. Using replaceAllUsesWith() is not |
+; correct on a PHI node when the new instruction has to be added to an |
+; incoming block. |
+define i32* @tls_phi_twice(i1 %arg) { |
+ br i1 %arg, label %iftrue, label %iffalse |
+iftrue: |
+ br label %exit |
+iffalse: |
+ br label %exit |
+exit: |
+ %result = phi i32* [ @tvar, %iftrue ], [ @tvar, %iffalse ] |
+ ret i32* %result |
+} |
+; CHECK: define i32* @tls_phi_twice(i1 %arg) { |
+; CHECK: iftrue: |
+; CHECK: %field{{.*}} = getelementptr %tls_struct* %tls_struct{{.*}}, i32 -1, i32 0, i32 0 |
+; CHECK: iffalse: |
+; CHECK: %field{{.*}} = getelementptr %tls_struct* %tls_struct{{.*}}, i32 -1, i32 0, i32 0 |
+; CHECK: exit: |
+; CHECK: %result = phi i32* [ %field{{.*}}, %iftrue ], [ %field{{.*}}, %iffalse ] |
+ |
+ |
+; In this corner case, ExpandTls must expand out @tvar only once, |
+; otherwise it will produce invalid IR. |
+define i32* @tls_phi_multiple_entry(i1 %arg) { |
+entry: |
+ br i1 %arg, label %done, label %done |
+done: |
+ %result = phi i32* [ @tvar, %entry ], [ @tvar, %entry ] |
+ ret i32* %result |
+} |
+; CHECK: define i32* @tls_phi_multiple_entry(i1 %arg) { |
+; CHECK: %result = phi i32* [ %field, %entry ], [ %field, %entry ] |