[AArch64][GlobalISel] Select patterns which use shifted register operands

This adds GlobalISel equivalents for the following from AArch64InstrFormats:

- arith_shifted_reg32
- arith_shifted_reg64

And partial support for

- logical_shifted_reg32
- logical_shifted_reg32

The only thing missing for the logical cases is support for rotates. Other than
the missing support, the transformation is identical for the arithmetic shifted
register and the logical shifted register.

Lots of tests here:

- Add select-arith-shifted-reg.mir to show that we correctly select add and
sub instructions which use this pattern.

- Add select-logical-shifted-reg.mir to cover patterns which are not shared
between the arithmetic and logical cases.

- Update addsub-shifted.ll to show that we correctly fold shifts into
adds/subs.

- Update eon.ll to show that we can select the eon instruction by folding xors.

Differential Revision: https://reviews.llvm.org/D66163

llvm-svn: 369460
This commit is contained in:
Jessica Paquette 2019-08-20 22:18:06 +00:00
parent ba375263e8
commit 9a95e79b1b
6 changed files with 602 additions and 1 deletions

View File

@ -782,6 +782,14 @@ class arith_shifted_reg<ValueType Ty, RegisterClass regclass, int width>
def arith_shifted_reg32 : arith_shifted_reg<i32, GPR32, 32>;
def arith_shifted_reg64 : arith_shifted_reg<i64, GPR64, 64>;
def gi_arith_shifted_reg32 :
GIComplexOperandMatcher<s32, "selectArithShiftedRegister">,
GIComplexPatternEquiv<arith_shifted_reg32>;
def gi_arith_shifted_reg64 :
GIComplexOperandMatcher<s64, "selectArithShiftedRegister">,
GIComplexPatternEquiv<arith_shifted_reg64>;
// An arithmetic shifter operand:
// {7-6} - shift type: 00 = lsl, 01 = lsr, 10 = asr, 11 = ror
// {5-0} - imm6
@ -804,6 +812,14 @@ class logical_shifted_reg<ValueType Ty, RegisterClass regclass, Operand shiftop>
def logical_shifted_reg32 : logical_shifted_reg<i32, GPR32, logical_shift32>;
def logical_shifted_reg64 : logical_shifted_reg<i64, GPR64, logical_shift64>;
def gi_logical_shifted_reg32 :
GIComplexOperandMatcher<s32, "selectLogicalShiftedRegister">,
GIComplexPatternEquiv<logical_shifted_reg32>;
def gi_logical_shifted_reg64 :
GIComplexOperandMatcher<s64, "selectLogicalShiftedRegister">,
GIComplexPatternEquiv<logical_shifted_reg64>;
// A logical vector shifter operand:
// {7-6} - shift type: 00 = lsl
// {5-0} - imm6: #0, #8, #16, or #24

View File

