436 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc < %s -mtriple=arm-eabi -mattr=+v6t2 | FileCheck %s --check-prefixes=CHECK,SCALAR3; RUN: llc < %s -mtriple=arm-eabi -mattr=+v6t2 -mattr=+neon | FileCheck %s --check-prefixes=CHECK,NEON4 5declare i8 @llvm.fshl.i8(i8, i8, i8)6declare i16 @llvm.fshl.i16(i16, i16, i16)7declare i32 @llvm.fshl.i32(i32, i32, i32)8declare i64 @llvm.fshl.i64(i64, i64, i64)9declare <4 x i32> @llvm.fshl.v4i32(<4 x i32>, <4 x i32>, <4 x i32>)10 11declare i8 @llvm.fshr.i8(i8, i8, i8)12declare i16 @llvm.fshr.i16(i16, i16, i16)13declare i32 @llvm.fshr.i32(i32, i32, i32)14declare i64 @llvm.fshr.i64(i64, i64, i64)15declare <4 x i32> @llvm.fshr.v4i32(<4 x i32>, <4 x i32>, <4 x i32>)16 17; General case - all operands can be variables.18 19define i16 @fshl_i16(i16 %x, i16 %y, i16 %z) {20; CHECK-LABEL: fshl_i16:21; CHECK: @ %bb.0:22; CHECK-NEXT: pkhbt r0, r1, r0, lsl #1623; CHECK-NEXT: and r1, r2, #1524; CHECK-NEXT: lsl r0, r0, r125; CHECK-NEXT: lsr r0, r0, #1626; CHECK-NEXT: bx lr27 %f = call i16 @llvm.fshl.i16(i16 %x, i16 %y, i16 %z)28 ret i16 %f29}30 31define i32 @fshl_i32(i32 %x, i32 %y, i32 %z) {32; CHECK-LABEL: fshl_i32:33; CHECK: @ %bb.0:34; CHECK-NEXT: mov r3, #3135; CHECK-NEXT: lsr r1, r1, #136; CHECK-NEXT: bic r3, r3, r237; CHECK-NEXT: and r2, r2, #3138; CHECK-NEXT: lsl r0, r0, r239; CHECK-NEXT: orr r0, r0, r1, lsr r340; CHECK-NEXT: bx lr41 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %z)42 ret i32 %f43}44 45; Verify that weird types are minimally supported.46declare i37 @llvm.fshl.i37(i37, i37, i37)47define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) {48; SCALAR-LABEL: fshl_i37:49; SCALAR: @ %bb.0:50; SCALAR-NEXT: .save {r4, r5, r6, r7, r8, lr}51; SCALAR-NEXT: push {r4, r5, r6, r7, r8, lr}52; SCALAR-NEXT: mov r8, r053; SCALAR-NEXT: ldr r0, [sp, #28]54; SCALAR-NEXT: mov r4, r155; SCALAR-NEXT: mov r5, r356; SCALAR-NEXT: and r1, r0, #3157; SCALAR-NEXT: ldr r0, [sp, #24]58; SCALAR-NEXT: mov r6, r259; SCALAR-NEXT: mov r2, #3760; SCALAR-NEXT: mov r3, #061; SCALAR-NEXT: bl __aeabi_uldivmod62; SCALAR-NEXT: lsl r0, r5, #2763; SCALAR-NEXT: tst r2, #3264; SCALAR-NEXT: orr r0, r0, r6, lsr #565; SCALAR-NEXT: mov r1, r866; SCALAR-NEXT: and r3, r2, #3167; SCALAR-NEXT: mov r7, #3168; SCALAR-NEXT: movne r1, r069; SCALAR-NEXT: lslne r0, r6, #2770; SCALAR-NEXT: bic r2, r7, r271; SCALAR-NEXT: lsl r5, r1, r372; SCALAR-NEXT: lsr r0, r0, #173; SCALAR-NEXT: movne r4, r874; SCALAR-NEXT: lsr r1, r1, #175; SCALAR-NEXT: lsl r3, r4, r376; SCALAR-NEXT: orr r0, r5, r0, lsr r277; SCALAR-NEXT: orr r1, r3, r1, lsr r278; SCALAR-NEXT: pop {r4, r5, r6, r7, r8, pc}79;80; NEON-LABEL: fshl_i37:81; NEON: @ %bb.0:82; NEON-NEXT: .save {r4, r5, r6, r7, r8, lr}83; NEON-NEXT: push {r4, r5, r6, r7, r8, lr}84; NEON-NEXT: mov r4, r185; NEON-NEXT: ldr r1, [sp, #28]86; NEON-NEXT: mov r8, r087; NEON-NEXT: ldr r0, [sp, #24]88; NEON-NEXT: and r1, r1, #3189; NEON-NEXT: mov r5, r390; NEON-NEXT: mov r6, r291; NEON-NEXT: mov r2, #3792; NEON-NEXT: mov r3, #093; NEON-NEXT: bl __aeabi_uldivmod94; NEON-NEXT: lsl r0, r5, #2795; NEON-NEXT: tst r2, #3296; NEON-NEXT: orr r0, r0, r6, lsr #597; NEON-NEXT: mov r1, r898; NEON-NEXT: and r3, r2, #3199; NEON-NEXT: mov r7, #31100; NEON-NEXT: movne r1, r0101; NEON-NEXT: lslne r0, r6, #27102; NEON-NEXT: bic r2, r7, r2103; NEON-NEXT: lsl r5, r1, r3104; NEON-NEXT: lsr r0, r0, #1105; NEON-NEXT: movne r4, r8106; NEON-NEXT: lsr r1, r1, #1107; NEON-NEXT: lsl r3, r4, r3108; NEON-NEXT: orr r0, r5, r0, lsr r2109; NEON-NEXT: orr r1, r3, r1, lsr r2110; NEON-NEXT: pop {r4, r5, r6, r7, r8, pc}111 %f = call i37 @llvm.fshl.i37(i37 %x, i37 %y, i37 %z)112 ret i37 %f113}114 115; extract(concat(0b1110000, 0b1111111) << 2) = 0b1000011116 117declare i7 @llvm.fshl.i7(i7, i7, i7)118define i7 @fshl_i7_const_fold() {119; CHECK-LABEL: fshl_i7_const_fold:120; CHECK: @ %bb.0:121; CHECK-NEXT: mov r0, #67122; CHECK-NEXT: bx lr123 %f = call i7 @llvm.fshl.i7(i7 112, i7 127, i7 2)124 ret i7 %f125}126 127define i8 @fshl_i8_const_fold_overshift_1() {128; CHECK-LABEL: fshl_i8_const_fold_overshift_1:129; CHECK: @ %bb.0:130; CHECK-NEXT: mov r0, #128131; CHECK-NEXT: bx lr132 %f = call i8 @llvm.fshl.i8(i8 255, i8 0, i8 15)133 ret i8 %f134}135 136define i8 @fshl_i8_const_fold_overshift_2() {137; CHECK-LABEL: fshl_i8_const_fold_overshift_2:138; CHECK: @ %bb.0:139; CHECK-NEXT: mov r0, #120140; CHECK-NEXT: bx lr141 %f = call i8 @llvm.fshl.i8(i8 15, i8 15, i8 11)142 ret i8 %f143}144 145define i8 @fshl_i8_const_fold_overshift_3() {146; CHECK-LABEL: fshl_i8_const_fold_overshift_3:147; CHECK: @ %bb.0:148; CHECK-NEXT: mov r0, #0149; CHECK-NEXT: bx lr150 %f = call i8 @llvm.fshl.i8(i8 0, i8 225, i8 8)151 ret i8 %f152}153 154; With constant shift amount, this is 'extr'.155 156define i32 @fshl_i32_const_shift(i32 %x, i32 %y) {157; CHECK-LABEL: fshl_i32_const_shift:158; CHECK: @ %bb.0:159; CHECK-NEXT: lsl r0, r0, #9160; CHECK-NEXT: orr r0, r0, r1, lsr #23161; CHECK-NEXT: bx lr162 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 9)163 ret i32 %f164}165 166; Check modulo math on shift amount.167 168define i32 @fshl_i32_const_overshift(i32 %x, i32 %y) {169; CHECK-LABEL: fshl_i32_const_overshift:170; CHECK: @ %bb.0:171; CHECK-NEXT: lsl r0, r0, #9172; CHECK-NEXT: orr r0, r0, r1, lsr #23173; CHECK-NEXT: bx lr174 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 41)175 ret i32 %f176}177 178; 64-bit should also work.179 180define i64 @fshl_i64_const_overshift(i64 %x, i64 %y) {181; CHECK-LABEL: fshl_i64_const_overshift:182; CHECK: @ %bb.0:183; CHECK-NEXT: lsl r1, r3, #9184; CHECK-NEXT: orr r2, r1, r2, lsr #23185; CHECK-NEXT: lsl r0, r0, #9186; CHECK-NEXT: orr r1, r0, r3, lsr #23187; CHECK-NEXT: mov r0, r2188; CHECK-NEXT: bx lr189 %f = call i64 @llvm.fshl.i64(i64 %x, i64 %y, i64 105)190 ret i64 %f191}192 193; This should work without any node-specific logic.194 195define i8 @fshl_i8_const_fold() {196; CHECK-LABEL: fshl_i8_const_fold:197; CHECK: @ %bb.0:198; CHECK-NEXT: mov r0, #128199; CHECK-NEXT: bx lr200 %f = call i8 @llvm.fshl.i8(i8 255, i8 0, i8 7)201 ret i8 %f202}203 204; Repeat everything for funnel shift right.205 206; General case - all operands can be variables.207 208define i16 @fshr_i16(i16 %x, i16 %y, i16 %z) {209; CHECK-LABEL: fshr_i16:210; CHECK: @ %bb.0:211; CHECK-NEXT: pkhbt r0, r1, r0, lsl #16212; CHECK-NEXT: and r1, r2, #15213; CHECK-NEXT: lsr r0, r0, r1214; CHECK-NEXT: bx lr215 %f = call i16 @llvm.fshr.i16(i16 %x, i16 %y, i16 %z)216 ret i16 %f217}218 219define i32 @fshr_i32(i32 %x, i32 %y, i32 %z) {220; CHECK-LABEL: fshr_i32:221; CHECK: @ %bb.0:222; CHECK-NEXT: mov r3, #31223; CHECK-NEXT: lsl r0, r0, #1224; CHECK-NEXT: bic r3, r3, r2225; CHECK-NEXT: and r2, r2, #31226; CHECK-NEXT: lsl r0, r0, r3227; CHECK-NEXT: orr r0, r0, r1, lsr r2228; CHECK-NEXT: bx lr229 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %z)230 ret i32 %f231}232 233; Verify that weird types are minimally supported.234declare i37 @llvm.fshr.i37(i37, i37, i37)235define i37 @fshr_i37(i37 %x, i37 %y, i37 %z) {236; SCALAR-LABEL: fshr_i37:237; SCALAR: @ %bb.0:238; SCALAR-NEXT: .save {r4, r5, r6, r7, r11, lr}239; SCALAR-NEXT: push {r4, r5, r6, r7, r11, lr}240; SCALAR-NEXT: mov r5, r0241; SCALAR-NEXT: ldr r0, [sp, #28]242; SCALAR-NEXT: mov r4, r1243; SCALAR-NEXT: mov r6, r3244; SCALAR-NEXT: and r1, r0, #31245; SCALAR-NEXT: ldr r0, [sp, #24]246; SCALAR-NEXT: mov r7, r2247; SCALAR-NEXT: mov r2, #37248; SCALAR-NEXT: mov r3, #0249; SCALAR-NEXT: bl __aeabi_uldivmod250; SCALAR-NEXT: add r0, r2, #27251; SCALAR-NEXT: lsl r2, r6, #27252; SCALAR-NEXT: orr r2, r2, r7, lsr #5253; SCALAR-NEXT: mov r1, #31254; SCALAR-NEXT: tst r0, #32255; SCALAR-NEXT: mov r3, r5256; SCALAR-NEXT: moveq r3, r2257; SCALAR-NEXT: lsleq r2, r7, #27258; SCALAR-NEXT: bic r1, r1, r0259; SCALAR-NEXT: and r7, r0, #31260; SCALAR-NEXT: lsl r6, r3, #1261; SCALAR-NEXT: moveq r4, r5262; SCALAR-NEXT: lsl r6, r6, r1263; SCALAR-NEXT: orr r0, r6, r2, lsr r7264; SCALAR-NEXT: lsl r2, r4, #1265; SCALAR-NEXT: lsl r1, r2, r1266; SCALAR-NEXT: orr r1, r1, r3, lsr r7267; SCALAR-NEXT: pop {r4, r5, r6, r7, r11, pc}268;269; NEON-LABEL: fshr_i37:270; NEON: @ %bb.0:271; NEON-NEXT: .save {r4, r5, r6, r7, r11, lr}272; NEON-NEXT: push {r4, r5, r6, r7, r11, lr}273; NEON-NEXT: mov r4, r1274; NEON-NEXT: ldr r1, [sp, #28]275; NEON-NEXT: mov r5, r0276; NEON-NEXT: ldr r0, [sp, #24]277; NEON-NEXT: and r1, r1, #31278; NEON-NEXT: mov r6, r3279; NEON-NEXT: mov r7, r2280; NEON-NEXT: mov r2, #37281; NEON-NEXT: mov r3, #0282; NEON-NEXT: bl __aeabi_uldivmod283; NEON-NEXT: add r0, r2, #27284; NEON-NEXT: lsl r2, r6, #27285; NEON-NEXT: orr r2, r2, r7, lsr #5286; NEON-NEXT: mov r1, #31287; NEON-NEXT: tst r0, #32288; NEON-NEXT: mov r3, r5289; NEON-NEXT: moveq r3, r2290; NEON-NEXT: lsleq r2, r7, #27291; NEON-NEXT: bic r1, r1, r0292; NEON-NEXT: and r7, r0, #31293; NEON-NEXT: lsl r6, r3, #1294; NEON-NEXT: moveq r4, r5295; NEON-NEXT: lsl r6, r6, r1296; NEON-NEXT: orr r0, r6, r2, lsr r7297; NEON-NEXT: lsl r2, r4, #1298; NEON-NEXT: lsl r1, r2, r1299; NEON-NEXT: orr r1, r1, r3, lsr r7300; NEON-NEXT: pop {r4, r5, r6, r7, r11, pc}301 %f = call i37 @llvm.fshr.i37(i37 %x, i37 %y, i37 %z)302 ret i37 %f303}304 305; extract(concat(0b1110000, 0b1111111) >> 2) = 0b0011111306 307declare i7 @llvm.fshr.i7(i7, i7, i7)308define i7 @fshr_i7_const_fold() {309; CHECK-LABEL: fshr_i7_const_fold:310; CHECK: @ %bb.0:311; CHECK-NEXT: mov r0, #31312; CHECK-NEXT: bx lr313 %f = call i7 @llvm.fshr.i7(i7 112, i7 127, i7 2)314 ret i7 %f315}316 317define i8 @fshr_i8_const_fold_overshift_1() {318; CHECK-LABEL: fshr_i8_const_fold_overshift_1:319; CHECK: @ %bb.0:320; CHECK-NEXT: mov r0, #254321; CHECK-NEXT: bx lr322 %f = call i8 @llvm.fshr.i8(i8 255, i8 0, i8 15)323 ret i8 %f324}325 326define i8 @fshr_i8_const_fold_overshift_2() {327; CHECK-LABEL: fshr_i8_const_fold_overshift_2:328; CHECK: @ %bb.0:329; CHECK-NEXT: mov r0, #225330; CHECK-NEXT: bx lr331 %f = call i8 @llvm.fshr.i8(i8 15, i8 15, i8 11)332 ret i8 %f333}334 335define i8 @fshr_i8_const_fold_overshift_3() {336; CHECK-LABEL: fshr_i8_const_fold_overshift_3:337; CHECK: @ %bb.0:338; CHECK-NEXT: mov r0, #255339; CHECK-NEXT: bx lr340 %f = call i8 @llvm.fshr.i8(i8 0, i8 255, i8 8)341 ret i8 %f342}343 344; With constant shift amount, this is 'extr'.345 346define i32 @fshr_i32_const_shift(i32 %x, i32 %y) {347; CHECK-LABEL: fshr_i32_const_shift:348; CHECK: @ %bb.0:349; CHECK-NEXT: lsl r0, r0, #23350; CHECK-NEXT: orr r0, r0, r1, lsr #9351; CHECK-NEXT: bx lr352 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 9)353 ret i32 %f354}355 356; Check modulo math on shift amount. 41-32=9.357 358define i32 @fshr_i32_const_overshift(i32 %x, i32 %y) {359; CHECK-LABEL: fshr_i32_const_overshift:360; CHECK: @ %bb.0:361; CHECK-NEXT: lsl r0, r0, #23362; CHECK-NEXT: orr r0, r0, r1, lsr #9363; CHECK-NEXT: bx lr364 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 41)365 ret i32 %f366}367 368; 64-bit should also work. 105-64 = 41.369 370define i64 @fshr_i64_const_overshift(i64 %x, i64 %y) {371; CHECK-LABEL: fshr_i64_const_overshift:372; CHECK: @ %bb.0:373; CHECK-NEXT: lsl r2, r0, #23374; CHECK-NEXT: lsl r1, r1, #23375; CHECK-NEXT: orr r2, r2, r3, lsr #9376; CHECK-NEXT: orr r1, r1, r0, lsr #9377; CHECK-NEXT: mov r0, r2378; CHECK-NEXT: bx lr379 %f = call i64 @llvm.fshr.i64(i64 %x, i64 %y, i64 105)380 ret i64 %f381}382 383; This should work without any node-specific logic.384 385define i8 @fshr_i8_const_fold() {386; CHECK-LABEL: fshr_i8_const_fold:387; CHECK: @ %bb.0:388; CHECK-NEXT: mov r0, #254389; CHECK-NEXT: bx lr390 %f = call i8 @llvm.fshr.i8(i8 255, i8 0, i8 7)391 ret i8 %f392}393 394define i32 @fshl_i32_shift_by_bitwidth(i32 %x, i32 %y) {395; CHECK-LABEL: fshl_i32_shift_by_bitwidth:396; CHECK: @ %bb.0:397; CHECK-NEXT: bx lr398 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 32)399 ret i32 %f400}401 402define i32 @fshr_i32_shift_by_bitwidth(i32 %x, i32 %y) {403; CHECK-LABEL: fshr_i32_shift_by_bitwidth:404; CHECK: @ %bb.0:405; CHECK-NEXT: mov r0, r1406; CHECK-NEXT: bx lr407 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 32)408 ret i32 %f409}410 411define <4 x i32> @fshl_v4i32_shift_by_bitwidth(<4 x i32> %x, <4 x i32> %y) {412; CHECK-LABEL: fshl_v4i32_shift_by_bitwidth:413; CHECK: @ %bb.0:414; CHECK-NEXT: bx lr415 %f = call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 32, i32 32, i32 32, i32 32>)416 ret <4 x i32> %f417}418 419define <4 x i32> @fshr_v4i32_shift_by_bitwidth(<4 x i32> %x, <4 x i32> %y) {420; SCALAR-LABEL: fshr_v4i32_shift_by_bitwidth:421; SCALAR: @ %bb.0:422; SCALAR-NEXT: ldm sp, {r0, r1, r2, r3}423; SCALAR-NEXT: bx lr424;425; NEON-LABEL: fshr_v4i32_shift_by_bitwidth:426; NEON: @ %bb.0:427; NEON-NEXT: mov r0, sp428; NEON-NEXT: vld1.64 {d16, d17}, [r0]429; NEON-NEXT: vmov r0, r1, d16430; NEON-NEXT: vmov r2, r3, d17431; NEON-NEXT: bx lr432 %f = call <4 x i32> @llvm.fshr.v4i32(<4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 32, i32 32, i32 32, i32 32>)433 ret <4 x i32> %f434}435 436