Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -455,6 +455,10 @@ /// Delete \p MI and replace all of its uses with \p Replacement. void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement); + /// @brief Replaces the shift amount in \p MI with ShiftAmt % BW + /// @param MI + void applyFunnelShiftConstantModulo(MachineInstr &MI); + /// Return true if \p MOP1 and \p MOP2 are register operands are defined by /// equivalent instructions. bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2); @@ -463,6 +467,10 @@ /// \p C. bool matchConstantOp(const MachineOperand &MOP, int64_t C); + /// @brief Checks if constant at \p ConstIdx is larger than \p MI 's bitwidth + /// @param ConstIdx Index of the constant + bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx); + /// Optimize (cond ? x : x) -> x bool matchSelectSameVal(MachineInstr &MI); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -803,6 +803,28 @@ (apply [{ Helper.applyFunnelShiftToRotate(*${root}); }]) >; +// Fold fshr x, y, 0 -> y +def funnel_shift_right_zero: GICombineRule< + (defs root:$root), + (match (G_FSHR $dst, $src1, $src2, 0):$root), + (apply (COPY $dst, $src2)) +>; + +// Fold fshl x, y, 0 -> x +def funnel_shift_left_zero: GICombineRule< + (defs root:$root), + (match (G_FSHL $dst, $src1, $src2, 0):$root), + (apply (COPY $dst, $src1)) +>; + +// Fold fsh(l/r) x, y, C -> fsh(l/r) x, y, C % bw +def funnel_shift_overshift: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_FSHL, G_FSHR):$root, + [{ return Helper.matchConstantLargerBitWidth(*${root}, 3); }]), + (apply [{ Helper.applyFunnelShiftConstantModulo(*${root}); }]) +>; + def rotate_out_of_range : GICombineRule< (defs root:$root), (match (wip_match_opcode G_ROTR, G_ROTL):$root, @@ -841,7 +863,10 @@ (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; def funnel_shift_combines : GICombineGroup<[funnel_shift_from_or_shift, - funnel_shift_to_rotate]>; + funnel_shift_to_rotate, + funnel_shift_right_zero, + funnel_shift_left_zero, + funnel_shift_overshift]>; def bitfield_extract_from_sext_inreg : GICombineRule< (defs root:$root, build_fn_matchinfo:$info), Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -2599,6 +2599,47 @@ replaceRegWith(MRI, OldReg, Replacement); } +bool CombinerHelper::matchConstantLargerBitWidth(MachineInstr &MI, + unsigned ConstIdx) { + Register ConstReg = MI.getOperand(ConstIdx).getReg(); + LLT ConstTy = MRI.getType(ConstReg); + LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); + + // Get the shift amount + auto VRegAndVal = getIConstantVRegValWithLookThrough(ConstReg, MRI); + if (!VRegAndVal) + return false; + + // Return true of shift amount >= Bitwidth + APInt BitWidth(ConstTy.getSizeInBits(), DstTy.getSizeInBits(), false); + return (VRegAndVal->Value.uge(BitWidth)); +} + +void CombinerHelper::applyFunnelShiftConstantModulo(MachineInstr &MI) { + assert((MI.getOpcode() == TargetOpcode::G_FSHL || + MI.getOpcode() == TargetOpcode::G_FSHR) && + "This is not a funnel shift operation"); + + Register ConstReg = MI.getOperand(3).getReg(); + LLT ConstTy = MRI.getType(ConstReg); + LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); + + auto VRegAndVal = getIConstantVRegValWithLookThrough(ConstReg, MRI); + assert((VRegAndVal) && "Value is not a constant"); + + // Calculate the new Shift Amount = Old Shift Amount % BitWidth + APInt NewConst = VRegAndVal->Value.urem( + APInt(ConstTy.getSizeInBits(), DstTy.getScalarSizeInBits())); + + Builder.setInstrAndDebugLoc(MI); + auto NewConstInstr = Builder.buildConstant(ConstTy, NewConst.getZExtValue()); + Builder.buildInstr( + MI.getOpcode(), {MI.getOperand(0)}, + {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)}); + + MI.eraseFromParent(); +} + bool CombinerHelper::matchSelectSameVal(MachineInstr &MI) { assert(MI.getOpcode() == TargetOpcode::G_SELECT); // Match (cond ? x : x) Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-fshl.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fshl.mir @@ -0,0 +1,452 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 2 +# RUN: llc -O0 -mtriple=arm64-unknown-unknown -global-isel -run-pass=aarch64-prelegalizer-combiner -global-isel-abort=1 %s -o - | FileCheck %s + +--- +name: fshl_i8 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1, $w2 + + ; CHECK-LABEL: name: fshl_i8 + ; CHECK: liveins: $w0, $w1, $w2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[TRUNC2:%[0-9]+]]:_(s8) = G_TRUNC [[COPY2]](s32) + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s8) = G_FSHL [[TRUNC]], [[TRUNC1]], [[TRUNC2]](s8) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHL]](s8) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %3:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %3(s32) + %4:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %4(s32) + %5:_(s32) = COPY $w2 + %2:_(s8) = G_TRUNC %5(s32) + %6:_(s8) = G_FSHL %0, %1, %2(s8) + %7:_(s32) = G_ANYEXT %6(s8) + $w0 = COPY %7(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i16 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1, $w2 + + ; CHECK-LABEL: name: fshl_i16 + ; CHECK: liveins: $w0, $w1, $w2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32) + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s16) = G_FSHL [[TRUNC]], [[TRUNC1]], [[TRUNC2]](s16) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHL]](s16) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %3:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %3(s32) + %4:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %4(s32) + %5:_(s32) = COPY $w2 + %2:_(s16) = G_TRUNC %5(s32) + %6:_(s16) = G_FSHL %0, %1, %2(s16) + %7:_(s32) = G_ANYEXT %6(s16) + $w0 = COPY %7(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i32 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1, $w2 + + ; CHECK-LABEL: name: fshl_i32 + ; CHECK: liveins: $w0, $w1, $w2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s32) = G_FSHL [[COPY]], [[COPY1]], [[COPY2]](s32) + ; CHECK-NEXT: $w0 = COPY [[FSHL]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = COPY $w2 + %3:_(s32) = G_FSHL %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i64 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1, $x2 + + ; CHECK-LABEL: name: fshl_i64 + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s64) = G_FSHL [[COPY]], [[COPY1]], [[COPY2]](s64) + ; CHECK-NEXT: $x0 = COPY [[FSHL]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %3:_(s64) = G_FSHL %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... + +--- +name: fshl_i8_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i8_const_shift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 5 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s8) = G_FSHL [[TRUNC]], [[TRUNC1]], [[C]](s8) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHL]](s8) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_CONSTANT i8 5 + %5:_(s8) = G_FSHL %0, %1, %4(s8) + %6:_(s32) = G_ANYEXT %5(s8) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i8_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i8_const_overshift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 2 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s8) = G_FSHL [[TRUNC]], [[TRUNC1]], [[C]](s8) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHL]](s8) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_CONSTANT i8 10 + %5:_(s8) = G_FSHL %0, %1, %4(s8) + %6:_(s32) = G_ANYEXT %5(s8) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i8_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i8_shift_by_bidwidth + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_CONSTANT i8 8 + %5:_(s8) = G_FSHL %0, %1, %4(s8) + %6:_(s32) = G_ANYEXT %5(s8) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i16_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i16_const_shift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 5 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s16) = G_FSHL [[TRUNC]], [[TRUNC1]], [[C]](s16) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHL]](s16) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_CONSTANT i16 5 + %5:_(s16) = G_FSHL %0, %1, %4(s16) + %6:_(s32) = G_ANYEXT %5(s16) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i16_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i16_const_overshift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 4 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s16) = G_FSHL [[TRUNC]], [[TRUNC1]], [[C]](s16) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHL]](s16) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_CONSTANT i16 20 + %5:_(s16) = G_FSHL %0, %1, %4(s16) + %6:_(s32) = G_ANYEXT %5(s16) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i16_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i16_shift_by_bidwidth + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_CONSTANT i16 16 + %5:_(s16) = G_FSHL %0, %1, %4(s16) + %6:_(s32) = G_ANYEXT %5(s16) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i32_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i32_const_shift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s32) = G_FSHL [[COPY]], [[COPY1]], [[C]](s32) + ; CHECK-NEXT: $w0 = COPY [[FSHL]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_CONSTANT i32 5 + %3:_(s32) = G_FSHL %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i32_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i32_const_overshift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 10 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s32) = G_FSHL [[COPY]], [[COPY1]], [[C]](s32) + ; CHECK-NEXT: $w0 = COPY [[FSHL]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_CONSTANT i32 42 + %3:_(s32) = G_FSHL %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i32_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshl_i32_shift_by_bidwidth + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_CONSTANT i32 32 + %3:_(s32) = G_FSHL %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshl_i64_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: fshl_i64_const_shift + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 5 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s64) = G_FSHL [[COPY]], [[COPY1]], [[C]](s64) + ; CHECK-NEXT: $x0 = COPY [[FSHL]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = G_CONSTANT i64 5 + %3:_(s64) = G_FSHL %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... + +--- +name: fshl_i64_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: fshl_i64_const_overshift + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 + ; CHECK-NEXT: [[FSHL:%[0-9]+]]:_(s64) = G_FSHL [[COPY]], [[COPY1]], [[C]](s64) + ; CHECK-NEXT: $x0 = COPY [[FSHL]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = G_CONSTANT i64 72 + %3:_(s64) = G_FSHL %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... + +--- +name: fshl_i64_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: fshl_i64_shift_by_bidwidth + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: $x0 = COPY [[COPY]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = G_CONSTANT i64 64 + %3:_(s64) = G_FSHL %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-fshr.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fshr.mir @@ -0,0 +1,452 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 2 +# RUN: llc -O0 -mtriple=arm64-unknown-unknown -global-isel -run-pass=aarch64-prelegalizer-combiner -global-isel-abort=1 %s -o - | FileCheck %s + +--- +name: fshr_i8 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1, $w2 + + ; CHECK-LABEL: name: fshr_i8 + ; CHECK: liveins: $w0, $w1, $w2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[TRUNC2:%[0-9]+]]:_(s8) = G_TRUNC [[COPY2]](s32) + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s8) = G_FSHR [[TRUNC]], [[TRUNC1]], [[TRUNC2]](s8) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHR]](s8) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %3:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %3(s32) + %4:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %4(s32) + %5:_(s32) = COPY $w2 + %2:_(s8) = G_TRUNC %5(s32) + %6:_(s8) = G_FSHR %0, %1, %2(s8) + %7:_(s32) = G_ANYEXT %6(s8) + $w0 = COPY %7(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i16 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1, $w2 + + ; CHECK-LABEL: name: fshr_i16 + ; CHECK: liveins: $w0, $w1, $w2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32) + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s16) = G_FSHR [[TRUNC]], [[TRUNC1]], [[TRUNC2]](s16) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHR]](s16) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %3:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %3(s32) + %4:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %4(s32) + %5:_(s32) = COPY $w2 + %2:_(s16) = G_TRUNC %5(s32) + %6:_(s16) = G_FSHR %0, %1, %2(s16) + %7:_(s32) = G_ANYEXT %6(s16) + $w0 = COPY %7(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i32 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1, $w2 + + ; CHECK-LABEL: name: fshr_i32 + ; CHECK: liveins: $w0, $w1, $w2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s32) = G_FSHR [[COPY]], [[COPY1]], [[COPY2]](s32) + ; CHECK-NEXT: $w0 = COPY [[FSHR]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = COPY $w2 + %3:_(s32) = G_FSHR %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i64 +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1, $x2 + + ; CHECK-LABEL: name: fshr_i64 + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s64) = G_FSHR [[COPY]], [[COPY1]], [[COPY2]](s64) + ; CHECK-NEXT: $x0 = COPY [[FSHR]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %3:_(s64) = G_FSHR %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... + +--- +name: fshr_i8_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i8_const_shift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 5 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s8) = G_FSHR [[TRUNC]], [[TRUNC1]], [[C]](s8) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHR]](s8) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_CONSTANT i8 5 + %5:_(s8) = G_FSHR %0, %1, %4(s8) + %6:_(s32) = G_ANYEXT %5(s8) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i8_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i8_const_overshift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 2 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s8) = G_FSHR [[TRUNC]], [[TRUNC1]], [[C]](s8) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHR]](s8) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_CONSTANT i8 10 + %5:_(s8) = G_FSHR %0, %1, %4(s8) + %6:_(s32) = G_ANYEXT %5(s8) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i8_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i8_shift_by_bidwidth + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s8) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %3(s32) + %4:_(s8) = G_CONSTANT i8 8 + %5:_(s8) = G_FSHR %0, %1, %4(s8) + %6:_(s32) = G_ANYEXT %5(s8) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i16_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i16_const_shift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 5 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s16) = G_FSHR [[TRUNC]], [[TRUNC1]], [[C]](s16) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHR]](s16) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_CONSTANT i16 5 + %5:_(s16) = G_FSHR %0, %1, %4(s16) + %6:_(s32) = G_ANYEXT %5(s16) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i16_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i16_const_overshift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32) + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 4 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s16) = G_FSHR [[TRUNC]], [[TRUNC1]], [[C]](s16) + ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FSHR]](s16) + ; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_CONSTANT i16 20 + %5:_(s16) = G_FSHR %0, %1, %4(s16) + %6:_(s32) = G_ANYEXT %5(s16) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i16_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i16_shift_by_bidwidth + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %2:_(s32) = COPY $w0 + %0:_(s16) = G_TRUNC %2(s32) + %3:_(s32) = COPY $w1 + %1:_(s16) = G_TRUNC %3(s32) + %4:_(s16) = G_CONSTANT i16 16 + %5:_(s16) = G_FSHR %0, %1, %4(s16) + %6:_(s32) = G_ANYEXT %5(s16) + $w0 = COPY %6(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i32_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i32_const_shift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s32) = G_FSHR [[COPY]], [[COPY1]], [[C]](s32) + ; CHECK-NEXT: $w0 = COPY [[FSHR]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_CONSTANT i32 5 + %3:_(s32) = G_FSHR %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i32_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i32_const_overshift + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 10 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s32) = G_FSHR [[COPY]], [[COPY1]], [[C]](s32) + ; CHECK-NEXT: $w0 = COPY [[FSHR]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_CONSTANT i32 42 + %3:_(s32) = G_FSHR %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i32_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: fshr_i32_shift_by_bidwidth + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + ; CHECK-NEXT: RET_ReallyLR implicit $w0 + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_CONSTANT i32 32 + %3:_(s32) = G_FSHR %0, %1, %2(s32) + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: fshr_i64_const_shift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: fshr_i64_const_shift + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 5 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s64) = G_FSHR [[COPY]], [[COPY1]], [[C]](s64) + ; CHECK-NEXT: $x0 = COPY [[FSHR]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = G_CONSTANT i64 5 + %3:_(s64) = G_FSHR %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... + +--- +name: fshr_i64_const_overshift +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: fshr_i64_const_overshift + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 + ; CHECK-NEXT: [[FSHR:%[0-9]+]]:_(s64) = G_FSHR [[COPY]], [[COPY1]], [[C]](s64) + ; CHECK-NEXT: $x0 = COPY [[FSHR]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = G_CONSTANT i64 72 + %3:_(s64) = G_FSHR %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... + +--- +name: fshr_i64_shift_by_bidwidth +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: fshr_i64_shift_by_bidwidth + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: $x0 = COPY [[COPY]](s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = G_CONSTANT i64 64 + %3:_(s64) = G_FSHR %0, %1, %2(s64) + $x0 = COPY %3(s64) + RET_ReallyLR implicit $x0 + +... Index: llvm/test/CodeGen/AArch64/funnel-shift.ll =================================================================== --- llvm/test/CodeGen/AArch64/funnel-shift.ll +++ llvm/test/CodeGen/AArch64/funnel-shift.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s +; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s --check-prefixes=CHECK,CHECK-SD +; RUN: llc < %s -mtriple=aarch64-- -global-isel -global-isel-abort=2 | FileCheck %s --check-prefixes=CHECK,CHECK-GI declare i8 @llvm.fshl.i8(i8, i8, i8) declare i16 @llvm.fshl.i16(i16, i16, i16) @@ -17,49 +18,110 @@ ; General case - all operands can be variables. define i32 @fshl_i32(i32 %x, i32 %y, i32 %z) { -; CHECK-LABEL: fshl_i32: -; CHECK: // %bb.0: -; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 -; CHECK-NEXT: mvn w8, w2 -; CHECK-NEXT: lsr w9, w1, #1 -; CHECK-NEXT: lsl w10, w0, w2 -; CHECK-NEXT: lsr w8, w9, w8 -; CHECK-NEXT: orr w0, w10, w8 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshl_i32: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: // kill: def $w2 killed $w2 def $x2 +; CHECK-SD-NEXT: mvn w8, w2 +; CHECK-SD-NEXT: lsr w9, w1, #1 +; CHECK-SD-NEXT: lsl w10, w0, w2 +; CHECK-SD-NEXT: lsr w8, w9, w8 +; CHECK-SD-NEXT: orr w0, w10, w8 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshl_i32: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsr w10, w1, #1 +; CHECK-GI-NEXT: lsl w9, w0, w9 +; CHECK-GI-NEXT: lsr w8, w10, w8 +; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: ret %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %z) ret i32 %f } define i64 @fshl_i64(i64 %x, i64 %y, i64 %z) { -; CHECK-LABEL: fshl_i64: -; CHECK: // %bb.0: -; CHECK-NEXT: mvn w8, w2 -; CHECK-NEXT: lsr x9, x1, #1 -; CHECK-NEXT: lsl x10, x0, x2 -; CHECK-NEXT: lsr x8, x9, x8 -; CHECK-NEXT: orr x0, x10, x8 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshl_i64: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mvn w8, w2 +; CHECK-SD-NEXT: lsr x9, x1, #1 +; CHECK-SD-NEXT: lsl x10, x0, x2 +; CHECK-SD-NEXT: lsr x8, x9, x8 +; CHECK-SD-NEXT: orr x0, x10, x8 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshl_i64: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #63 // =0x3f +; CHECK-GI-NEXT: and x9, x2, #0x3f +; CHECK-GI-NEXT: bic x8, x8, x2 +; CHECK-GI-NEXT: lsr x10, x1, #1 +; CHECK-GI-NEXT: lsl x9, x0, x9 +; CHECK-GI-NEXT: lsr x8, x10, x8 +; CHECK-GI-NEXT: orr x0, x9, x8 +; CHECK-GI-NEXT: ret %f = call i64 @llvm.fshl.i64(i64 %x, i64 %y, i64 %z) ret i64 %f } define i128 @fshl_i128(i128 %x, i128 %y, i128 %z) nounwind { -; CHECK-LABEL: fshl_i128: -; CHECK: // %bb.0: -; CHECK-NEXT: tst x4, #0x40 -; CHECK-NEXT: mvn w8, w4 -; CHECK-NEXT: csel x9, x2, x3, ne -; CHECK-NEXT: csel x10, x3, x0, ne -; CHECK-NEXT: lsr x9, x9, #1 -; CHECK-NEXT: lsl x11, x10, x4 -; CHECK-NEXT: csel x12, x0, x1, ne -; CHECK-NEXT: lsr x10, x10, #1 -; CHECK-NEXT: lsr x9, x9, x8 -; CHECK-NEXT: lsl x12, x12, x4 -; CHECK-NEXT: lsr x8, x10, x8 -; CHECK-NEXT: orr x0, x11, x9 -; CHECK-NEXT: orr x1, x12, x8 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshl_i128: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: tst x4, #0x40 +; CHECK-SD-NEXT: mvn w8, w4 +; CHECK-SD-NEXT: csel x9, x2, x3, ne +; CHECK-SD-NEXT: csel x10, x3, x0, ne +; CHECK-SD-NEXT: lsr x9, x9, #1 +; CHECK-SD-NEXT: lsl x11, x10, x4 +; CHECK-SD-NEXT: csel x12, x0, x1, ne +; CHECK-SD-NEXT: lsr x10, x10, #1 +; CHECK-SD-NEXT: lsr x9, x9, x8 +; CHECK-SD-NEXT: lsl x12, x12, x4 +; CHECK-SD-NEXT: lsr x8, x10, x8 +; CHECK-SD-NEXT: orr x0, x11, x9 +; CHECK-SD-NEXT: orr x1, x12, x8 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshl_i128: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #64 // =0x40 +; CHECK-GI-NEXT: and x9, x4, #0x7f +; CHECK-GI-NEXT: sub x11, x8, x9 +; CHECK-GI-NEXT: sub x13, x9, #64 +; CHECK-GI-NEXT: mov w10, #127 // =0x7f +; CHECK-GI-NEXT: cmp x9, #64 +; CHECK-GI-NEXT: bic x10, x10, x4 +; CHECK-GI-NEXT: lsl x15, x1, x9 +; CHECK-GI-NEXT: lsr x11, x0, x11 +; CHECK-GI-NEXT: lsl x14, x0, x9 +; CHECK-GI-NEXT: orr x11, x11, x15 +; CHECK-GI-NEXT: lsl x9, x0, x13 +; CHECK-GI-NEXT: sub x8, x8, x10 +; CHECK-GI-NEXT: csel x9, x11, x9, lo +; CHECK-GI-NEXT: lsl x11, x3, #63 +; CHECK-GI-NEXT: sub x15, x10, #64 +; CHECK-GI-NEXT: csel x13, x14, xzr, lo +; CHECK-GI-NEXT: orr x11, x11, x2, lsr #1 +; CHECK-GI-NEXT: lsr x14, x3, #1 +; CHECK-GI-NEXT: tst x4, #0x7f +; CHECK-GI-NEXT: lsr x16, x11, x10 +; CHECK-GI-NEXT: lsl x8, x14, x8 +; CHECK-GI-NEXT: mvn x12, x4 +; CHECK-GI-NEXT: csel x9, x1, x9, eq +; CHECK-GI-NEXT: lsr x17, x14, x10 +; CHECK-GI-NEXT: orr x8, x16, x8 +; CHECK-GI-NEXT: lsr x14, x14, x15 +; CHECK-GI-NEXT: cmp x10, #64 +; CHECK-GI-NEXT: csel x8, x8, x14, lo +; CHECK-GI-NEXT: tst x12, #0x7f +; CHECK-GI-NEXT: csel x8, x11, x8, eq +; CHECK-GI-NEXT: cmp x10, #64 +; CHECK-GI-NEXT: csel x10, x17, xzr, lo +; CHECK-GI-NEXT: orr x0, x13, x8 +; CHECK-GI-NEXT: orr x1, x9, x10 +; CHECK-GI-NEXT: ret %f = call i128 @llvm.fshl.i128(i128 %x, i128 %y, i128 %z) ret i128 %f } @@ -67,22 +129,38 @@ ; Verify that weird types are minimally supported. declare i37 @llvm.fshl.i37(i37, i37, i37) define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) { -; CHECK-LABEL: fshl_i37: -; CHECK: // %bb.0: -; CHECK-NEXT: mov x9, #46053 -; CHECK-NEXT: and x8, x2, #0x1fffffffff -; CHECK-NEXT: movk x9, #12398, lsl #16 -; CHECK-NEXT: ubfiz x10, x1, #26, #37 -; CHECK-NEXT: movk x9, #15941, lsl #32 -; CHECK-NEXT: movk x9, #1771, lsl #48 -; CHECK-NEXT: umulh x8, x8, x9 -; CHECK-NEXT: mov w9, #37 -; CHECK-NEXT: msub w8, w8, w9, w2 -; CHECK-NEXT: mvn w9, w8 -; CHECK-NEXT: lsl x8, x0, x8 -; CHECK-NEXT: lsr x9, x10, x9 -; CHECK-NEXT: orr x0, x8, x9 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshl_i37: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov x9, #46053 // =0xb3e5 +; CHECK-SD-NEXT: and x8, x2, #0x1fffffffff +; CHECK-SD-NEXT: movk x9, #12398, lsl #16 +; CHECK-SD-NEXT: ubfiz x10, x1, #26, #37 +; CHECK-SD-NEXT: movk x9, #15941, lsl #32 +; CHECK-SD-NEXT: movk x9, #1771, lsl #48 +; CHECK-SD-NEXT: umulh x8, x8, x9 +; CHECK-SD-NEXT: mov w9, #37 // =0x25 +; CHECK-SD-NEXT: msub w8, w8, w9, w2 +; CHECK-SD-NEXT: mvn w9, w8 +; CHECK-SD-NEXT: lsl x8, x0, x8 +; CHECK-SD-NEXT: lsr x9, x10, x9 +; CHECK-SD-NEXT: orr x0, x8, x9 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshl_i37: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #37 // =0x25 +; CHECK-GI-NEXT: and x9, x2, #0x1fffffffff +; CHECK-GI-NEXT: udiv x10, x9, x8 +; CHECK-GI-NEXT: msub x8, x10, x8, x9 +; CHECK-GI-NEXT: mov w9, #36 // =0x24 +; CHECK-GI-NEXT: ubfx x10, x1, #1, #36 +; CHECK-GI-NEXT: sub x9, x9, x8 +; CHECK-GI-NEXT: and x8, x8, #0x1fffffffff +; CHECK-GI-NEXT: and x9, x9, #0x1fffffffff +; CHECK-GI-NEXT: lsl x8, x0, x8 +; CHECK-GI-NEXT: lsr x9, x10, x9 +; CHECK-GI-NEXT: orr x0, x8, x9 +; CHECK-GI-NEXT: ret %f = call i37 @llvm.fshl.i37(i37 %x, i37 %y, i37 %z) ret i37 %f } @@ -93,26 +171,37 @@ define i7 @fshl_i7_const_fold() { ; CHECK-LABEL: fshl_i7_const_fold: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #67 +; CHECK-NEXT: mov w0, #67 // =0x43 ; CHECK-NEXT: ret %f = call i7 @llvm.fshl.i7(i7 112, i7 127, i7 2) ret i7 %f } define i8 @fshl_i8_const_fold_overshift_1() { -; CHECK-LABEL: fshl_i8_const_fold_overshift_1: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #128 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshl_i8_const_fold_overshift_1: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w0, #128 // =0x80 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshl_i8_const_fold_overshift_1: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w0, #-128 // =0xffffff80 +; CHECK-GI-NEXT: ret %f = call i8 @llvm.fshl.i8(i8 255, i8 0, i8 15) ret i8 %f } define i8 @fshl_i8_const_fold_overshift_2() { -; CHECK-LABEL: fshl_i8_const_fold_overshift_2: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #120 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshl_i8_const_fold_overshift_2: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w0, #120 // =0x78 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshl_i8_const_fold_overshift_2: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #15 // =0xf +; CHECK-GI-NEXT: lsl w0, w8, #3 +; CHECK-GI-NEXT: ret %f = call i8 @llvm.fshl.i8(i8 15, i8 15, i8 11) ret i8 %f } @@ -162,10 +251,15 @@ ; This should work without any node-specific logic. define i8 @fshl_i8_const_fold() { -; CHECK-LABEL: fshl_i8_const_fold: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #128 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshl_i8_const_fold: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w0, #128 // =0x80 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshl_i8_const_fold: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w0, #-128 // =0xffffff80 +; CHECK-GI-NEXT: ret %f = call i8 @llvm.fshl.i8(i8 255, i8 0, i8 7) ret i8 %f } @@ -175,28 +269,50 @@ ; General case - all operands can be variables. define i32 @fshr_i32(i32 %x, i32 %y, i32 %z) { -; CHECK-LABEL: fshr_i32: -; CHECK: // %bb.0: -; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 -; CHECK-NEXT: mvn w8, w2 -; CHECK-NEXT: lsl w9, w0, #1 -; CHECK-NEXT: lsr w10, w1, w2 -; CHECK-NEXT: lsl w8, w9, w8 -; CHECK-NEXT: orr w0, w8, w10 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshr_i32: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: // kill: def $w2 killed $w2 def $x2 +; CHECK-SD-NEXT: mvn w8, w2 +; CHECK-SD-NEXT: lsl w9, w0, #1 +; CHECK-SD-NEXT: lsr w10, w1, w2 +; CHECK-SD-NEXT: lsl w8, w9, w8 +; CHECK-SD-NEXT: orr w0, w8, w10 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshr_i32: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsl w10, w0, #1 +; CHECK-GI-NEXT: lsr w9, w1, w9 +; CHECK-GI-NEXT: lsl w8, w10, w8 +; CHECK-GI-NEXT: orr w0, w8, w9 +; CHECK-GI-NEXT: ret %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %z) ret i32 %f } define i64 @fshr_i64(i64 %x, i64 %y, i64 %z) { -; CHECK-LABEL: fshr_i64: -; CHECK: // %bb.0: -; CHECK-NEXT: mvn w8, w2 -; CHECK-NEXT: lsl x9, x0, #1 -; CHECK-NEXT: lsr x10, x1, x2 -; CHECK-NEXT: lsl x8, x9, x8 -; CHECK-NEXT: orr x0, x8, x10 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshr_i64: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mvn w8, w2 +; CHECK-SD-NEXT: lsl x9, x0, #1 +; CHECK-SD-NEXT: lsr x10, x1, x2 +; CHECK-SD-NEXT: lsl x8, x9, x8 +; CHECK-SD-NEXT: orr x0, x8, x10 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshr_i64: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #63 // =0x3f +; CHECK-GI-NEXT: and x9, x2, #0x3f +; CHECK-GI-NEXT: bic x8, x8, x2 +; CHECK-GI-NEXT: lsl x10, x0, #1 +; CHECK-GI-NEXT: lsr x9, x1, x9 +; CHECK-GI-NEXT: lsl x8, x10, x8 +; CHECK-GI-NEXT: orr x0, x8, x9 +; CHECK-GI-NEXT: ret %f = call i64 @llvm.fshr.i64(i64 %x, i64 %y, i64 %z) ret i64 %f } @@ -204,24 +320,41 @@ ; Verify that weird types are minimally supported. declare i37 @llvm.fshr.i37(i37, i37, i37) define i37 @fshr_i37(i37 %x, i37 %y, i37 %z) { -; CHECK-LABEL: fshr_i37: -; CHECK: // %bb.0: -; CHECK-NEXT: mov x9, #46053 -; CHECK-NEXT: and x8, x2, #0x1fffffffff -; CHECK-NEXT: movk x9, #12398, lsl #16 -; CHECK-NEXT: lsl x10, x1, #27 -; CHECK-NEXT: movk x9, #15941, lsl #32 -; CHECK-NEXT: lsl x11, x0, #1 -; CHECK-NEXT: movk x9, #1771, lsl #48 -; CHECK-NEXT: umulh x8, x8, x9 -; CHECK-NEXT: mov w9, #37 -; CHECK-NEXT: msub w8, w8, w9, w2 -; CHECK-NEXT: add w8, w8, #27 -; CHECK-NEXT: mvn w9, w8 -; CHECK-NEXT: lsr x8, x10, x8 -; CHECK-NEXT: lsl x9, x11, x9 -; CHECK-NEXT: orr x0, x9, x8 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshr_i37: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov x9, #46053 // =0xb3e5 +; CHECK-SD-NEXT: and x8, x2, #0x1fffffffff +; CHECK-SD-NEXT: movk x9, #12398, lsl #16 +; CHECK-SD-NEXT: lsl x10, x1, #27 +; CHECK-SD-NEXT: movk x9, #15941, lsl #32 +; CHECK-SD-NEXT: lsl x11, x0, #1 +; CHECK-SD-NEXT: movk x9, #1771, lsl #48 +; CHECK-SD-NEXT: umulh x8, x8, x9 +; CHECK-SD-NEXT: mov w9, #37 // =0x25 +; CHECK-SD-NEXT: msub w8, w8, w9, w2 +; CHECK-SD-NEXT: add w8, w8, #27 +; CHECK-SD-NEXT: mvn w9, w8 +; CHECK-SD-NEXT: lsr x8, x10, x8 +; CHECK-SD-NEXT: lsl x9, x11, x9 +; CHECK-SD-NEXT: orr x0, x9, x8 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshr_i37: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #37 // =0x25 +; CHECK-GI-NEXT: and x9, x2, #0x1fffffffff +; CHECK-GI-NEXT: and x11, x1, #0x1fffffffff +; CHECK-GI-NEXT: udiv x10, x9, x8 +; CHECK-GI-NEXT: msub x8, x10, x8, x9 +; CHECK-GI-NEXT: mov w9, #36 // =0x24 +; CHECK-GI-NEXT: lsl x10, x0, #1 +; CHECK-GI-NEXT: sub x9, x9, x8 +; CHECK-GI-NEXT: and x8, x8, #0x1fffffffff +; CHECK-GI-NEXT: and x9, x9, #0x1fffffffff +; CHECK-GI-NEXT: lsr x8, x11, x8 +; CHECK-GI-NEXT: lsl x9, x10, x9 +; CHECK-GI-NEXT: orr x0, x9, x8 +; CHECK-GI-NEXT: ret %f = call i37 @llvm.fshr.i37(i37 %x, i37 %y, i37 %z) ret i37 %f } @@ -232,35 +365,52 @@ define i7 @fshr_i7_const_fold() { ; CHECK-LABEL: fshr_i7_const_fold: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #31 +; CHECK-NEXT: mov w0, #31 // =0x1f ; CHECK-NEXT: ret %f = call i7 @llvm.fshr.i7(i7 112, i7 127, i7 2) ret i7 %f } define i8 @fshr_i8_const_fold_overshift_1() { -; CHECK-LABEL: fshr_i8_const_fold_overshift_1: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #254 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshr_i8_const_fold_overshift_1: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w0, #254 // =0xfe +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshr_i8_const_fold_overshift_1: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w0, #-2 // =0xfffffffe +; CHECK-GI-NEXT: ret %f = call i8 @llvm.fshr.i8(i8 255, i8 0, i8 15) ret i8 %f } define i8 @fshr_i8_const_fold_overshift_2() { -; CHECK-LABEL: fshr_i8_const_fold_overshift_2: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #225 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshr_i8_const_fold_overshift_2: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w0, #225 // =0xe1 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshr_i8_const_fold_overshift_2: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #15 // =0xf +; CHECK-GI-NEXT: lsl w9, w8, #5 +; CHECK-GI-NEXT: orr w0, w9, w8, lsr #3 +; CHECK-GI-NEXT: ret %f = call i8 @llvm.fshr.i8(i8 15, i8 15, i8 11) ret i8 %f } define i8 @fshr_i8_const_fold_overshift_3() { -; CHECK-LABEL: fshr_i8_const_fold_overshift_3: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #255 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshr_i8_const_fold_overshift_3: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w0, #255 // =0xff +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshr_i8_const_fold_overshift_3: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w0, #-1 // =0xffffffff +; CHECK-GI-NEXT: ret %f = call i8 @llvm.fshr.i8(i8 0, i8 255, i8 8) ret i8 %f } @@ -301,10 +451,15 @@ ; This should work without any node-specific logic. define i8 @fshr_i8_const_fold() { -; CHECK-LABEL: fshr_i8_const_fold: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w0, #254 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: fshr_i8_const_fold: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w0, #254 // =0xfe +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: fshr_i8_const_fold: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w0, #-2 // =0xfffffffe +; CHECK-GI-NEXT: ret %f = call i8 @llvm.fshr.i8(i8 255, i8 0, i8 7) ret i8 %f } @@ -344,17 +499,30 @@ } define i32 @or_shl_fshl(i32 %x, i32 %y, i32 %s) { -; CHECK-LABEL: or_shl_fshl: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, w2 -; CHECK-NEXT: mvn w9, w2 -; CHECK-NEXT: lsr w10, w1, #1 -; CHECK-NEXT: lsr w9, w10, w9 -; CHECK-NEXT: lsl w8, w0, w8 -; CHECK-NEXT: lsl w10, w1, w2 -; CHECK-NEXT: orr w8, w8, w9 -; CHECK-NEXT: orr w0, w8, w10 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: or_shl_fshl: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w8, w2 +; CHECK-SD-NEXT: mvn w9, w2 +; CHECK-SD-NEXT: lsr w10, w1, #1 +; CHECK-SD-NEXT: lsr w9, w10, w9 +; CHECK-SD-NEXT: lsl w8, w0, w8 +; CHECK-SD-NEXT: lsl w10, w1, w2 +; CHECK-SD-NEXT: orr w8, w8, w9 +; CHECK-SD-NEXT: orr w0, w8, w10 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: or_shl_fshl: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsl w10, w1, w2 +; CHECK-GI-NEXT: lsr w11, w1, #1 +; CHECK-GI-NEXT: lsl w9, w0, w9 +; CHECK-GI-NEXT: lsr w8, w11, w8 +; CHECK-GI-NEXT: orr w9, w9, w10 +; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: ret %shy = shl i32 %y, %s %fun = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %s) %or = or i32 %fun, %shy @@ -376,17 +544,30 @@ } define i32 @or_shl_fshl_commute(i32 %x, i32 %y, i32 %s) { -; CHECK-LABEL: or_shl_fshl_commute: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, w2 -; CHECK-NEXT: mvn w9, w2 -; CHECK-NEXT: lsr w10, w1, #1 -; CHECK-NEXT: lsr w9, w10, w9 -; CHECK-NEXT: lsl w8, w0, w8 -; CHECK-NEXT: lsl w10, w1, w2 -; CHECK-NEXT: orr w8, w8, w9 -; CHECK-NEXT: orr w0, w10, w8 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: or_shl_fshl_commute: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w8, w2 +; CHECK-SD-NEXT: mvn w9, w2 +; CHECK-SD-NEXT: lsr w10, w1, #1 +; CHECK-SD-NEXT: lsr w9, w10, w9 +; CHECK-SD-NEXT: lsl w8, w0, w8 +; CHECK-SD-NEXT: lsl w10, w1, w2 +; CHECK-SD-NEXT: orr w8, w8, w9 +; CHECK-SD-NEXT: orr w0, w10, w8 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: or_shl_fshl_commute: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsl w10, w1, w2 +; CHECK-GI-NEXT: lsr w11, w1, #1 +; CHECK-GI-NEXT: lsl w9, w0, w9 +; CHECK-GI-NEXT: lsr w8, w11, w8 +; CHECK-GI-NEXT: orr w9, w10, w9 +; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: ret %shy = shl i32 %y, %s %fun = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %s) %or = or i32 %shy, %fun @@ -408,17 +589,30 @@ } define i32 @or_lshr_fshr(i32 %x, i32 %y, i32 %s) { -; CHECK-LABEL: or_lshr_fshr: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, w2 -; CHECK-NEXT: mvn w9, w2 -; CHECK-NEXT: lsl w10, w1, #1 -; CHECK-NEXT: lsr w8, w0, w8 -; CHECK-NEXT: lsl w9, w10, w9 -; CHECK-NEXT: lsr w10, w1, w2 -; CHECK-NEXT: orr w8, w9, w8 -; CHECK-NEXT: orr w0, w8, w10 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: or_lshr_fshr: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w8, w2 +; CHECK-SD-NEXT: mvn w9, w2 +; CHECK-SD-NEXT: lsl w10, w1, #1 +; CHECK-SD-NEXT: lsr w8, w0, w8 +; CHECK-SD-NEXT: lsl w9, w10, w9 +; CHECK-SD-NEXT: lsr w10, w1, w2 +; CHECK-SD-NEXT: orr w8, w9, w8 +; CHECK-SD-NEXT: orr w0, w8, w10 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: or_lshr_fshr: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsr w10, w1, w2 +; CHECK-GI-NEXT: lsl w11, w1, #1 +; CHECK-GI-NEXT: lsr w9, w0, w9 +; CHECK-GI-NEXT: lsl w8, w11, w8 +; CHECK-GI-NEXT: orr w9, w9, w10 +; CHECK-GI-NEXT: orr w0, w8, w9 +; CHECK-GI-NEXT: ret %shy = lshr i32 %y, %s %fun = call i32 @llvm.fshr.i32(i32 %y, i32 %x, i32 %s) %or = or i32 %fun, %shy @@ -439,17 +633,30 @@ } define i32 @or_lshr_fshr_commute(i32 %x, i32 %y, i32 %s) { -; CHECK-LABEL: or_lshr_fshr_commute: -; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, w2 -; CHECK-NEXT: mvn w9, w2 -; CHECK-NEXT: lsl w10, w1, #1 -; CHECK-NEXT: lsr w8, w0, w8 -; CHECK-NEXT: lsl w9, w10, w9 -; CHECK-NEXT: lsr w10, w1, w2 -; CHECK-NEXT: orr w8, w9, w8 -; CHECK-NEXT: orr w0, w10, w8 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: or_lshr_fshr_commute: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: mov w8, w2 +; CHECK-SD-NEXT: mvn w9, w2 +; CHECK-SD-NEXT: lsl w10, w1, #1 +; CHECK-SD-NEXT: lsr w8, w0, w8 +; CHECK-SD-NEXT: lsl w9, w10, w9 +; CHECK-SD-NEXT: lsr w10, w1, w2 +; CHECK-SD-NEXT: orr w8, w9, w8 +; CHECK-SD-NEXT: orr w0, w10, w8 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: or_lshr_fshr_commute: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsr w10, w1, w2 +; CHECK-GI-NEXT: lsl w11, w1, #1 +; CHECK-GI-NEXT: lsr w9, w0, w9 +; CHECK-GI-NEXT: lsl w8, w11, w8 +; CHECK-GI-NEXT: orr w9, w10, w9 +; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: ret %shy = lshr i32 %y, %s %fun = call i32 @llvm.fshr.i32(i32 %y, i32 %x, i32 %s) %or = or i32 %shy, %fun @@ -470,15 +677,28 @@ } define i32 @or_shl_fshl_simplify(i32 %x, i32 %y, i32 %s) { -; CHECK-LABEL: or_shl_fshl_simplify: -; CHECK: // %bb.0: -; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 -; CHECK-NEXT: mvn w8, w2 -; CHECK-NEXT: lsr w9, w0, #1 -; CHECK-NEXT: lsl w10, w1, w2 -; CHECK-NEXT: lsr w8, w9, w8 -; CHECK-NEXT: orr w0, w10, w8 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: or_shl_fshl_simplify: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: // kill: def $w2 killed $w2 def $x2 +; CHECK-SD-NEXT: mvn w8, w2 +; CHECK-SD-NEXT: lsr w9, w0, #1 +; CHECK-SD-NEXT: lsl w10, w1, w2 +; CHECK-SD-NEXT: lsr w8, w9, w8 +; CHECK-SD-NEXT: orr w0, w10, w8 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: or_shl_fshl_simplify: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsl w10, w1, w2 +; CHECK-GI-NEXT: lsr w11, w0, #1 +; CHECK-GI-NEXT: lsl w9, w1, w9 +; CHECK-GI-NEXT: lsr w8, w11, w8 +; CHECK-GI-NEXT: orr w9, w9, w10 +; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: ret %shy = shl i32 %y, %s %fun = call i32 @llvm.fshl.i32(i32 %y, i32 %x, i32 %s) %or = or i32 %fun, %shy @@ -486,15 +706,28 @@ } define i32 @or_lshr_fshr_simplify(i32 %x, i32 %y, i32 %s) { -; CHECK-LABEL: or_lshr_fshr_simplify: -; CHECK: // %bb.0: -; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 -; CHECK-NEXT: mvn w8, w2 -; CHECK-NEXT: lsl w9, w0, #1 -; CHECK-NEXT: lsr w10, w1, w2 -; CHECK-NEXT: lsl w8, w9, w8 -; CHECK-NEXT: orr w0, w8, w10 -; CHECK-NEXT: ret +; CHECK-SD-LABEL: or_lshr_fshr_simplify: +; CHECK-SD: // %bb.0: +; CHECK-SD-NEXT: // kill: def $w2 killed $w2 def $x2 +; CHECK-SD-NEXT: mvn w8, w2 +; CHECK-SD-NEXT: lsl w9, w0, #1 +; CHECK-SD-NEXT: lsr w10, w1, w2 +; CHECK-SD-NEXT: lsl w8, w9, w8 +; CHECK-SD-NEXT: orr w0, w8, w10 +; CHECK-SD-NEXT: ret +; +; CHECK-GI-LABEL: or_lshr_fshr_simplify: +; CHECK-GI: // %bb.0: +; CHECK-GI-NEXT: mov w8, #31 // =0x1f +; CHECK-GI-NEXT: and w9, w2, #0x1f +; CHECK-GI-NEXT: bic w8, w8, w2 +; CHECK-GI-NEXT: lsr w10, w1, w2 +; CHECK-GI-NEXT: lsl w11, w0, #1 +; CHECK-GI-NEXT: lsr w9, w1, w9 +; CHECK-GI-NEXT: lsl w8, w11, w8 +; CHECK-GI-NEXT: orr w9, w10, w9 +; CHECK-GI-NEXT: orr w0, w9, w8 +; CHECK-GI-NEXT: ret %shy = lshr i32 %y, %s %fun = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %s) %or = or i32 %shy, %fun Index: llvm/test/CodeGen/AMDGPU/GlobalISel/fshl.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/GlobalISel/fshl.ll +++ llvm/test/CodeGen/AMDGPU/GlobalISel/fshl.ll @@ -2790,33 +2790,33 @@ ; GFX6-LABEL: s_fshl_i32_5: ; GFX6: ; %bb.0: ; GFX6-NEXT: v_mov_b32_e32 v0, s1 -; GFX6-NEXT: v_alignbit_b32 v0, s0, v0, -5 +; GFX6-NEXT: v_alignbit_b32 v0, s0, v0, 27 ; GFX6-NEXT: v_readfirstlane_b32 s0, v0 ; GFX6-NEXT: ; return to shader part epilog ; ; GFX8-LABEL: s_fshl_i32_5: ; GFX8: ; %bb.0: ; GFX8-NEXT: v_mov_b32_e32 v0, s1 -; GFX8-NEXT: v_alignbit_b32 v0, s0, v0, -5 +; GFX8-NEXT: v_alignbit_b32 v0, s0, v0, 27 ; GFX8-NEXT: v_readfirstlane_b32 s0, v0 ; GFX8-NEXT: ; return to shader part epilog ; ; GFX9-LABEL: s_fshl_i32_5: ; GFX9: ; %bb.0: ; GFX9-NEXT: v_mov_b32_e32 v0, s1 -; GFX9-NEXT: v_alignbit_b32 v0, s0, v0, -5 +; GFX9-NEXT: v_alignbit_b32 v0, s0, v0, 27 ; GFX9-NEXT: v_readfirstlane_b32 s0, v0 ; GFX9-NEXT: ; return to shader part epilog ; ; GFX10-LABEL: s_fshl_i32_5: ; GFX10: ; %bb.0: -; GFX10-NEXT: v_alignbit_b32 v0, s0, s1, -5 +; GFX10-NEXT: v_alignbit_b32 v0, s0, s1, 27 ; GFX10-NEXT: v_readfirstlane_b32 s0, v0 ; GFX10-NEXT: ; return to shader part epilog ; ; GFX11-LABEL: s_fshl_i32_5: ; GFX11: ; %bb.0: -; GFX11-NEXT: v_alignbit_b32 v0, s0, s1, -5 +; GFX11-NEXT: v_alignbit_b32 v0, s0, s1, 27 ; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX11-NEXT: v_readfirstlane_b32 s0, v0 ; GFX11-NEXT: ; return to shader part epilog @@ -2828,33 +2828,33 @@ ; GFX6-LABEL: s_fshl_i32_8: ; GFX6: ; %bb.0: ; GFX6-NEXT: v_mov_b32_e32 v0, s1 -; GFX6-NEXT: v_alignbit_b32 v0, s0, v0, -8 +; GFX6-NEXT: v_alignbit_b32 v0, s0, v0, 24 ; GFX6-NEXT: v_readfirstlane_b32 s0, v0 ; GFX6-NEXT: ; return to shader part epilog ; ; GFX8-LABEL: s_fshl_i32_8: ; GFX8: ; %bb.0: ; GFX8-NEXT: v_mov_b32_e32 v0, s1 -; GFX8-NEXT: v_alignbit_b32 v0, s0, v0, -8 +; GFX8-NEXT: v_alignbit_b32 v0, s0, v0, 24 ; GFX8-NEXT: v_readfirstlane_b32 s0, v0 ; GFX8-NEXT: ; return to shader part epilog ; ; GFX9-LABEL: s_fshl_i32_8: ; GFX9: ; %bb.0: ; GFX9-NEXT: v_mov_b32_e32 v0, s1 -; GFX9-NEXT: v_alignbit_b32 v0, s0, v0, -8 +; GFX9-NEXT: v_alignbit_b32 v0, s0, v0, 24 ; GFX9-NEXT: v_readfirstlane_b32 s0, v0 ; GFX9-NEXT: ; return to shader part epilog ; ; GFX10-LABEL: s_fshl_i32_8: ; GFX10: ; %bb.0: -; GFX10-NEXT: v_alignbit_b32 v0, s0, s1, -8 +; GFX10-NEXT: v_alignbit_b32 v0, s0, s1, 24 ; GFX10-NEXT: v_readfirstlane_b32 s0, v0 ; GFX10-NEXT: ; return to shader part epilog ; ; GFX11-LABEL: s_fshl_i32_8: ; GFX11: ; %bb.0: -; GFX11-NEXT: v_alignbit_b32 v0, s0, s1, -8 +; GFX11-NEXT: v_alignbit_b32 v0, s0, s1, 24 ; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX11-NEXT: v_readfirstlane_b32 s0, v0 ; GFX11-NEXT: ; return to shader part epilog @@ -2889,13 +2889,13 @@ ; GCN-LABEL: v_fshl_i32_5: ; GCN: ; %bb.0: ; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GCN-NEXT: v_alignbit_b32 v0, v0, v1, -5 +; GCN-NEXT: v_alignbit_b32 v0, v0, v1, 27 ; GCN-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-LABEL: v_fshl_i32_5: ; GFX11: ; %bb.0: ; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX11-NEXT: v_alignbit_b32 v0, v0, v1, -5 +; GFX11-NEXT: v_alignbit_b32 v0, v0, v1, 27 ; GFX11-NEXT: s_setpc_b64 s[30:31] %result = call i32 @llvm.fshl.i32(i32 %lhs, i32 %rhs, i32 5) ret i32 %result @@ -2905,13 +2905,13 @@ ; GCN-LABEL: v_fshl_i32_8: ; GCN: ; %bb.0: ; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GCN-NEXT: v_alignbit_b32 v0, v0, v1, -8 +; GCN-NEXT: v_alignbit_b32 v0, v0, v1, 24 ; GCN-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-LABEL: v_fshl_i32_8: ; GFX11: ; %bb.0: ; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX11-NEXT: v_alignbit_b32 v0, v0, v1, -8 +; GFX11-NEXT: v_alignbit_b32 v0, v0, v1, 24 ; GFX11-NEXT: s_setpc_b64 s[30:31] %result = call i32 @llvm.fshl.i32(i32 %lhs, i32 %rhs, i32 8) ret i32 %result