321 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; When first 2 operands match, it's a rotate.18 19define i8 @rotl_i8_const_shift(i8 %x) {20; CHECK-LABEL: rotl_i8_const_shift:21; CHECK: @ %bb.0:22; CHECK-NEXT: uxtb r1, r023; CHECK-NEXT: lsl r0, r0, #324; CHECK-NEXT: orr r0, r0, r1, lsr #525; CHECK-NEXT: bx lr26 %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 3)27 ret i8 %f28}29 30define i64 @rotl_i64_const_shift(i64 %x) {31; CHECK-LABEL: rotl_i64_const_shift:32; CHECK: @ %bb.0:33; CHECK-NEXT: lsl r2, r0, #334; CHECK-NEXT: orr r2, r2, r1, lsr #2935; CHECK-NEXT: lsl r1, r1, #336; CHECK-NEXT: orr r1, r1, r0, lsr #2937; CHECK-NEXT: mov r0, r238; CHECK-NEXT: bx lr39 %f = call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 3)40 ret i64 %f41}42 43; When first 2 operands match, it's a rotate (by variable amount).44 45define i16 @rotl_i16(i16 %x, i16 %z) {46; CHECK-LABEL: rotl_i16:47; CHECK: @ %bb.0:48; CHECK-NEXT: and r2, r1, #1549; CHECK-NEXT: rsb r1, r1, #050; CHECK-NEXT: and r1, r1, #1551; CHECK-NEXT: lsl r2, r0, r252; CHECK-NEXT: uxth r0, r053; CHECK-NEXT: orr r0, r2, r0, lsr r154; CHECK-NEXT: bx lr55 %f = call i16 @llvm.fshl.i16(i16 %x, i16 %x, i16 %z)56 ret i16 %f57}58 59define i32 @rotl_i32(i32 %x, i32 %z) {60; CHECK-LABEL: rotl_i32:61; CHECK: @ %bb.0:62; CHECK-NEXT: rsb r1, r1, #063; CHECK-NEXT: ror r0, r0, r164; CHECK-NEXT: bx lr65 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %z)66 ret i32 %f67}68 69define i64 @rotl_i64(i64 %x, i64 %z) {70; CHECK-LABEL: rotl_i64:71; CHECK: @ %bb.0:72; CHECK-NEXT: .save {r4, lr}73; CHECK-NEXT: push {r4, lr}74; CHECK-NEXT: tst r2, #3275; CHECK-NEXT: mov r3, r076; CHECK-NEXT: and r12, r2, #3177; CHECK-NEXT: movne r3, r178; CHECK-NEXT: movne r1, r079; CHECK-NEXT: mov r4, #3180; CHECK-NEXT: bic r2, r4, r281; CHECK-NEXT: lsl lr, r3, r1282; CHECK-NEXT: lsr r0, r1, #183; CHECK-NEXT: lsl r1, r1, r1284; CHECK-NEXT: lsr r3, r3, #185; CHECK-NEXT: orr r0, lr, r0, lsr r286; CHECK-NEXT: orr r1, r1, r3, lsr r287; CHECK-NEXT: pop {r4, pc}88 %f = call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %z)89 ret i64 %f90}91 92; Vector rotate.93 94define <4 x i32> @rotl_v4i32(<4 x i32> %x, <4 x i32> %z) {95; SCALAR-LABEL: rotl_v4i32:96; SCALAR: @ %bb.0:97; SCALAR-NEXT: ldr r12, [sp]98; SCALAR-NEXT: rsb r12, r12, #099; SCALAR-NEXT: ror r0, r0, r12100; SCALAR-NEXT: ldr r12, [sp, #4]101; SCALAR-NEXT: rsb r12, r12, #0102; SCALAR-NEXT: ror r1, r1, r12103; SCALAR-NEXT: ldr r12, [sp, #8]104; SCALAR-NEXT: rsb r12, r12, #0105; SCALAR-NEXT: ror r2, r2, r12106; SCALAR-NEXT: ldr r12, [sp, #12]107; SCALAR-NEXT: rsb r12, r12, #0108; SCALAR-NEXT: ror r3, r3, r12109; SCALAR-NEXT: bx lr110;111; NEON-LABEL: rotl_v4i32:112; NEON: @ %bb.0:113; NEON-NEXT: mov r12, sp114; NEON-NEXT: vld1.64 {d16, d17}, [r12]115; NEON-NEXT: vmov.i32 q10, #0x1f116; NEON-NEXT: vneg.s32 q9, q8117; NEON-NEXT: vmov d23, r2, r3118; NEON-NEXT: vand q9, q9, q10119; NEON-NEXT: vand q8, q8, q10120; NEON-NEXT: vmov d22, r0, r1121; NEON-NEXT: vneg.s32 q9, q9122; NEON-NEXT: vshl.u32 q8, q11, q8123; NEON-NEXT: vshl.u32 q9, q11, q9124; NEON-NEXT: vorr q8, q8, q9125; NEON-NEXT: vmov r0, r1, d16126; NEON-NEXT: vmov r2, r3, d17127; NEON-NEXT: bx lr128 %f = call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %x, <4 x i32> %x, <4 x i32> %z)129 ret <4 x i32> %f130}131 132; Vector rotate by constant splat amount.133 134define <4 x i32> @rotl_v4i32_rotl_const_shift(<4 x i32> %x) {135; SCALAR-LABEL: rotl_v4i32_rotl_const_shift:136; SCALAR: @ %bb.0:137; SCALAR-NEXT: ror r0, r0, #29138; SCALAR-NEXT: ror r1, r1, #29139; SCALAR-NEXT: ror r2, r2, #29140; SCALAR-NEXT: ror r3, r3, #29141; SCALAR-NEXT: bx lr142;143; NEON-LABEL: rotl_v4i32_rotl_const_shift:144; NEON: @ %bb.0:145; NEON-NEXT: vmov d17, r2, r3146; NEON-NEXT: vmov d16, r0, r1147; NEON-NEXT: vshr.u32 q9, q8, #29148; NEON-NEXT: vshl.i32 q8, q8, #3149; NEON-NEXT: vorr q8, q8, q9150; NEON-NEXT: vmov r0, r1, d16151; NEON-NEXT: vmov r2, r3, d17152; NEON-NEXT: bx lr153 %f = call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %x, <4 x i32> %x, <4 x i32> <i32 3, i32 3, i32 3, i32 3>)154 ret <4 x i32> %f155}156 157; Repeat everything for funnel shift right.158 159; When first 2 operands match, it's a rotate.160 161define i8 @rotr_i8_const_shift(i8 %x) {162; CHECK-LABEL: rotr_i8_const_shift:163; CHECK: @ %bb.0:164; CHECK-NEXT: uxtb r1, r0165; CHECK-NEXT: lsr r1, r1, #3166; CHECK-NEXT: orr r0, r1, r0, lsl #5167; CHECK-NEXT: bx lr168 %f = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 3)169 ret i8 %f170}171 172define i32 @rotr_i32_const_shift(i32 %x) {173; CHECK-LABEL: rotr_i32_const_shift:174; CHECK: @ %bb.0:175; CHECK-NEXT: ror r0, r0, #3176; CHECK-NEXT: bx lr177 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 3)178 ret i32 %f179}180 181; When first 2 operands match, it's a rotate (by variable amount).182 183define i16 @rotr_i16(i16 %x, i16 %z) {184; CHECK-LABEL: rotr_i16:185; CHECK: @ %bb.0:186; CHECK-NEXT: and r2, r1, #15187; CHECK-NEXT: rsb r1, r1, #0188; CHECK-NEXT: and r1, r1, #15189; CHECK-NEXT: uxth r3, r0190; CHECK-NEXT: lsr r2, r3, r2191; CHECK-NEXT: orr r0, r2, r0, lsl r1192; CHECK-NEXT: bx lr193 %f = call i16 @llvm.fshr.i16(i16 %x, i16 %x, i16 %z)194 ret i16 %f195}196 197define i32 @rotr_i32(i32 %x, i32 %z) {198; CHECK-LABEL: rotr_i32:199; CHECK: @ %bb.0:200; CHECK-NEXT: ror r0, r0, r1201; CHECK-NEXT: bx lr202 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 %z)203 ret i32 %f204}205 206define i64 @rotr_i64(i64 %x, i64 %z) {207; CHECK-LABEL: rotr_i64:208; CHECK: @ %bb.0:209; CHECK-NEXT: tst r2, #32210; CHECK-NEXT: mov r3, r1211; CHECK-NEXT: moveq r3, r0212; CHECK-NEXT: moveq r0, r1213; CHECK-NEXT: mov r1, #31214; CHECK-NEXT: lsl r12, r0, #1215; CHECK-NEXT: bic r1, r1, r2216; CHECK-NEXT: and r2, r2, #31217; CHECK-NEXT: lsl r12, r12, r1218; CHECK-NEXT: orr r12, r12, r3, lsr r2219; CHECK-NEXT: lsl r3, r3, #1220; CHECK-NEXT: lsl r1, r3, r1221; CHECK-NEXT: orr r1, r1, r0, lsr r2222; CHECK-NEXT: mov r0, r12223; CHECK-NEXT: bx lr224 %f = call i64 @llvm.fshr.i64(i64 %x, i64 %x, i64 %z)225 ret i64 %f226}227 228; Vector rotate.229 230define <4 x i32> @rotr_v4i32(<4 x i32> %x, <4 x i32> %z) {231; SCALAR-LABEL: rotr_v4i32:232; SCALAR: @ %bb.0:233; SCALAR-NEXT: ldr r12, [sp]234; SCALAR-NEXT: ror r0, r0, r12235; SCALAR-NEXT: ldr r12, [sp, #4]236; SCALAR-NEXT: ror r1, r1, r12237; SCALAR-NEXT: ldr r12, [sp, #8]238; SCALAR-NEXT: ror r2, r2, r12239; SCALAR-NEXT: ldr r12, [sp, #12]240; SCALAR-NEXT: ror r3, r3, r12241; SCALAR-NEXT: bx lr242;243; NEON-LABEL: rotr_v4i32:244; NEON: @ %bb.0:245; NEON-NEXT: mov r12, sp246; NEON-NEXT: vld1.64 {d16, d17}, [r12]247; NEON-NEXT: vmov.i32 q9, #0x1f248; NEON-NEXT: vneg.s32 q10, q8249; NEON-NEXT: vand q8, q8, q9250; NEON-NEXT: vmov d23, r2, r3251; NEON-NEXT: vand q9, q10, q9252; NEON-NEXT: vneg.s32 q8, q8253; NEON-NEXT: vmov d22, r0, r1254; NEON-NEXT: vshl.u32 q9, q11, q9255; NEON-NEXT: vshl.u32 q8, q11, q8256; NEON-NEXT: vorr q8, q8, q9257; NEON-NEXT: vmov r0, r1, d16258; NEON-NEXT: vmov r2, r3, d17259; NEON-NEXT: bx lr260 %f = call <4 x i32> @llvm.fshr.v4i32(<4 x i32> %x, <4 x i32> %x, <4 x i32> %z)261 ret <4 x i32> %f262}263 264; Vector rotate by constant splat amount.265 266define <4 x i32> @rotr_v4i32_const_shift(<4 x i32> %x) {267; SCALAR-LABEL: rotr_v4i32_const_shift:268; SCALAR: @ %bb.0:269; SCALAR-NEXT: ror r0, r0, #3270; SCALAR-NEXT: ror r1, r1, #3271; SCALAR-NEXT: ror r2, r2, #3272; SCALAR-NEXT: ror r3, r3, #3273; SCALAR-NEXT: bx lr274;275; NEON-LABEL: rotr_v4i32_const_shift:276; NEON: @ %bb.0:277; NEON-NEXT: vmov d17, r2, r3278; NEON-NEXT: vmov d16, r0, r1279; NEON-NEXT: vshl.i32 q9, q8, #29280; NEON-NEXT: vshr.u32 q8, q8, #3281; NEON-NEXT: vorr q8, q8, q9282; NEON-NEXT: vmov r0, r1, d16283; NEON-NEXT: vmov r2, r3, d17284; NEON-NEXT: bx lr285 %f = call <4 x i32> @llvm.fshr.v4i32(<4 x i32> %x, <4 x i32> %x, <4 x i32> <i32 3, i32 3, i32 3, i32 3>)286 ret <4 x i32> %f287}288 289define i32 @rotl_i32_shift_by_bitwidth(i32 %x) {290; CHECK-LABEL: rotl_i32_shift_by_bitwidth:291; CHECK: @ %bb.0:292; CHECK-NEXT: bx lr293 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 32)294 ret i32 %f295}296 297define i32 @rotr_i32_shift_by_bitwidth(i32 %x) {298; CHECK-LABEL: rotr_i32_shift_by_bitwidth:299; CHECK: @ %bb.0:300; CHECK-NEXT: bx lr301 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 32)302 ret i32 %f303}304 305define <4 x i32> @rotl_v4i32_shift_by_bitwidth(<4 x i32> %x) {306; CHECK-LABEL: rotl_v4i32_shift_by_bitwidth:307; CHECK: @ %bb.0:308; CHECK-NEXT: bx lr309 %f = call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %x, <4 x i32> %x, <4 x i32> <i32 32, i32 32, i32 32, i32 32>)310 ret <4 x i32> %f311}312 313define <4 x i32> @rotr_v4i32_shift_by_bitwidth(<4 x i32> %x) {314; CHECK-LABEL: rotr_v4i32_shift_by_bitwidth:315; CHECK: @ %bb.0:316; CHECK-NEXT: bx lr317 %f = call <4 x i32> @llvm.fshr.v4i32(<4 x i32> %x, <4 x i32> %x, <4 x i32> <i32 32, i32 32, i32 32, i32 32>)318 ret <4 x i32> %f319}320 321