Index: test/Transforms/NaCl/flatten-globals.ll |
diff --git a/test/Transforms/NaCl/flatten-globals.ll b/test/Transforms/NaCl/flatten-globals.ll |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5fa81fff9089522d1f5b9478c77dce025617f90c |
--- /dev/null |
+++ b/test/Transforms/NaCl/flatten-globals.ll |
@@ -0,0 +1,207 @@ |
+; RUN: opt -flatten-globals %s -S | FileCheck %s |
+; RUN: opt -flatten-globals %s -S | FileCheck %s -check-prefix=CLEANED |
+ |
+target datalayout = "p:32:32:32" |
+ |
+ |
+; Check simple cases |
+ |
+@var_i32 = global i32 258 |
+; CHECK: @var_i32 = global [4 x i8] c"\02\01\00\00" |
+; CLEANED-NOT: global i32 258 |
+ |
+@external_var = external global i32 |
+; CHECK: @external_var = external global [4 x i8] |
+ |
+@zero_init = global i32 0 |
+; CHECK: @zero_init = global [4 x i8] zeroinitializer |
+ |
+@big_zero_init = global [2000 x i8] zeroinitializer |
+; CHECK: @big_zero_init = global [2000 x i8] zeroinitializer |
+ |
+@null_ptr = global i32* null |
+; CHECK: @null_ptr = global [4 x i8] zeroinitializer |
+ |
+@undef_value = global i32 undef |
+; CHECK: @undef_value = global [4 x i8] zeroinitializer |
+ |
+%opaque = type opaque |
+@opaque_extern = external global %opaque |
+; CHECK: @opaque_extern = external global [0 x i8] |
+ |
+ |
+; Check various data types |
+ |
+@var_i1 = global i8 1 |
+; CHECK: @var_i1 = global [1 x i8] c"\01" |
+ |
+@var_i8 = global i8 65 |
+; CHECK: @var_i8 = global [1 x i8] c"A" |
+ |
+@var_i16 = global i16 258 |
+; CHECK: @var_i16 = global [2 x i8] c"\02\01" |
+ |
+@var_i64 = global i64 72623859790382856 |
+; CHECK: @var_i64 = global [8 x i8] c"\08\07\06\05\04\03\02\01" |
+ |
+@var_i128 = global i128 1339673755198158349044581307228491536 |
+; CHECK: @var_i128 = global [16 x i8] c"\10\0F\0E\0D\0C\0B\0A\09\08\07\06\05\04\03\02\01" |
+ |
+; Check that padding bits come out as zero. |
+@var_i121 = global i121 1339673755198158349044581307228491536 |
+; CHECK: @var_i121 = global [16 x i8] c"\10\0F\0E\0D\0C\0B\0A\09\08\07\06\05\04\03\02\01" |
+ |
+@var_double = global double 123.456 |
+; CHECK: @var_double = global [8 x i8] c"w\BE\9F\1A/\DD^@" |
+ |
+@var_float = global float 123.0 |
+; CHECK: @var_float = global [4 x i8] c"\00\00\F6B" |
+ |
+ |
+; Check aggregates |
+ |
+@padded_struct = global { i8, i8, i32 } { i8 65, i8 66, i32 258 } |
+; CHECK: @padded_struct = global [8 x i8] c"AB\00\00\02\01\00\00" |
+ |
+@packed_struct = global <{ i8, i8, i32 }> <{ i8 67, i8 68, i32 258 }> |
+; CHECK: @packed_struct = global [6 x i8] c"CD\02\01\00\00" |
+ |
+@i8_array = global [6 x i8] c"Hello\00" |
+; CHECK: @i8_array = global [6 x i8] c"Hello\00" |
+ |
+@i16_array = global [3 x i16] [ i16 1, i16 2, i16 3 ] |
+; CHECK: @i16_array = global [6 x i8] c"\01\00\02\00\03\00" |
+ |
+%s = type { i8, i8 } |
+@struct_array = global [2 x %s] [%s { i8 1, i8 2 }, %s { i8 3, i8 4 }] |
+; CHECK: @struct_array = global [4 x i8] c"\01\02\03\04" |
+ |
+@vector = global <2 x i32> <i32 259, i32 520> |
+; CHECK: @vector = global [8 x i8] c"\03\01\00\00\08\02\00\00" |
+ |
+ |
+; Check that various attributes are preserved |
+ |
+@constant_var = constant i32 259 |
+; CHECK: @constant_var = constant [4 x i8] c"\03\01\00\00" |
+ |
+@weak_external_var = extern_weak global i32 |
+; CHECK: @weak_external_var = extern_weak global [4 x i8] |
+ |
+@tls_var = external thread_local global i32 |
+; CHECK: @tls_var = external thread_local global [4 x i8] |
+ |
+@aligned_var = global i32 260, align 8 |
+; CHECK: @aligned_var = global [4 x i8] c"\04\01\00\00", align 8 |
+ |
+ |
+; Check alignment handling |
+ |
+@implicit_alignment_i32 = global i32 zeroinitializer |
+; CHECK: @implicit_alignment_i32 = global [4 x i8] zeroinitializer, align 4 |
+ |
+@implicit_alignment_double = global double zeroinitializer |
+; CHECK: @implicit_alignment_double = global [8 x i8] zeroinitializer, align 8 |
+ |
+@implicit_alignment_vector = global <16 x i8> zeroinitializer |
+; CHECK: @implicit_alignment_vector = global [16 x i8] zeroinitializer, align 16 |
+ |
+; FlattenGlobals is not allowed to increase the alignment of the |
+; variable when an explicit section is specified (although PNaCl does |
+; not support this attribute). |
+@lower_alignment_section = global i32 0, section "mysection", align 1 |
+; CHECK: @lower_alignment_section = global [4 x i8] zeroinitializer, section "mysection", align 1 |
+ |
+; FlattenGlobals could increase the alignment when no section is |
+; specified, but it does not. |
+@lower_alignment = global i32 0, align 1 |
+; CHECK: @lower_alignment = global [4 x i8] zeroinitializer, align 1 |
+ |
+ |
+; Check handling of global references |
+ |
+@var1 = external global i32 |
+@var2 = external global i8 |
+ |
+%ptrs1 = type { i32*, i8*, i32 } |
+@ptrs1 = global %ptrs1 { i32* @var1, i8* null, i32 259 } |
+; CHECK: @ptrs1 = global <{ i32, [8 x i8] }> <{ i32 ptrtoint ([4 x i8]* @var1 to i32), [8 x i8] c"\00\00\00\00\03\01\00\00" }> |
+ |
+%ptrs2 = type { i32, i32*, i8* } |
+@ptrs2 = global %ptrs2 { i32 259, i32* @var1, i8* @var2 } |
+; CHECK: @ptrs2 = global <{ [4 x i8], i32, i32 }> <{ [4 x i8] c"\03\01\00\00", i32 ptrtoint ([4 x i8]* @var1 to i32), i32 ptrtoint ([1 x i8]* @var2 to i32) }> |
+ |
+%ptrs3 = type { i32*, [3 x i8], i8* } |
+@ptrs3 = global %ptrs3 { i32* @var1, [3 x i8] c"foo", i8* @var2 } |
+; CHECK: @ptrs3 = global <{ i32, [4 x i8], i32 }> <{ i32 ptrtoint ([4 x i8]* @var1 to i32), [4 x i8] c"foo\00", i32 ptrtoint ([1 x i8]* @var2 to i32) }> |
+ |
+@ptr = global i32* @var1 |
+; CHECK: @ptr = global i32 ptrtoint ([4 x i8]* @var1 to i32) |
+ |
+@func_ptr = global i32* ()* @get_address |
+; CHECK: @func_ptr = global i32 ptrtoint (i32* ()* @get_address to i32) |
+ |
+@block_addr = global i8* blockaddress(@func_with_block, %label) |
+; CHECK: @block_addr = global i32 ptrtoint (i8* blockaddress(@func_with_block, %label) to i32) |
+ |
+@vector_reloc = global <2 x i32*> <i32* @var1, i32* @var1> |
+; CHECK: global <{ i32, i32 }> <{ i32 ptrtoint ([4 x i8]* @var1 to i32), i32 ptrtoint ([4 x i8]* @var1 to i32) }> |
+ |
+ |
+; Global references with addends |
+ |
+@reloc_addend = global i32* getelementptr (%ptrs1* @ptrs1, i32 0, i32 2) |
+; CHECK: @reloc_addend = global i32 add (i32 ptrtoint (<{ i32, [8 x i8] }>* @ptrs1 to i32), i32 8) |
+ |
+@negative_addend = global %ptrs1* getelementptr (%ptrs1* @ptrs1, i32 -1) |
+; CHECK: @negative_addend = global i32 add (i32 ptrtoint (<{ i32, [8 x i8] }>* @ptrs1 to i32), i32 -12) |
+ |
+@const_ptr = global i32* getelementptr (%ptrs1* null, i32 0, i32 2) |
+; CHECK: @const_ptr = global [4 x i8] c"\08\00\00\00" |
+ |
+@int_to_ptr = global i32* inttoptr (i16 260 to i32*) |
+; CHECK: @int_to_ptr = global [4 x i8] c"\04\01\00\00" |
+ |
+; Clang allows "(uintptr_t) &var" as a global initializer, so we |
+; handle this case. |
+@ptr_to_int = global i32 ptrtoint (i8* @var2 to i32) |
+; CHECK: @ptr_to_int = global i32 ptrtoint ([1 x i8]* @var2 to i32) |
+ |
+; This is handled via Constant folding. The getelementptr is |
+; converted to an undef when it is created, so the pass does not see a |
+; getelementptr here. |
+@undef_gep = global i32* getelementptr (%ptrs1* undef, i32 0, i32 2) |
+; CHECK: @undef_gep = global [4 x i8] zeroinitializer |
+ |
+; Adding an offset to a function address isn't useful, but check that |
+; the pass handles it anyway. |
+@func_addend = global i8* getelementptr ( |
+ i8* bitcast (void ()* @func_with_block to i8*), i32 123) |
+; CHECK: @func_addend = global i32 add (i32 ptrtoint (void ()* @func_with_block to i32), i32 123) |
+ |
+; Similarly, adding an offset to a label address isn't useful, but |
+; check it anyway. |
+@block_addend = global i8* getelementptr ( |
+ i8* blockaddress(@func_with_block, %label), i32 100) |
+; CHECK: @block_addend = global i32 add (i32 ptrtoint (i8* blockaddress(@func_with_block, %label) to i32), i32 100) |
+ |
+ |
+; Special cases |
+ |
+; Leave vars with "appending" linkage alone. |
+@appending = appending global [1 x i32*] [i32* @var1] |
+; CHECK: @appending = appending global [1 x i32*] [i32* bitcast ([4 x i8]* @var1 to i32*)] |
+ |
+ |
+define i32* @get_address() { |
+ ret i32* @var_i32 |
+} |
+; CHECK: define i32* @get_address() { |
+; CHECK-NEXT: ret i32* bitcast ([4 x i8]* @var_i32 to i32*) |
+ |
+ |
+define void @func_with_block() { |
+ br label %label |
+label: |
+ ret void |
+} |