Home | History | Annotate | Download | only in llvm2ice_tests
      1 ; This tests the advanced lowering of switch statements. The advanced lowering
      2 ; uses jump tables, range tests and binary search.
      3 
      4 ; RUN: %p2i -i %s --target=x8632 --filetype=obj --disassemble --args -O2 \
      5 ; RUN:   | FileCheck %s --check-prefix=CHECK --check-prefix=X8632
      6 ; RUN: %p2i -i %s --target=x8664 --filetype=obj --disassemble --args -O2 \
      7 ; RUN:   | FileCheck %s --check-prefix=CHECK --check-prefix=X8664
      8 
      9 ; RUN: %if --need=target_MIPS32 --need=allow_dump \
     10 ; RUN:   --command %p2i --filetype=asm --assemble --disassemble --target \
     11 ; RUN:   mips32 -i %s --args -O2 -allow-externally-defined-symbols \
     12 ; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
     13 ; RUN:   --command FileCheck --check-prefix MIPS32 %s
     14 
     15 ; Dense but non-continuous ranges should be converted into a jump table.
     16 define internal i32 @testJumpTable(i32 %a) {
     17 entry:
     18   switch i32 %a, label %sw.default [
     19     i32 91, label %sw.default
     20     i32 92, label %sw.bb1
     21     i32 93, label %sw.default
     22     i32 99, label %sw.bb1
     23     i32 98, label %sw.default
     24     i32 96, label %sw.bb1
     25     i32 97, label %sw.epilog
     26   ]
     27 
     28 sw.default:
     29   %add = add i32 %a, 27
     30   br label %sw.epilog
     31 
     32 sw.bb1:
     33   %tmp = add i32 %a, 16
     34   br label %sw.epilog
     35 
     36 sw.epilog:
     37   %result.1 = phi i32 [ %add, %sw.default ], [ %tmp, %sw.bb1 ], [ 17, %entry ]
     38   ret i32 %result.1
     39 }
     40 ; CHECK-LABEL: testJumpTable
     41 ; CHECK: sub [[IND:[^,]+]],0x5b
     42 ; CHECK-NEXT: cmp [[IND]],0x8
     43 ; CHECK-NEXT: ja
     44 ; X8632-NEXT: mov [[TARGET:.*]],DWORD PTR {{\[}}[[IND]]*4+0x0] {{[0-9a-f]+}}: R_386_32 .{{.*}}testJumpTable$jumptable
     45 ; X8632-NEXT: jmp [[TARGET]]
     46 ; X8664-NEXT: mov {{.}}[[TARGET:.*]],DWORD PTR {{\[}}[[IND]]*4+0x0] {{[0-9a-f]+}}: R_X86_64_32S .{{.*}}testJumpTable$jumptable
     47 ; X8664-NEXT: jmp {{.}}[[TARGET]]
     48 ; Note: x86-32 may do "mov eax, [...]; jmp eax", whereas x86-64 may do
     49 ; "mov eax, [...]; jmp rax", so we assume the all characters except the first
     50 ; one in the register name will match.
     51 
     52 ; MIPS32-LABEL: testJumpTable
     53 ; MIPS32: 	move	[[REG1:.*]],{{.*}}
     54 ; MIPS32: 	li	[[REG2:.*]],91
     55 ; MIPS32: 	beq	[[REG1]],[[REG2]],6c <.LtestJumpTable$sw.default>
     56 ; MIPS32: 	nop
     57 ; MIPS32: 	li	[[REG2:.*]],92
     58 ; MIPS32: 	beq	[[REG1]],[[REG2]],78 <.LtestJumpTable$sw.bb1>
     59 ; MIPS32: 	nop
     60 ; MIPS32: 	li	[[REG2:.*]],93
     61 ; MIPS32: 	beq	[[REG1]],[[REG2]],6c <.LtestJumpTable$sw.default>
     62 ; MIPS32: 	nop
     63 ; MIPS32: 	li	[[REG2:.*]],99
     64 ; MIPS32: 	beq	[[REG1]],[[REG2]],78 <.LtestJumpTable$sw.bb1>
     65 ; MIPS32: 	nop
     66 ; MIPS32: 	li	[[REG2:.*]],98
     67 ; MIPS32: 	beq	[[REG1]],[[REG2]],6c <.LtestJumpTable$sw.default>
     68 ; MIPS32: 	nop
     69 ; MIPS32: 	li	[[REG2:.*]],96
     70 ; MIPS32: 	beq	[[REG1]],[[REG2]],78 <.LtestJumpTable$sw.bb1>
     71 ; MIPS32: 	nop
     72 ; MIPS32: 	li	[[REG2:.*]],97
     73 ; MIPS32: 	beq	[[REG1]],[[REG2]],60 <.LtestJumpTable$split_entry_sw.epilog_0>
     74 ; MIPS32: 	nop
     75 ; MIPS32: 	b	6c <.LtestJumpTable$sw.default>
     76 ; MIPS32: 	nop
     77 
     78 ; Continuous ranges which map to the same target should be grouped and
     79 ; efficiently tested.
     80 define internal i32 @testRangeTest() {
     81 entry:
     82   switch i32 10, label %sw.default [
     83     i32 0, label %sw.epilog
     84     i32 1, label %sw.epilog
     85     i32 2, label %sw.epilog
     86     i32 3, label %sw.epilog
     87     i32 10, label %sw.bb1
     88     i32 11, label %sw.bb1
     89     i32 12, label %sw.bb1
     90     i32 13, label %sw.bb1
     91   ]
     92 
     93 sw.default:
     94   br label %sw.epilog
     95 
     96 sw.bb1:
     97   br label %sw.epilog
     98 
     99 sw.epilog:
    100   %result.1 = phi i32 [ 23, %sw.default ], [ 42, %sw.bb1 ], [ 17, %entry ], [ 17, %entry ], [ 17, %entry ], [ 17, %entry ]
    101   ret i32 %result.1
    102 }
    103 ; CHECK-LABEL: testRangeTest
    104 ; CHECK: cmp {{.*}},0x3
    105 ; CHECK-NEXT: jbe
    106 ; CHECK: sub [[REG:[^,]*]],0xa
    107 ; CHECK-NEXT: cmp [[REG]],0x3
    108 ; CHECK-NEXT: jbe
    109 ; CHECK-NEXT: jmp
    110 
    111 ; MIPS32-LABEL: testRangeTest
    112 ; MIPS32: 	li	[[REG1:.*]],10
    113 ; MIPS32: 	li	[[REG2:.*]],0
    114 ; MIPS32: 	beq	[[REG1]],[[REG2]],114 <.LtestRangeTest$split_entry_sw.epilog_0>
    115 ; MIPS32: 	nop
    116 ; MIPS32: 	li	[[REG2:.*]],1
    117 ; MIPS32: 	beq	[[REG1]],[[REG2]],114 <.LtestRangeTest$split_entry_sw.epilog_0>
    118 ; MIPS32: 	nop
    119 ; MIPS32: 	li	[[REG2:.*]],2
    120 ; MIPS32: 	beq	[[REG1]],[[REG2]],114 <.LtestRangeTest$split_entry_sw.epilog_0>
    121 ; MIPS32: 	nop
    122 ; MIPS32: 	li	[[REG2:.*]],3
    123 ; MIPS32: 	beq	[[REG1]],[[REG2]],114 <.LtestRangeTest$split_entry_sw.epilog_0>
    124 ; MIPS32: 	nop
    125 ; MIPS32: 	li	[[REG2:.*]],10
    126 ; MIPS32: 	beq	[[REG1]],[[REG2]],fc <.LtestRangeTest$split_sw.bb1_sw.epilog_2>
    127 ; MIPS32: 	nop
    128 ; MIPS32: 	li	[[REG2:.*]],11
    129 ; MIPS32: 	beq	[[REG1]],[[REG2]],fc <.LtestRangeTest$split_sw.bb1_sw.epilog_2>
    130 ; MIPS32: 	nop
    131 ; MIPS32: 	li	[[REG2:.*]],12
    132 ; MIPS32: 	beq	[[REG1]],[[REG2]],fc <.LtestRangeTest$split_sw.bb1_sw.epilog_2>
    133 ; MIPS32: 	nop
    134 ; MIPS32: 	li	[[REG2:.*]],13
    135 ; MIPS32: 	beq	[[REG1]],[[REG2]],fc <.LtestRangeTest$split_sw.bb1_sw.epilog_2>
    136 ; MIPS32: 	nop
    137 ; MIPS32: 	b	108 <.LtestRangeTest$split_sw.default_sw.epilog_1>
    138 ; MIPS32: 	nop
    139 
    140 ; Sparse cases should be searched with a binary search.
    141 define internal i32 @testBinarySearch() {
    142 entry:
    143   switch i32 10, label %sw.default [
    144     i32 0, label %sw.epilog
    145     i32 10, label %sw.epilog
    146     i32 20, label %sw.bb1
    147     i32 30, label %sw.bb1
    148   ]
    149 
    150 sw.default:
    151   br label %sw.epilog
    152 
    153 sw.bb1:
    154   br label %sw.epilog
    155 
    156 sw.epilog:
    157   %result.1 = phi i32 [ 23, %sw.default ], [ 42, %sw.bb1 ], [ 17, %entry ], [ 17, %entry ]
    158   ret i32 %result.1
    159 }
    160 ; CHECK-LABEL: testBinarySearch
    161 ; CHECK: cmp {{.*}},0x14
    162 ; CHECK-NEXT: jb
    163 ; CHECK-NEXT: je
    164 ; CHECK-NEXT: cmp {{.*}},0x1e
    165 ; CHECK-NEXT: je
    166 ; CHECK-NEXT: jmp
    167 ; CHECK-NEXT: cmp {{.*}},0x0
    168 ; CHECK-NEXT: je
    169 ; CHECK-NEXT: cmp {{.*}},0xa
    170 ; CHECK-NEXT: je
    171 ; CHECK-NEXT: jmp
    172 
    173 ; MIPS32-LABEL: testBinarySearch
    174 ; MIPS32: 	li	[[REG1:.*]],10
    175 ; MIPS32: 	li	[[REG2:.*]],0
    176 ; MIPS32: 	beq	[[REG1]],[[REG2]],174 <.LtestBinarySearch$split_entry_sw.epilog_0>
    177 ; MIPS32: 	nop
    178 ; MIPS32: 	li	[[REG2:.*]],10
    179 ; MIPS32: 	beq	[[REG1]],[[REG2]],174 <.LtestBinarySearch$split_entry_sw.epilog_0>
    180 ; MIPS32: 	nop
    181 ; MIPS32: 	li	[[REG2:.*]],20
    182 ; MIPS32: 	beq	[[REG1]],[[REG2]],15c <.LtestBinarySearch$split_sw.bb1_sw.epilog_2>
    183 ; MIPS32: 	nop
    184 ; MIPS32: 	li	[[REG2:.*]],30
    185 ; MIPS32: 	beq	[[REG1]],[[REG2]],15c <.LtestBinarySearch$split_sw.bb1_sw.epilog_2>
    186 ; MIPS32: 	nop
    187 ; MIPS32: 	b	168 <.LtestBinarySearch$split_sw.default_sw.epilog_1>
    188 ; MIPS32: 	nop
    189 
    190 ; 64-bit switches where the cases are all 32-bit values should be reduced to a
    191 ; 32-bit switch after checking the top byte is 0.
    192 define internal i32 @testSwitchSmall64(i64 %a) {
    193 entry:
    194   switch i64 %a, label %sw.default [
    195     i64 123, label %return
    196     i64 234, label %sw.bb1
    197     i64 345, label %sw.bb2
    198     i64 456, label %sw.bb3
    199   ]
    200 
    201 sw.bb1:
    202   br label %return
    203 
    204 sw.bb2:
    205   br label %return
    206 
    207 sw.bb3:
    208   br label %return
    209 
    210 sw.default:
    211   br label %return
    212 
    213 return:
    214   %retval.0 = phi i32 [ 5, %sw.default ], [ 4, %sw.bb3 ], [ 3, %sw.bb2 ], [ 2, %sw.bb1 ], [ 1, %entry ]
    215   ret i32 %retval.0
    216 }
    217 ; CHECK-LABEL: testSwitchSmall64
    218 ; X8632: cmp {{.*}},0x0
    219 ; X8632-NEXT: jne
    220 ; X8632-NEXT: cmp {{.*}},0x159
    221 ; X8632-NEXT: jb
    222 ; X8632-NEXT: je
    223 ; X8632-NEXT: cmp {{.*}},0x1c8
    224 ; X8632-NEXT: je
    225 ; X8632-NEXT: jmp
    226 ; X8632-NEXT: cmp {{.*}},0x7b
    227 ; X8632-NEXT: je
    228 ; X8632-NEXT: cmp {{.*}},0xea
    229 ; X8632-NEXT: je
    230 
    231 ; MIPS32-LABEL: testSwitchSmall64
    232 ; MIPS32: 	li	[[REG:.*]],0
    233 ; MIPS32: 	bne	{{.*}},[[REG]],198 <.LtestSwitchSmall64$local$__0>
    234 ; MIPS32: 	nop
    235 ; MIPS32: 	li	[[REG:.*]],123
    236 ; MIPS32: 	beq	{{.*}},[[REG]],210 <.LtestSwitchSmall64$split_entry_return_0>
    237 ; MIPS32: 	nop
    238 
    239 ; Test for correct 64-bit lowering.
    240 ; TODO(ascull): this should generate better code like the 32-bit version
    241 define internal i32 @testSwitch64(i64 %a) {
    242 entry:
    243   switch i64 %a, label %sw.default [
    244     i64 123, label %return
    245     i64 234, label %sw.bb1
    246     i64 345, label %sw.bb2
    247     i64 78187493520, label %sw.bb3
    248   ]
    249 
    250 sw.bb1:
    251   br label %return
    252 
    253 sw.bb2:
    254   br label %return
    255 
    256 sw.bb3:
    257   br label %return
    258 
    259 sw.default:
    260   br label %return
    261 
    262 return:
    263   %retval.0 = phi i32 [ 5, %sw.default ], [ 4, %sw.bb3 ], [ 3, %sw.bb2 ], [ 2, %sw.bb1 ], [ 1, %entry ]
    264   ret i32 %retval.0
    265 }
    266 ; CHECK-LABEL: testSwitch64
    267 ; X8632: cmp {{.*}},0x7b
    268 ; X8632-NEXT: jne
    269 ; X8632-NEXT: cmp {{.*}},0x0
    270 ; X8632-NEXT: je
    271 ; X8632: cmp {{.*}},0xea
    272 ; X8632-NEXT: jne
    273 ; X8632-NEXT: cmp {{.*}},0x0
    274 ; X8632-NEXT: je
    275 ; X8632: cmp {{.*}},0x159
    276 ; X8632-NEXT: jne
    277 ; X8632-NEXT: cmp {{.*}},0x0
    278 ; X8632-NEXT: je
    279 ; X8632: cmp {{.*}},0x34567890
    280 ; X8632-NEXT: jne
    281 ; X8632-NEXT: cmp {{.*}},0x12
    282 ; X8632-NEXT: je
    283 
    284 ; MIPS32-LABEL: testSwitch64
    285 ; MIPS32: 	li	[[REG:.*]],0
    286 ; MIPS32: 	bne	{{.*}},[[REG]],238 <.LtestSwitch64$local$__0>
    287 ; MIPS32: 	nop
    288 ; MIPS32: 	li	[[REG:.*]],123
    289 ; MIPS32: 	beq	{{.*}},[[REG]],2b4 <.LtestSwitch64$split_entry_return_0>
    290 ; MIPS32: 	nop
    291 
    292 ; Test for correct 64-bit jump table with UINT64_MAX as one of the values.
    293 define internal i32 @testJumpTable64(i64 %a) {
    294 entry:
    295   switch i64 %a, label %sw.default [
    296     i64 -6, label %return
    297     i64 -4, label %sw.bb1
    298     i64 -3, label %sw.bb2
    299     i64 -1, label %sw.bb3
    300   ]
    301 
    302 sw.bb1:
    303   br label %return
    304 
    305 sw.bb2:
    306   br label %return
    307 
    308 sw.bb3:
    309   br label %return
    310 
    311 sw.default:
    312   br label %return
    313 
    314 return:
    315   %retval.0 = phi i32 [ 5, %sw.default ], [ 4, %sw.bb3 ], [ 3, %sw.bb2 ], [ 2, %sw.bb1 ], [ 1, %entry ]
    316   ret i32 %retval.0
    317 }
    318 
    319 ; TODO(ascull): this should generate a jump table. For now, just make sure it
    320 ; doesn't crash the compiler.
    321 ; CHECK-LABEL: testJumpTable64
    322