aboutsummaryrefslogtreecommitdiff
path: root/test/Transforms
diff options
context:
space:
mode:
authorMark Seaborn <mseaborn@chromium.org>2012-11-29 18:42:19 -0800
committerMark Seaborn <mseaborn@chromium.org>2012-11-29 18:42:19 -0800
commitffb0eedef4f034996ce59aac3176482617a8044c (patch)
tree03195b67f4e4770e961a4487fcdc5ac9e52bbb17 /test/Transforms
parent7a51b9c26dfc7fb9df8047c553227b47d64ba5c6 (diff)
PNaCl: Add ExpandTls pass for expanding out static TLS variables
This replaces each reference to a TLS variable "foo" with the LLVM IR equivalent of the expression: ((struct tls_template *) __nacl_read_tp())->foo This pass fills out the global variables __tls_template_start, __tls_template_end etc. which are used by src/untrusted/nacl/tls.c. These are the symbols that are otherwise defined by a binutils linker script. In order to handle the case of TLS variables that occur inside ConstantExprs, we have a helper pass, ExpandTlsConstantExpr. BUG=http://code.google.com/p/nativeclient/issues/detail?id=2837 TEST=test/Transforms/NaCl/expand-tls*.ll Review URL: https://chromiumcodereview.appspot.com/10896042
Diffstat (limited to 'test/Transforms')
-rw-r--r--test/Transforms/NaCl/expand-tls-aligned.ll42
-rw-r--r--test/Transforms/NaCl/expand-tls-bss.ll17
-rw-r--r--test/Transforms/NaCl/expand-tls-constexpr.ll116
-rw-r--r--test/Transforms/NaCl/expand-tls-constexpr2.ll12
-rw-r--r--test/Transforms/NaCl/expand-tls-phi.ll23
-rw-r--r--test/Transforms/NaCl/expand-tls.ll85
-rw-r--r--test/Transforms/NaCl/lit.local.cfg3
7 files changed, 298 insertions, 0 deletions
diff --git a/test/Transforms/NaCl/expand-tls-aligned.ll b/test/Transforms/NaCl/expand-tls-aligned.ll
new file mode 100644
index 0000000000..75f03ba306
--- /dev/null
+++ b/test/Transforms/NaCl/expand-tls-aligned.ll
@@ -0,0 +1,42 @@
+; RUN: opt < %s -nacl-expand-tls -S | FileCheck %s
+
+target datalayout = "p:32:32:32"
+
+
+@var = global i32 123
+
+; Put this first to check that the pass handles BSS variables last.
+@bss_tvar_aligned = thread_local global i32 0, align 64
+
+@tvar1 = thread_local global i16 234
+; Test a pointer to check we are getting the right pointer size.
+@tvar2 = thread_local global i32* @var
+@tvar_aligned = thread_local global i8 99, align 32
+
+
+; CHECK: %tls_init_template = type <{ i16, [2 x i8], i32*, [24 x i8], i8 }>
+; CHECK: %tls_struct = type <{ %tls_init_template, %tls_bss_template }>
+
+; This struct type must be "packed" because the 31 byte padding here
+; is followed by an i32.
+; CHECK: %tls_bss_template = type <{ [31 x i8], i32, [60 x i8] }>
+
+; CHECK: @__tls_template_start = internal constant %tls_init_template <{ i16 234, [2 x i8] zeroinitializer, i32* @var, [24 x i8] zeroinitializer, i8 99 }>
+
+; CHECK: @__tls_template_alignment = internal constant i32 64
+
+
+; Create references to __tls_template_* to keep these live, otherwise
+; the definition of %tls_struct (which we check for above) is removed
+; from the output.
+
+@__tls_template_tdata_end = external global i8
+@__tls_template_end = external global i8
+
+define i8* @get_tls_template_tdata_end() {
+ ret i8* @__tls_template_tdata_end
+}
+
+define i8* @get_tls_template_end() {
+ ret i8* @__tls_template_end
+}
diff --git a/test/Transforms/NaCl/expand-tls-bss.ll b/test/Transforms/NaCl/expand-tls-bss.ll
new file mode 100644
index 0000000000..02504611f0
--- /dev/null
+++ b/test/Transforms/NaCl/expand-tls-bss.ll
@@ -0,0 +1,17 @@
+; RUN: opt < %s -nacl-expand-tls -S | FileCheck %s
+
+
+@tvar_bss1 = thread_local global i64 0
+@tvar_bss2 = thread_local global i32 0
+
+
+; CHECK: %tls_struct = type <{ %tls_init_template, %tls_bss_template }>
+; CHECK: %tls_bss_template = type <{ i64, i32, [4 x i8] }>
+
+
+define i64* @get_tvar_bss1() {
+ ret i64* @tvar_bss1
+}
+; CHECK: define i64* @get_tvar_bss1()
+; CHECK: %field = getelementptr %tls_struct* %tls_struct, i32 -1, i32 1, i32 0
+; CHECK: ret i64* %field
diff --git a/test/Transforms/NaCl/expand-tls-constexpr.ll b/test/Transforms/NaCl/expand-tls-constexpr.ll
new file mode 100644
index 0000000000..06bb8ed830
--- /dev/null
+++ b/test/Transforms/NaCl/expand-tls-constexpr.ll
@@ -0,0 +1,116 @@
+; 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 ]
diff --git a/test/Transforms/NaCl/expand-tls-constexpr2.ll b/test/Transforms/NaCl/expand-tls-constexpr2.ll
new file mode 100644
index 0000000000..ca7054961b
--- /dev/null
+++ b/test/Transforms/NaCl/expand-tls-constexpr2.ll
@@ -0,0 +1,12 @@
+; RUN: opt < %s -nacl-expand-tls -S | FileCheck %s
+
+@tvar = thread_local global i32 0
+
+define i32 @get_tvar() {
+ ret i32 ptrtoint (i32* @tvar to i32)
+}
+; CHECK: %tls_raw = call i8* @llvm.nacl.read.tp()
+; CHECK: %tls_struct = bitcast i8* %tls_raw to %tls_struct*
+; CHECK: %field = getelementptr %tls_struct* %tls_struct, i32 -1, i32 1, i32 0
+; CHECK: %expanded = ptrtoint i32* %field to i32
+; CHECK: ret i32 %expanded
diff --git a/test/Transforms/NaCl/expand-tls-phi.ll b/test/Transforms/NaCl/expand-tls-phi.ll
new file mode 100644
index 0000000000..0292a1d633
--- /dev/null
+++ b/test/Transforms/NaCl/expand-tls-phi.ll
@@ -0,0 +1,23 @@
+; 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: 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 ]
diff --git a/test/Transforms/NaCl/expand-tls.ll b/test/Transforms/NaCl/expand-tls.ll
new file mode 100644
index 0000000000..ec572ffa2c
--- /dev/null
+++ b/test/Transforms/NaCl/expand-tls.ll
@@ -0,0 +1,85 @@
+; RUN: opt < %s -nacl-expand-tls -S | FileCheck %s
+
+; All thread-local variables should be removed
+; RUN: opt < %s -nacl-expand-tls -S | not grep thread_local
+
+
+@tvar1 = thread_local global i64 123
+@tvar2 = thread_local global i32 456
+
+
+; CHECK: %tls_init_template = type <{ i64, i32 }>
+; CHECK: %tls_struct = type <{ %tls_init_template, %tls_bss_template }>
+; CHECK: %tls_bss_template = type <{ [4 x i8] }>
+
+
+; CHECK: @__tls_template_start = internal constant %tls_init_template <{ i64 123, i32 456 }>
+
+; CHECK: @__tls_template_alignment = internal constant i32 8
+
+
+define i64* @get_tvar1() {
+ ret i64* @tvar1
+}
+; CHECK: define i64* @get_tvar1()
+; CHECK: %tls_raw = call i8* @llvm.nacl.read.tp()
+; CHECK: %tls_struct = bitcast i8* %tls_raw to %tls_struct*
+; CHECK: %field = getelementptr %tls_struct* %tls_struct, i32 -1, i32 0, i32 0
+; CHECK: ret i64* %field
+
+
+define i32* @get_tvar2() {
+ ret i32* @tvar2
+}
+; Much the same as for get_tvar1.
+; CHECK: define i32* @get_tvar2()
+; CHECK: %field = getelementptr %tls_struct* %tls_struct, i32 -1, i32 0, i32 1
+
+
+; Check that we define global variables for TLS templates
+
+@__tls_template_start = external global i8
+@__tls_template_tdata_end = external global i8
+@__tls_template_end = external global i8
+
+define i8* @get_tls_template_start() {
+ ret i8* @__tls_template_start
+}
+; CHECK: define i8* @get_tls_template_start()
+; CHECK: ret i8* bitcast (%tls_init_template* @__tls_template_start to i8*)
+
+define i8* @get_tls_template_tdata_end() {
+ ret i8* @__tls_template_tdata_end
+}
+; CHECK: define i8* @get_tls_template_tdata_end()
+; CHECK: ret i8* bitcast (%tls_init_template* getelementptr inbounds (%tls_init_template* @__tls_template_start, i32 1) to i8*)
+
+define i8* @get_tls_template_end() {
+ ret i8* @__tls_template_end
+}
+; CHECK: define i8* @get_tls_template_end()
+; CHECK: ret i8* bitcast (%tls_struct* getelementptr (%tls_struct* bitcast (%tls_init_template* @__tls_template_start to %tls_struct*), i32 1) to i8*)
+
+
+; Check that we expand out the TLS layout intrinsics
+
+declare i32 @llvm.nacl.tp.tls.offset(i32)
+declare i32 @llvm.nacl.tp.tdb.offset(i32)
+
+define i32 @test_get_tp_tls_offset(i32 %tls_size) {
+ %offset = call i32 @llvm.nacl.tp.tls.offset(i32 %tls_size)
+ ret i32 %offset
+}
+; Uses of the intrinsic are replaced with uses of a regular function.
+; CHECK: define i32 @test_get_tp_tls_offset
+; CHECK: call i32 @nacl_tp_tls_offset
+; RUN: opt < %s -nacl-expand-tls -S | not grep llvm.nacl.tp.tls.offset
+
+define i32 @test_get_tp_tdb_offset(i32 %tdb_size) {
+ %offset = call i32 @llvm.nacl.tp.tdb.offset(i32 %tdb_size)
+ ret i32 %offset
+}
+; Uses of the intrinsic are replaced with uses of a regular function.
+; CHECK: define i32 @test_get_tp_tdb_offset
+; CHECK: call i32 @nacl_tp_tdb_offset
+; RUN: opt < %s -nacl-expand-tls -S | not grep llvm.nacl.tp.tdb.offset
diff --git a/test/Transforms/NaCl/lit.local.cfg b/test/Transforms/NaCl/lit.local.cfg
new file mode 100644
index 0000000000..a43fd3ebdd
--- /dev/null
+++ b/test/Transforms/NaCl/lit.local.cfg
@@ -0,0 +1,3 @@
+# -*- Python -*-
+
+config.suffixes = ['.ll']