@ -209,6 +209,20 @@ private:
ComplexRendererFns selectAddrModeXRO(MachineOperand &Root,
unsigned SizeInBytes) const;
ComplexRendererFns selectShiftedRegister(MachineOperand &Root) const;
ComplexRendererFns selectArithShiftedRegister(MachineOperand &Root) const {
return selectShiftedRegister(Root);
}
ComplexRendererFns selectLogicalShiftedRegister(MachineOperand &Root) const {
// TODO: selectShiftedRegister should allow for rotates on logical shifts.
// For now, make them the same. The only difference between the two is that
// logical shifts are allowed to fold in rotates. Otherwise, these are
// functionally the same.
return selectShiftedRegister(Root);
}
void renderTruncImm(MachineInstrBuilder &MIB, const MachineInstr &MI) const;
// Materialize a GlobalValue or BlockAddress using a movz+movk sequence.
@ -4492,6 +4506,65 @@ AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
}};
}
/// Given a shift instruction, return the correct shift type for that
/// instruction.
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI) {
// TODO: Handle AArch64_AM::ROR
switch (MI.getOpcode()) {
default:
return AArch64_AM::InvalidShiftExtend;
case TargetOpcode::G_SHL:
return AArch64_AM::LSL;
case TargetOpcode::G_LSHR:
return AArch64_AM::LSR;
case TargetOpcode::G_ASHR:
return AArch64_AM::ASR;
}
}
/// Select a "shifted register" operand. If the value is not shifted, set the
/// shift operand to a default value of "lsl 0".
///
/// TODO: Allow shifted register to be rotated in logical instructions.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root) const {
if (!Root.isReg())
return None;
MachineRegisterInfo &MRI =
Root.getParent()->getParent()->getParent()->getRegInfo();
// Check if the operand is defined by an instruction which corresponds to
// a ShiftExtendType. E.g. a G_SHL, G_LSHR, etc.
//
// TODO: Handle AArch64_AM::ROR for logical instructions.
MachineInstr *ShiftInst = MRI.getVRegDef(Root.getReg());
if (!ShiftInst)
return None;
AArch64_AM::ShiftExtendType ShType = getShiftTypeForInst(*ShiftInst);
if (ShType == AArch64_AM::InvalidShiftExtend)
return None;
if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI))
return None;
// Need an immediate on the RHS.
MachineOperand &ShiftRHS = ShiftInst->getOperand(2);
auto Immed = getImmedFromMO(ShiftRHS);
if (!Immed)
return None;
// We have something that we can fold. Fold in the shift's LHS and RHS into
// the instruction.
MachineOperand &ShiftLHS = ShiftInst->getOperand(1);
Register ShiftReg = ShiftLHS.getReg();
unsigned NumBits = MRI.getType(ShiftReg).getSizeInBits();
unsigned Val = *Immed & (NumBits - 1);
unsigned ShiftVal = AArch64_AM::getShifterImm(ShType, Val);
return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
[=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
}
void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
const MachineInstr &MI) const {
const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();

View File

@ -0,0 +1,395 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=aarch64-unknown-unknown -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
---
name: add_shl_s64_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: add_shl_s64_rhs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[ADDXrs:%[0-9]+]]:gpr64 = ADDXrs [[COPY]], [[COPY]], 8
; CHECK: $x0 = COPY [[ADDXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_SHL %0, %1:gpr(s64)
%3:gpr(s64) = G_ADD %0, %2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: add_shl_s64_lhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0, $x1
; CHECK-LABEL: name: add_shl_s64_lhs
; CHECK: liveins: $x0, $x1
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
; CHECK: [[ADDXrs:%[0-9]+]]:gpr64 = ADDXrs [[COPY1]], [[COPY]], 8
; CHECK: $x0 = COPY [[ADDXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%4:gpr(s64) = COPY $x1
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_SHL %0, %1:gpr(s64)
%3:gpr(s64) = G_ADD %2, %4:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: sub_shl_s64_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: sub_shl_s64_rhs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[SUBSXrs:%[0-9]+]]:gpr64 = SUBSXrs [[COPY]], [[COPY]], 8, implicit-def $nzcv
; CHECK: $x0 = COPY [[SUBSXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_SHL %0, %1:gpr(s64)
%3:gpr(s64) = G_SUB %0, %2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
---
name: add_lshr_s64_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_LSHR %0, %1:gpr(s64)
%3:gpr(s64) = G_ADD %0, %2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: add_lshr_s64_lhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0, $x1
; CHECK-LABEL: name: add_lshr_s64_lhs
; CHECK: liveins: $x0, $x1
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: %param2:gpr64 = COPY $x1
; CHECK: [[ADDXrs:%[0-9]+]]:gpr64 = ADDXrs %param2, [[COPY]], 72
; CHECK: $x0 = COPY [[ADDXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%param2:gpr(s64) = COPY $x1
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_LSHR %0, %1:gpr(s64)
%3:gpr(s64) = G_ADD %2, %param2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: sub_lshr_s64_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: sub_lshr_s64_rhs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[SUBSXrs:%[0-9]+]]:gpr64 = SUBSXrs [[COPY]], [[COPY]], 72, implicit-def $nzcv
; CHECK: $x0 = COPY [[SUBSXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_LSHR %0, %1:gpr(s64)
%3:gpr(s64) = G_SUB %0, %2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: add_ashr_s64_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: add_ashr_s64_rhs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[ADDXrs:%[0-9]+]]:gpr64 = ADDXrs [[COPY]], [[COPY]], 136
; CHECK: $x0 = COPY [[ADDXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_ASHR %0, %1:gpr(s64)
%3:gpr(s64) = G_ADD %0, %2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: add_ashr_s64_lhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0, $x1
; CHECK-LABEL: name: add_ashr_s64_lhs
; CHECK: liveins: $x0, $x1
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: %param2:gpr64 = COPY $x1
; CHECK: [[ADDXrs:%[0-9]+]]:gpr64 = ADDXrs %param2, [[COPY]], 136
; CHECK: $x0 = COPY [[ADDXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%param2:gpr(s64) = COPY $x1
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_ASHR %0, %1:gpr(s64)
%3:gpr(s64) = G_ADD %2, %param2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: sub_ashr_s64_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: sub_ashr_s64_rhs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[SUBSXrs:%[0-9]+]]:gpr64 = SUBSXrs [[COPY]], [[COPY]], 136, implicit-def $nzcv
; CHECK: $x0 = COPY [[SUBSXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_ASHR %0, %1:gpr(s64)
%3:gpr(s64) = G_SUB %0, %2:gpr(s64)
$x0 = COPY %3:gpr(s64)
RET_ReallyLR implicit $x0
---
name: add_shl_s32_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_SHL %0, %1:gpr(s32)
%3:gpr(s32) = G_ADD %0, %2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: add_shl_s32_lhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1
; CHECK-LABEL: name: add_shl_s32_lhs
; CHECK: liveins: $w0, $w1
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: %param2:gpr32 = COPY $w1
; CHECK: [[ADDWrs:%[0-9]+]]:gpr32 = ADDWrs %param2, [[COPY]], 8
; CHECK: $w0 = COPY [[ADDWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%param2:gpr(s32) = COPY $w1
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_SHL %0, %1:gpr(s32)
%3:gpr(s32) = G_ADD %2, %param2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: sub_shl_s32_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
; CHECK-LABEL: name: sub_shl_s32_rhs
; CHECK: liveins: $w0
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[SUBSWrs:%[0-9]+]]:gpr32 = SUBSWrs [[COPY]], [[COPY]], 8, implicit-def $nzcv
; CHECK: $w0 = COPY [[SUBSWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_SHL %0, %1:gpr(s32)
%3:gpr(s32) = G_SUB %0, %2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: add_lshr_s32_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
; CHECK-LABEL: name: add_lshr_s32_rhs
; CHECK: liveins: $w0
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[ADDWrs:%[0-9]+]]:gpr32 = ADDWrs [[COPY]], [[COPY]], 72
; CHECK: $w0 = COPY [[ADDWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_LSHR %0, %1:gpr(s32)
%3:gpr(s32) = G_ADD %0, %2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: add_lshr_s32_lhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1
; CHECK-LABEL: name: add_lshr_s32_lhs
; CHECK: liveins: $w0, $w1
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: %param2:gpr32 = COPY $w1
; CHECK: [[ADDWrs:%[0-9]+]]:gpr32 = ADDWrs %param2, [[COPY]], 72
; CHECK: $w0 = COPY [[ADDWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%param2:gpr(s32) = COPY $w1
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_LSHR %0, %1:gpr(s32)
%3:gpr(s32) = G_ADD %2, %param2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: sub_lshr_s32_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
; CHECK-LABEL: name: sub_lshr_s32_rhs
; CHECK: liveins: $w0
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[SUBSWrs:%[0-9]+]]:gpr32 = SUBSWrs [[COPY]], [[COPY]], 72, implicit-def $nzcv
; CHECK: $w0 = COPY [[SUBSWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_LSHR %0, %1:gpr(s32)
%3:gpr(s32) = G_SUB %0, %2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: add_ashr_s32_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
; CHECK-LABEL: name: add_ashr_s32_rhs
; CHECK: liveins: $w0
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[ADDWrs:%[0-9]+]]:gpr32 = ADDWrs [[COPY]], [[COPY]], 136
; CHECK: $w0 = COPY [[ADDWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_ASHR %0, %1:gpr(s32)
%3:gpr(s32) = G_ADD %0, %2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: add_ashr_s32_lhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1
; CHECK-LABEL: name: add_ashr_s32_lhs
; CHECK: liveins: $w0, $w1
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: %param2:gpr32 = COPY $w1
; CHECK: [[ADDWrs:%[0-9]+]]:gpr32 = ADDWrs %param2, [[COPY]], 136
; CHECK: $w0 = COPY [[ADDWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%param2:gpr(s32) = COPY $w1
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_ASHR %0, %1:gpr(s32)
%3:gpr(s32) = G_ADD %2, %param2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0
...
---
name: sub_ashr_s32_rhs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
; CHECK-LABEL: name: sub_ashr_s32_rhs
; CHECK: liveins: $w0
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[SUBSWrs:%[0-9]+]]:gpr32 = SUBSWrs [[COPY]], [[COPY]], 136, implicit-def $nzcv
; CHECK: $w0 = COPY [[SUBSWrs]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = G_CONSTANT i32 8
%2:gpr(s32) = G_ASHR %0, %1:gpr(s32)
%3:gpr(s32) = G_SUB %0, %2:gpr(s32)
$w0 = COPY %3:gpr(s32)
RET_ReallyLR implicit $w0

View File

@ -0,0 +1,75 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=aarch64-unknown-unknown -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
#
# Test patterns related to logical_shifted_reg32/logical_shifted_reg64 which
# are not shared with arith_shifted_reg32/arith_shifted_reg64.
---
name: and_xor_bicxrs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: and_xor_bicxrs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[BICXrs:%[0-9]+]]:gpr64 = BICXrs [[COPY]], [[COPY]], 8
; CHECK: $x0 = COPY [[BICXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_CONSTANT i64 -1
%3:gpr(s64) = G_SHL %0, %1:gpr(s64)
%4:gpr(s64) = G_XOR %3, %2:gpr(s64)
%5:gpr(s64) = G_AND %0, %4:gpr(s64)
$x0 = COPY %5:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: or_xor_ornxrs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: or_xor_ornxrs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[ORNXrs:%[0-9]+]]:gpr64 = ORNXrs [[COPY]], [[COPY]], 8
; CHECK: $x0 = COPY [[ORNXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_CONSTANT i64 -1
%3:gpr(s64) = G_SHL %0, %1:gpr(s64)
%4:gpr(s64) = G_XOR %3, %2:gpr(s64)
%5:gpr(s64) = G_OR %0, %4:gpr(s64)
$x0 = COPY %5:gpr(s64)
RET_ReallyLR implicit $x0
...
---
name: xor_xor_eonxrs
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: xor_xor_eonxrs
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[EONXrs:%[0-9]+]]:gpr64 = EONXrs [[COPY]], [[COPY]], 8
; CHECK: $x0 = COPY [[EONXrs]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 8
%2:gpr(s64) = G_CONSTANT i64 -1
%3:gpr(s64) = G_SHL %0, %1:gpr(s64)
%4:gpr(s64) = G_XOR %3, %2:gpr(s64)
%5:gpr(s64) = G_XOR %0, %4:gpr(s64)
$x0 = COPY %5:gpr(s64)
RET_ReallyLR implicit $x0
...

View File

@ -1,28 +1,35 @@
; RUN: llc -verify-machineinstrs %s -o - -mtriple=arm64-apple-ios7.0 | FileCheck %s
; RUN: llc -verify-machineinstrs %s -o - -mtriple=arm64-apple-ios7.0 -global-isel -pass-remarks-missed=gisel* 2>&1 | FileCheck %s --check-prefixes=GISEL,FALLBACK
; FALLBACK-NOT: remark
@var32 = global i32 0
@var64 = global i64 0
define void @test_lsl_arith(i32 %lhs32, i32 %rhs32, i64 %lhs64, i64 %rhs64) {
; CHECK-LABEL: test_lsl_arith:
; GISEL-LABEL: test_lsl_arith:
%rhs1 = load volatile i32, i32* @var32
%shift1 = shl i32 %rhs1, 18
%val1 = add i32 %lhs32, %shift1
store volatile i32 %val1, i32* @var32
; CHECK: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #18
; GISEL: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #18
%rhs2 = load volatile i32, i32* @var32
%shift2 = shl i32 %rhs2, 31
%val2 = add i32 %shift2, %lhs32
store volatile i32 %val2, i32* @var32
; CHECK: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #31
; GISEL: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #31
%rhs3 = load volatile i32, i32* @var32
%shift3 = shl i32 %rhs3, 5
%val3 = sub i32 %lhs32, %shift3
store volatile i32 %val3, i32* @var32
; CHECK: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #5
; GISEL: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #5
; Subtraction is not commutative!
%rhs4 = load volatile i32, i32* @var32
@ -30,30 +37,35 @@ define void @test_lsl_arith(i32 %lhs32, i32 %rhs32, i64 %lhs64, i64 %rhs64) {
%val4 = sub i32 %shift4, %lhs32
store volatile i32 %val4, i32* @var32
; CHECK-NOT: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #19
; GISEL-NOT: sub{{[s]?}} {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsl #19
%lhs4a = load volatile i32, i32* @var32
%shift4a = shl i32 %lhs4a, 15
%val4a = sub i32 0, %shift4a
store volatile i32 %val4a, i32* @var32
; CHECK: neg {{w[0-9]+}}, {{w[0-9]+}}, lsl #15
; GISEL: negs {{w[0-9]+}}, {{w[0-9]+}}, lsl #15
%rhs5 = load volatile i64, i64* @var64
%shift5 = shl i64 %rhs5, 18
%val5 = add i64 %lhs64, %shift5
store volatile i64 %val5, i64* @var64
; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #18
; GISEL: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #18
%rhs6 = load volatile i64, i64* @var64
%shift6 = shl i64 %rhs6, 31
%val6 = add i64 %shift6, %lhs64
store volatile i64 %val6, i64* @var64
; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #31
; GISEL: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #31
%rhs7 = load volatile i64, i64* @var64
%shift7 = shl i64 %rhs7, 5
%val7 = sub i64 %lhs64, %shift7
store volatile i64 %val7, i64* @var64
; CHECK: sub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #5
; GISEL: subs {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #5
; Subtraction is not commutative!
%rhs8 = load volatile i64, i64* @var64
@ -61,12 +73,14 @@ define void @test_lsl_arith(i32 %lhs32, i32 %rhs32, i64 %lhs64, i64 %rhs64) {
%val8 = sub i64 %shift8, %lhs64
store volatile i64 %val8, i64* @var64
; CHECK-NOT: sub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #19
; GISEL-NOT: sub{{[s]?}} {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsl #19
%lhs8a = load volatile i64, i64* @var64
%shift8a = shl i64 %lhs8a, 60
%val8a = sub i64 0, %shift8a
store volatile i64 %val8a, i64* @var64
; CHECK: neg {{x[0-9]+}}, {{x[0-9]+}}, lsl #60
; GISEL: negs {{x[0-9]+}}, {{x[0-9]+}}, lsl #60
ret void
; CHECK: ret
@ -79,56 +93,67 @@ define void @test_lsr_arith(i32 %lhs32, i32 %rhs32, i64 %lhs64, i64 %rhs64) {
%val1 = add i32 %lhs32, %shift1
store volatile i32 %val1, i32* @var32
; CHECK: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #18
; GISEL: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #18
%shift2 = lshr i32 %rhs32, 31
%val2 = add i32 %shift2, %lhs32
store volatile i32 %val2, i32* @var32
; CHECK: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #31
; GISEL: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #31
%shift3 = lshr i32 %rhs32, 5
%val3 = sub i32 %lhs32, %shift3
store volatile i32 %val3, i32* @var32
; CHECK: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #5
; GISEL: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #5
; Subtraction is not commutative!
%shift4 = lshr i32 %rhs32, 19
%val4 = sub i32 %shift4, %lhs32
store volatile i32 %val4, i32* @var32
; CHECK-NOT: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #19
; GISEL-NOT: sub{{[s]?}} {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, lsr #19
%shift4a = lshr i32 %lhs32, 15
%val4a = sub i32 0, %shift4a
store volatile i32 %val4a, i32* @var32
; CHECK: neg {{w[0-9]+}}, {{w[0-9]+}}, lsr #15
; GISEL: negs {{w[0-9]+}}, {{w[0-9]+}}, lsr #15
%shift5 = lshr i64 %rhs64, 18
%val5 = add i64 %lhs64, %shift5
store volatile i64 %val5, i64* @var64
; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #18
; GISEL: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #18
%shift6 = lshr i64 %rhs64, 31
%val6 = add i64 %shift6, %lhs64
store volatile i64 %val6, i64* @var64
; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #31
; GISEL: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #31
%shift7 = lshr i64 %rhs64, 5
%val7 = sub i64 %lhs64, %shift7
store volatile i64 %val7, i64* @var64
; CHECK: sub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #5
; GISEL: subs {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #5
; Subtraction is not commutative!
%shift8 = lshr i64 %rhs64, 19
%val8 = sub i64 %shift8, %lhs64
store volatile i64 %val8, i64* @var64
; CHECK-NOT: sub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #19
; GISEL-NOT: sub{{[s]?}} {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, lsr #19
%shift8a = lshr i64 %lhs64, 45
%val8a = sub i64 0, %shift8a
store volatile i64 %val8a, i64* @var64
; CHECK: neg {{x[0-9]+}}, {{x[0-9]+}}, lsr #45
; GISEL: negs {{x[0-9]+}}, {{x[0-9]+}}, lsr #45
ret void
; CHECK: ret
; GISEL: ret
}
define void @test_asr_arith(i32 %lhs32, i32 %rhs32, i64 %lhs64, i64 %rhs64) {
@ -138,53 +163,63 @@ define void @test_asr_arith(i32 %lhs32, i32 %rhs32, i64 %lhs64, i64 %rhs64) {
%val1 = add i32 %lhs32, %shift1
store volatile i32 %val1, i32* @var32
; CHECK: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #18
; GISEL: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #18
%shift2 = ashr i32 %rhs32, 31
%val2 = add i32 %shift2, %lhs32
store volatile i32 %val2, i32* @var32
; CHECK: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #31
; GISEL: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #31
%shift3 = ashr i32 %rhs32, 5
%val3 = sub i32 %lhs32, %shift3
store volatile i32 %val3, i32* @var32
; CHECK: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #5
; GISEL: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #5
; Subtraction is not commutative!
%shift4 = ashr i32 %rhs32, 19
%val4 = sub i32 %shift4, %lhs32
store volatile i32 %val4, i32* @var32
; CHECK-NOT: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #19
; GISEL-NOT: sub{{[s]?}} {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, asr #19
%shift4a = ashr i32 %lhs32, 15
%val4a = sub i32 0, %shift4a
store volatile i32 %val4a, i32* @var32
; CHECK: neg {{w[0-9]+}}, {{w[0-9]+}}, asr #15
; GISEL: negs {{w[0-9]+}}, {{w[0-9]+}}, asr #15
%shift5 = ashr i64 %rhs64, 18
%val5 = add i64 %lhs64, %shift5
store volatile i64 %val5, i64* @var64
; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #18
; GISEL: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #18
%shift6 = ashr i64 %rhs64, 31
%val6 = add i64 %shift6, %lhs64
store volatile i64 %val6, i64* @var64
; CHECK: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #31
; GISEL: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #31
%shift7 = ashr i64 %rhs64, 5
%val7 = sub i64 %lhs64, %shift7
store volatile i64 %val7, i64* @var64
; CHECK: sub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #5
; GISEL: subs {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #5
; Subtraction is not commutative!
%shift8 = ashr i64 %rhs64, 19
%val8 = sub i64 %shift8, %lhs64
store volatile i64 %val8, i64* @var64
; CHECK-NOT: sub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #19
; GISEL-NOT: sub{{[s]?}} {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, asr #19
%shift8a = ashr i64 %lhs64, 45
%val8a = sub i64 0, %shift8a
store volatile i64 %val8a, i64* @var64
; CHECK: neg {{x[0-9]+}}, {{x[0-9]+}}, asr #45
; GISEL: negs {{x[0-9]+}}, {{x[0-9]+}}, asr #45
ret void
; CHECK: ret
@ -253,6 +288,8 @@ define i32 @test_cmn(i32 %lhs32, i32 %rhs32, i64 %lhs64, i64 %rhs64) {
; 0 then the results will differ.
; CHECK: neg [[RHS:w[0-9]+]], {{w[0-9]+}}, lsl #13
; CHECK: cmp {{w[0-9]+}}, [[RHS]]
; GISEL: negs [[RHS:w[0-9]+]], {{w[0-9]+}}, lsl #13
; GISEL: cmp {{w[0-9]+}}, [[RHS]]
t2:
%shift2 = lshr i32 %rhs32, 20
@ -276,6 +313,8 @@ t4:
; Again, it's important that cmn isn't used here in case %rhs64 == 0.
; CHECK: neg [[RHS:x[0-9]+]], {{x[0-9]+}}, lsl #43
; CHECK: cmp {{x[0-9]+}}, [[RHS]]
; GISEL: negs [[RHS:x[0-9]+]], {{x[0-9]+}}, lsl #43
; GISEL: cmp {{x[0-9]+}}, [[RHS]]
t5:
%shift5 = lshr i64 %rhs64, 20
@ -297,5 +336,5 @@ end:
ret i32 0
; CHECK: ret
; GISEL: ret
}

View File

@ -1,4 +1,7 @@
; RUN: llc -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s
; RUN: llc %s -pass-remarks-missed=gisel* -mtriple=aarch64-none-linux-gnu -global-isel -o - 2>&1 | FileCheck %s
; CHECK-NOT: remark
; Check that the eon instruction is generated instead of eor,movn
define i64 @test1(i64 %a, i64 %b, i64 %c) {