Added patterns so that both SSAT and USAT instructions are generated with shifts. Added corresponding regression tests.
Differential Review: https://reviews.llvm.org/D85120
return CurDAG->getTargetConstant(~(int)N->getZExtValue(), SDLoc(N), MVT::i32);
}]>;
+// asr_imm_XFORM - Returns a shift immediate with bit {5} set to 1
+def asr_imm_XFORM : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(0x20 | N->getZExtValue(), SDLoc(N), MVT:: i32);
+}]>;
+
/// imm16_31 predicate - True if the 32-bit immediate is in the range [16,31].
def imm16_31 : ImmLeaf<i32, [{
return (int32_t)Imm >= 16 && (int32_t)Imm < 32;
def imm_even : ImmLeaf<i32, [{ return (Imm & 1) == 0; }]>;
def imm_odd : ImmLeaf<i32, [{ return (Imm & 1) == 1; }]>;
+def asr_imm : ImmLeaf<i32, [{ return Imm > 0 && Imm <= 32; }], asr_imm_XFORM>;
+
//===----------------------------------------------------------------------===//
// NEON/MVE pattern fragments
//
(SSAT16 imm1_16:$pos, GPRnopc:$a)>;
def : ARMV6Pat<(int_arm_usat16 GPRnopc:$a, imm0_15:$pos),
(USAT16 imm0_15:$pos, GPRnopc:$a)>;
+def : ARMV6Pat<(int_arm_ssat (shl GPRnopc:$a, imm0_31:$shft), imm1_32:$pos),
+ (SSAT imm1_32:$pos, GPRnopc:$a, imm0_31:$shft)>;
+def : ARMV6Pat<(int_arm_ssat (sra GPRnopc:$a, asr_imm:$shft), imm1_32:$pos),
+ (SSAT imm1_32:$pos, GPRnopc:$a, asr_imm:$shft)>;
+def : ARMV6Pat<(int_arm_usat (shl GPRnopc:$a, imm0_31:$shft), imm0_31:$pos),
+ (USAT imm0_31:$pos, GPRnopc:$a, imm0_31:$shft)>;
+def : ARMV6Pat<(int_arm_usat (sra GPRnopc:$a, asr_imm:$shft), imm0_31:$pos),
+ (USAT imm0_31:$pos, GPRnopc:$a, asr_imm:$shft)>;
+
//===----------------------------------------------------------------------===//
// Bitwise Instructions.
(t2SSAT16 imm1_16:$pos, GPR:$a)>;
def : T2Pat<(int_arm_usat16 GPR:$a, imm0_15:$pos),
(t2USAT16 imm0_15:$pos, GPR:$a)>;
+def : T2Pat<(int_arm_ssat (shl GPRnopc:$a, imm0_31:$shft), imm1_32:$pos),
+ (t2SSAT imm1_32:$pos, GPRnopc:$a, imm0_31:$shft)>;
+def : T2Pat<(int_arm_ssat (sra GPRnopc:$a, asr_imm:$shft), imm1_32:$pos),
+ (t2SSAT imm1_32:$pos, GPRnopc:$a, asr_imm:$shft)>;
+def : T2Pat<(int_arm_usat (shl GPRnopc:$a, imm0_31:$shft), imm0_31:$pos),
+ (t2USAT imm0_31:$pos, GPRnopc:$a, imm0_31:$shft)>;
+def : T2Pat<(int_arm_usat (sra GPRnopc:$a, asr_imm:$shft), imm0_31:$pos),
+ (t2USAT imm0_31:$pos, GPRnopc:$a, asr_imm:$shft)>;
+
//===----------------------------------------------------------------------===//
// Shift and rotate Instructions.
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=armv6-eabi %s -o - | FileCheck %s
+; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+dsp %s -o - | FileCheck %s
+
+define arm_aapcs_vfpcc i32 @ssat_lsl(i32 %num){
+; CHECK-LABEL: ssat_lsl
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: ssat r0, #8, r0, lsl #7
+; CHECK-NEXT: bx lr
+entry:
+ %shl = shl i32 %num, 7
+ %0 = tail call i32 @llvm.arm.ssat(i32 %shl, i32 8)
+ ret i32 %0
+}
+
+define arm_aapcs_vfpcc i32 @ssat_asr(i32 %num){
+; CHECK-LABEL: ssat_asr
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: ssat r0, #8, r0, asr #7
+; CHECK-NEXT: bx lr
+entry:
+ %shr = ashr i32 %num, 7
+ %0 = tail call i32 @llvm.arm.ssat(i32 %shr, i32 8)
+ ret i32 %0
+}
+
+declare i32 @llvm.arm.ssat(i32, i32)
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=armv6-eabi %s -o - | FileCheck %s
+; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+dsp %s -o - | FileCheck %s
+
+define arm_aapcs_vfpcc i32 @usat_lsl(i32 %num){
+; CHECK-LABEL: usat_lsl
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: usat r0, #7, r0, lsl #2
+; CHECK-NEXT: bx lr
+entry:
+ %shl = shl i32 %num, 2
+ %0 = tail call i32 @llvm.arm.usat(i32 %shl, i32 7)
+ ret i32 %0
+}
+
+define arm_aapcs_vfpcc i32 @usat_asr(i32 %num){
+; CHECK-LABEL: usat_asr
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: usat r0, #7, r0, asr #2
+; CHECK-NEXT: bx lr
+entry:
+ %shr = ashr i32 %num, 2
+ %0 = tail call i32 @llvm.arm.usat(i32 %shr, i32 7)
+ ret i32 %0
+}
+
+declare i32 @llvm.arm.usat(i32, i32)