mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-27 14:34:58 +00:00
[FastISel][AArch64] Fold Sign-/Zero-Extend into the shift immediate instruction.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216510 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c04b78627d
commit
836f4bd090
@ -195,13 +195,16 @@ private:
|
||||
unsigned Op1, bool Op1IsKill);
|
||||
unsigned emitLSL_rr(MVT RetVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
unsigned Op1Reg, bool Op1IsKill);
|
||||
unsigned emitLSL_ri(MVT RetVT, unsigned Op0Reg, bool Op0IsKill, uint64_t Imm);
|
||||
unsigned emitLSL_ri(MVT RetVT, MVT SrcVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
uint64_t Imm, bool IsZExt = true);
|
||||
unsigned emitLSR_rr(MVT RetVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
unsigned Op1Reg, bool Op1IsKill);
|
||||
unsigned emitLSR_ri(MVT RetVT, unsigned Op0Reg, bool Op0IsKill, uint64_t Imm);
|
||||
unsigned emitLSR_ri(MVT RetVT, MVT SrcVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
uint64_t Imm, bool IsZExt = true);
|
||||
unsigned emitASR_rr(MVT RetVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
unsigned Op1Reg, bool Op1IsKill);
|
||||
unsigned emitASR_ri(MVT RetVT, unsigned Op0Reg, bool Op0IsKill, uint64_t Imm);
|
||||
unsigned emitASR_ri(MVT RetVT, MVT SrcVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
uint64_t Imm, bool IsZExt = false);
|
||||
|
||||
unsigned AArch64MaterializeInt(const ConstantInt *CI, MVT VT);
|
||||
unsigned AArch64MaterializeFP(const ConstantFP *CFP, MVT VT);
|
||||
@ -718,8 +721,8 @@ bool AArch64FastISel::SimplifyAddress(Address &Addr, MVT VT) {
|
||||
Addr.getOffsetReg(), /*TODO:IsKill=*/false,
|
||||
Addr.getShift());
|
||||
else
|
||||
ResultReg = emitLSL_ri(MVT::i64, Addr.getOffsetReg(), /*Op0IsKill=*/false,
|
||||
Addr.getShift());
|
||||
ResultReg = emitLSL_ri(MVT::i64, MVT::i64, Addr.getOffsetReg(),
|
||||
/*Op0IsKill=*/false, Addr.getShift());
|
||||
if (!ResultReg)
|
||||
return false;
|
||||
|
||||
@ -2381,7 +2384,8 @@ bool AArch64FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) {
|
||||
|
||||
if (VT == MVT::i32) {
|
||||
MulReg = Emit_SMULL_rr(MVT::i64, LHSReg, LHSIsKill, RHSReg, RHSIsKill);
|
||||
unsigned ShiftReg = emitLSR_ri(MVT::i64, MulReg, /*IsKill=*/false, 32);
|
||||
unsigned ShiftReg = emitLSR_ri(MVT::i64, MVT::i64, MulReg,
|
||||
/*IsKill=*/false, 32);
|
||||
MulReg = FastEmitInst_extractsubreg(VT, MulReg, /*IsKill=*/true,
|
||||
AArch64::sub_32);
|
||||
ShiftReg = FastEmitInst_extractsubreg(VT, ShiftReg, /*IsKill=*/true,
|
||||
@ -2694,23 +2698,70 @@ unsigned AArch64FastISel::emitLSL_rr(MVT RetVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
return ResultReg;
|
||||
}
|
||||
|
||||
unsigned AArch64FastISel::emitLSL_ri(MVT RetVT, unsigned Op0, bool Op0IsKill,
|
||||
uint64_t Shift) {
|
||||
unsigned Opc, ImmR, ImmS;
|
||||
switch (RetVT.SimpleTy) {
|
||||
default: return 0;
|
||||
case MVT::i8:
|
||||
Opc = AArch64::UBFMWri; ImmR = -Shift % 32; ImmS = 7 - Shift; break;
|
||||
case MVT::i16:
|
||||
Opc = AArch64::UBFMWri; ImmR = -Shift % 32; ImmS = 15 - Shift; break;
|
||||
case MVT::i32:
|
||||
Opc = AArch64::UBFMWri; ImmR = -Shift % 32; ImmS = 31 - Shift; break;
|
||||
case MVT::i64:
|
||||
Opc = AArch64::UBFMXri; ImmR = -Shift % 64; ImmS = 63 - Shift; break;
|
||||
}
|
||||
unsigned AArch64FastISel::emitLSL_ri(MVT RetVT, MVT SrcVT, unsigned Op0,
|
||||
bool Op0IsKill, uint64_t Shift,
|
||||
bool IsZext) {
|
||||
assert(RetVT.SimpleTy >= SrcVT.SimpleTy &&
|
||||
"Unexpected source/return type pair.");
|
||||
assert((SrcVT == MVT::i8 || SrcVT == MVT::i16 || SrcVT == MVT::i32 ||
|
||||
SrcVT == MVT::i64) && "Unexpected source value type.");
|
||||
assert((RetVT == MVT::i8 || RetVT == MVT::i16 || RetVT == MVT::i32 ||
|
||||
RetVT == MVT::i64) && "Unexpected return value type.");
|
||||
|
||||
bool Is64Bit = (RetVT == MVT::i64);
|
||||
unsigned RegSize = Is64Bit ? 64 : 32;
|
||||
unsigned DstBits = RetVT.getSizeInBits();
|
||||
unsigned SrcBits = SrcVT.getSizeInBits();
|
||||
|
||||
// Don't deal with undefined shifts.
|
||||
if (Shift >= DstBits)
|
||||
return 0;
|
||||
|
||||
// For immediate shifts we can fold the zero-/sign-extension into the shift.
|
||||
// {S|U}BFM Wd, Wn, #r, #s
|
||||
// Wd<32+s-r,32-r> = Wn<s:0> when r > s
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = shl i16 %1, 4
|
||||
// Wd<32+7-28,32-28> = Wn<7:0> <- clamp s to 7
|
||||
// 0b1111_1111_1111_1111__1111_1010_1010_0000 sext
|
||||
// 0b0000_0000_0000_0000__0000_0101_0101_0000 sext | zext
|
||||
// 0b0000_0000_0000_0000__0000_1010_1010_0000 zext
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = shl i16 %1, 8
|
||||
// Wd<32+7-24,32-24> = Wn<7:0>
|
||||
// 0b1111_1111_1111_1111__1010_1010_0000_0000 sext
|
||||
// 0b0000_0000_0000_0000__0101_0101_0000_0000 sext | zext
|
||||
// 0b0000_0000_0000_0000__1010_1010_0000_0000 zext
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = shl i16 %1, 12
|
||||
// Wd<32+3-20,32-20> = Wn<3:0>
|
||||
// 0b1111_1111_1111_1111__1010_0000_0000_0000 sext
|
||||
// 0b0000_0000_0000_0000__0101_0000_0000_0000 sext | zext
|
||||
// 0b0000_0000_0000_0000__1010_0000_0000_0000 zext
|
||||
|
||||
unsigned ImmR = RegSize - Shift;
|
||||
// Limit the width to the length of the source type.
|
||||
unsigned ImmS = std::min<unsigned>(SrcBits - 1, DstBits - 1 - Shift);
|
||||
static const unsigned OpcTable[2][2] = {
|
||||
{AArch64::SBFMWri, AArch64::SBFMXri},
|
||||
{AArch64::UBFMWri, AArch64::UBFMXri}
|
||||
};
|
||||
unsigned Opc = OpcTable[IsZext][Is64Bit];
|
||||
const TargetRegisterClass *RC =
|
||||
(RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
|
||||
Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
|
||||
if (SrcVT.SimpleTy <= MVT::i32 && RetVT == MVT::i64) {
|
||||
unsigned TmpReg = MRI.createVirtualRegister(RC);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(AArch64::SUBREG_TO_REG), TmpReg)
|
||||
.addImm(0)
|
||||
.addReg(Op0, getKillRegState(Op0IsKill))
|
||||
.addImm(AArch64::sub_32);
|
||||
Op0 = TmpReg;
|
||||
Op0IsKill = true;
|
||||
}
|
||||
return FastEmitInst_rii(Opc, RC, Op0, Op0IsKill, ImmR, ImmS);
|
||||
}
|
||||
|
||||
@ -2741,20 +2792,86 @@ unsigned AArch64FastISel::emitLSR_rr(MVT RetVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
return ResultReg;
|
||||
}
|
||||
|
||||
unsigned AArch64FastISel::emitLSR_ri(MVT RetVT, unsigned Op0, bool Op0IsKill,
|
||||
uint64_t Shift) {
|
||||
unsigned Opc, ImmS;
|
||||
switch (RetVT.SimpleTy) {
|
||||
default: return 0;
|
||||
case MVT::i8: Opc = AArch64::UBFMWri; ImmS = 7; break;
|
||||
case MVT::i16: Opc = AArch64::UBFMWri; ImmS = 15; break;
|
||||
case MVT::i32: Opc = AArch64::UBFMWri; ImmS = 31; break;
|
||||
case MVT::i64: Opc = AArch64::UBFMXri; ImmS = 63; break;
|
||||
unsigned AArch64FastISel::emitLSR_ri(MVT RetVT, MVT SrcVT, unsigned Op0,
|
||||
bool Op0IsKill, uint64_t Shift,
|
||||
bool IsZExt) {
|
||||
assert(RetVT.SimpleTy >= SrcVT.SimpleTy &&
|
||||
"Unexpected source/return type pair.");
|
||||
assert((SrcVT == MVT::i8 || SrcVT == MVT::i16 || SrcVT == MVT::i32 ||
|
||||
SrcVT == MVT::i64) && "Unexpected source value type.");
|
||||
assert((RetVT == MVT::i8 || RetVT == MVT::i16 || RetVT == MVT::i32 ||
|
||||
RetVT == MVT::i64) && "Unexpected return value type.");
|
||||
|
||||
bool Is64Bit = (RetVT == MVT::i64);
|
||||
unsigned RegSize = Is64Bit ? 64 : 32;
|
||||
unsigned DstBits = RetVT.getSizeInBits();
|
||||
unsigned SrcBits = SrcVT.getSizeInBits();
|
||||
|
||||
// Don't deal with undefined shifts.
|
||||
if (Shift >= DstBits)
|
||||
return 0;
|
||||
|
||||
// For immediate shifts we can fold the zero-/sign-extension into the shift.
|
||||
// {S|U}BFM Wd, Wn, #r, #s
|
||||
// Wd<s-r:0> = Wn<s:r> when r <= s
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = lshr i16 %1, 4
|
||||
// Wd<7-4:0> = Wn<7:4>
|
||||
// 0b0000_0000_0000_0000__0000_1111_1111_1010 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0101 sext | zext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_1010 zext
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = lshr i16 %1, 8
|
||||
// Wd<7-7,0> = Wn<7:7>
|
||||
// 0b0000_0000_0000_0000__0000_0000_1111_1111 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 zext
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = lshr i16 %1, 12
|
||||
// Wd<7-7,0> = Wn<7:7> <- clamp r to 7
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_1111 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 zext
|
||||
|
||||
if (Shift >= SrcBits && IsZExt)
|
||||
return AArch64MaterializeInt(ConstantInt::get(*Context, APInt(RegSize, 0)),
|
||||
RetVT);
|
||||
|
||||
// It is not possible to fold a sign-extend into the LShr instruction. In this
|
||||
// case emit a sign-extend.
|
||||
if (!IsZExt) {
|
||||
Op0 = EmitIntExt(SrcVT, Op0, RetVT, IsZExt);
|
||||
if (!Op0)
|
||||
return 0;
|
||||
Op0IsKill = true;
|
||||
SrcVT = RetVT;
|
||||
SrcBits = SrcVT.getSizeInBits();
|
||||
IsZExt = true;
|
||||
}
|
||||
|
||||
unsigned ImmR = std::min<unsigned>(SrcBits - 1, Shift);
|
||||
unsigned ImmS = SrcBits - 1;
|
||||
static const unsigned OpcTable[2][2] = {
|
||||
{AArch64::SBFMWri, AArch64::SBFMXri},
|
||||
{AArch64::UBFMWri, AArch64::UBFMXri}
|
||||
};
|
||||
unsigned Opc = OpcTable[IsZExt][Is64Bit];
|
||||
const TargetRegisterClass *RC =
|
||||
(RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
|
||||
return FastEmitInst_rii(Opc, RC, Op0, Op0IsKill, Shift, ImmS);
|
||||
Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
|
||||
if (SrcVT.SimpleTy <= MVT::i32 && RetVT == MVT::i64) {
|
||||
unsigned TmpReg = MRI.createVirtualRegister(RC);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(AArch64::SUBREG_TO_REG), TmpReg)
|
||||
.addImm(0)
|
||||
.addReg(Op0, getKillRegState(Op0IsKill))
|
||||
.addImm(AArch64::sub_32);
|
||||
Op0 = TmpReg;
|
||||
Op0IsKill = true;
|
||||
}
|
||||
return FastEmitInst_rii(Opc, RC, Op0, Op0IsKill, ImmR, ImmS);
|
||||
}
|
||||
|
||||
unsigned AArch64FastISel::emitASR_rr(MVT RetVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
@ -2784,20 +2901,74 @@ unsigned AArch64FastISel::emitASR_rr(MVT RetVT, unsigned Op0Reg, bool Op0IsKill,
|
||||
return ResultReg;
|
||||
}
|
||||
|
||||
unsigned AArch64FastISel::emitASR_ri(MVT RetVT, unsigned Op0, bool Op0IsKill,
|
||||
uint64_t Shift) {
|
||||
unsigned Opc, ImmS;
|
||||
switch (RetVT.SimpleTy) {
|
||||
default: return 0;
|
||||
case MVT::i8: Opc = AArch64::SBFMWri; ImmS = 7; break;
|
||||
case MVT::i16: Opc = AArch64::SBFMWri; ImmS = 15; break;
|
||||
case MVT::i32: Opc = AArch64::SBFMWri; ImmS = 31; break;
|
||||
case MVT::i64: Opc = AArch64::SBFMXri; ImmS = 63; break;
|
||||
}
|
||||
unsigned AArch64FastISel::emitASR_ri(MVT RetVT, MVT SrcVT, unsigned Op0,
|
||||
bool Op0IsKill, uint64_t Shift,
|
||||
bool IsZExt) {
|
||||
assert(RetVT.SimpleTy >= SrcVT.SimpleTy &&
|
||||
"Unexpected source/return type pair.");
|
||||
assert((SrcVT == MVT::i8 || SrcVT == MVT::i16 || SrcVT == MVT::i32 ||
|
||||
SrcVT == MVT::i64) && "Unexpected source value type.");
|
||||
assert((RetVT == MVT::i8 || RetVT == MVT::i16 || RetVT == MVT::i32 ||
|
||||
RetVT == MVT::i64) && "Unexpected return value type.");
|
||||
|
||||
bool Is64Bit = (RetVT == MVT::i64);
|
||||
unsigned RegSize = Is64Bit ? 64 : 32;
|
||||
unsigned DstBits = RetVT.getSizeInBits();
|
||||
unsigned SrcBits = SrcVT.getSizeInBits();
|
||||
|
||||
// Don't deal with undefined shifts.
|
||||
if (Shift >= DstBits)
|
||||
return 0;
|
||||
|
||||
// For immediate shifts we can fold the zero-/sign-extension into the shift.
|
||||
// {S|U}BFM Wd, Wn, #r, #s
|
||||
// Wd<s-r:0> = Wn<s:r> when r <= s
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = ashr i16 %1, 4
|
||||
// Wd<7-4:0> = Wn<7:4>
|
||||
// 0b1111_1111_1111_1111__1111_1111_1111_1010 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0101 sext | zext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_1010 zext
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = ashr i16 %1, 8
|
||||
// Wd<7-7,0> = Wn<7:7>
|
||||
// 0b1111_1111_1111_1111__1111_1111_1111_1111 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 zext
|
||||
|
||||
// %1 = {s|z}ext i8 {0b1010_1010|0b0101_0101} to i16
|
||||
// %2 = ashr i16 %1, 12
|
||||
// Wd<7-7,0> = Wn<7:7> <- clamp r to 7
|
||||
// 0b1111_1111_1111_1111__1111_1111_1111_1111 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 sext
|
||||
// 0b0000_0000_0000_0000__0000_0000_0000_0000 zext
|
||||
|
||||
if (Shift >= SrcBits && IsZExt)
|
||||
return AArch64MaterializeInt(ConstantInt::get(*Context, APInt(RegSize, 0)),
|
||||
RetVT);
|
||||
|
||||
unsigned ImmR = std::min<unsigned>(SrcBits - 1, Shift);
|
||||
unsigned ImmS = SrcBits - 1;
|
||||
static const unsigned OpcTable[2][2] = {
|
||||
{AArch64::SBFMWri, AArch64::SBFMXri},
|
||||
{AArch64::UBFMWri, AArch64::UBFMXri}
|
||||
};
|
||||
unsigned Opc = OpcTable[IsZExt][Is64Bit];
|
||||
const TargetRegisterClass *RC =
|
||||
(RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
|
||||
return FastEmitInst_rii(Opc, RC, Op0, Op0IsKill, Shift, ImmS);
|
||||
Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
|
||||
if (SrcVT.SimpleTy <= MVT::i32 && RetVT == MVT::i64) {
|
||||
unsigned TmpReg = MRI.createVirtualRegister(RC);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(AArch64::SUBREG_TO_REG), TmpReg)
|
||||
.addImm(0)
|
||||
.addReg(Op0, getKillRegState(Op0IsKill))
|
||||
.addImm(AArch64::sub_32);
|
||||
Op0 = TmpReg;
|
||||
Op0IsKill = true;
|
||||
}
|
||||
return FastEmitInst_rii(Opc, RC, Op0, Op0IsKill, ImmR, ImmS);
|
||||
}
|
||||
|
||||
unsigned AArch64FastISel::EmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
|
||||
@ -2988,29 +3159,47 @@ bool AArch64FastISel::SelectMul(const Instruction *I) {
|
||||
}
|
||||
|
||||
bool AArch64FastISel::SelectShift(const Instruction *I) {
|
||||
EVT RetEVT = TLI.getValueType(I->getType(), true);
|
||||
if (!RetEVT.isSimple())
|
||||
MVT RetVT;
|
||||
if (!isLoadStoreTypeLegal(I->getType(), RetVT))
|
||||
return false;
|
||||
MVT RetVT = RetEVT.getSimpleVT();
|
||||
|
||||
unsigned Op0Reg = getRegForValue(I->getOperand(0));
|
||||
if (!Op0Reg)
|
||||
return false;
|
||||
bool Op0IsKill = hasTrivialKill(I->getOperand(0));
|
||||
|
||||
if (const auto *C = dyn_cast<ConstantInt>(I->getOperand(1))) {
|
||||
unsigned ResultReg = 0;
|
||||
uint64_t ShiftVal = C->getZExtValue();
|
||||
MVT SrcVT = RetVT;
|
||||
bool IsZExt = (I->getOpcode() == Instruction::AShr) ? false : true;
|
||||
const Value * Op0 = I->getOperand(0);
|
||||
if (const auto *ZExt = dyn_cast<ZExtInst>(Op0)) {
|
||||
MVT TmpVT;
|
||||
if (isLoadStoreTypeLegal(ZExt->getSrcTy(), TmpVT)) {
|
||||
SrcVT = TmpVT;
|
||||
IsZExt = true;
|
||||
Op0 = ZExt->getOperand(0);
|
||||
}
|
||||
} else if (const auto *SExt = dyn_cast<SExtInst>(Op0)) {
|
||||
MVT TmpVT;
|
||||
if (isLoadStoreTypeLegal(SExt->getSrcTy(), TmpVT)) {
|
||||
SrcVT = TmpVT;
|
||||
IsZExt = false;
|
||||
Op0 = SExt->getOperand(0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned Op0Reg = getRegForValue(Op0);
|
||||
if (!Op0Reg)
|
||||
return false;
|
||||
bool Op0IsKill = hasTrivialKill(Op0);
|
||||
|
||||
switch (I->getOpcode()) {
|
||||
default: llvm_unreachable("Unexpected instruction.");
|
||||
case Instruction::Shl:
|
||||
ResultReg = emitLSL_ri(RetVT, Op0Reg, Op0IsKill, ShiftVal);
|
||||
ResultReg = emitLSL_ri(RetVT, SrcVT, Op0Reg, Op0IsKill, ShiftVal, IsZExt);
|
||||
break;
|
||||
case Instruction::AShr:
|
||||
ResultReg = emitASR_ri(RetVT, Op0Reg, Op0IsKill, ShiftVal);
|
||||
ResultReg = emitASR_ri(RetVT, SrcVT, Op0Reg, Op0IsKill, ShiftVal, IsZExt);
|
||||
break;
|
||||
case Instruction::LShr:
|
||||
ResultReg = emitLSR_ri(RetVT, Op0Reg, Op0IsKill, ShiftVal);
|
||||
ResultReg = emitLSR_ri(RetVT, SrcVT, Op0Reg, Op0IsKill, ShiftVal, IsZExt);
|
||||
break;
|
||||
}
|
||||
if (!ResultReg)
|
||||
@ -3020,6 +3209,11 @@ bool AArch64FastISel::SelectShift(const Instruction *I) {
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned Op0Reg = getRegForValue(I->getOperand(0));
|
||||
if (!Op0Reg)
|
||||
return false;
|
||||
bool Op0IsKill = hasTrivialKill(I->getOperand(0));
|
||||
|
||||
unsigned Op1Reg = getRegForValue(I->getOperand(1));
|
||||
if (!Op1Reg)
|
||||
return false;
|
||||
|
@ -16,6 +16,56 @@ define zeroext i8 @lsl_i8(i8 %a) {
|
||||
ret i8 %1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsl_zext_i8_i16
|
||||
; CHECK: ubfiz {{w[0-9]*}}, {{w[0-9]*}}, #4, #8
|
||||
define zeroext i16 @lsl_zext_i8_i16(i8 %b) {
|
||||
%1 = zext i8 %b to i16
|
||||
%2 = shl i16 %1, 4
|
||||
ret i16 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsl_sext_i8_i16
|
||||
; CHECK: sbfiz {{w[0-9]*}}, {{w[0-9]*}}, #4, #8
|
||||
define signext i16 @lsl_sext_i8_i16(i8 %b) {
|
||||
%1 = sext i8 %b to i16
|
||||
%2 = shl i16 %1, 4
|
||||
ret i16 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsl_zext_i8_i32
|
||||
; CHECK: ubfiz {{w[0-9]*}}, {{w[0-9]*}}, #4, #8
|
||||
define i32 @lsl_zext_i8_i32(i8 %b) {
|
||||
%1 = zext i8 %b to i32
|
||||
%2 = shl i32 %1, 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsl_sext_i8_i32
|
||||
; CHECK: sbfiz {{w[0-9]*}}, {{w[0-9]*}}, #4, #8
|
||||
define i32 @lsl_sext_i8_i32(i8 %b) {
|
||||
%1 = sext i8 %b to i32
|
||||
%2 = shl i32 %1, 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; FIXME: Cannot test this yet, because the target-independent instruction
|
||||
; selector handles this.
|
||||
; CHECK-LABEL: lsl_zext_i8_i64
|
||||
define i64 @lsl_zext_i8_i64(i8 %b) {
|
||||
%1 = zext i8 %b to i64
|
||||
%2 = shl i64 %1, 4
|
||||
ret i64 %2
|
||||
}
|
||||
|
||||
; FIXME: Cannot test this yet, because the target-independent instruction
|
||||
; selector handles this.
|
||||
; CHECK-LABEL: lsl_sext_i8_i64
|
||||
define i64 @lsl_sext_i8_i64(i8 %b) {
|
||||
%1 = sext i8 %b to i64
|
||||
%2 = shl i64 %1, 4
|
||||
ret i64 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lslv_i16
|
||||
; CHECK: and [[REG1:w[0-9]+]], w1, #0xffff
|
||||
; CHECK-NEXT: lsl [[REG2:w[0-9]+]], w0, [[REG1]]
|
||||
@ -32,6 +82,40 @@ define zeroext i16 @lsl_i16(i16 %a) {
|
||||
ret i16 %1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsl_zext_i16_i32
|
||||
; CHECK: ubfiz {{w[0-9]*}}, {{w[0-9]*}}, #8, #16
|
||||
define i32 @lsl_zext_i16_i32(i16 %b) {
|
||||
%1 = zext i16 %b to i32
|
||||
%2 = shl i32 %1, 8
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsl_sext_i16_i32
|
||||
; CHECK: sbfiz {{w[0-9]*}}, {{w[0-9]*}}, #8, #16
|
||||
define i32 @lsl_sext_i16_i32(i16 %b) {
|
||||
%1 = sext i16 %b to i32
|
||||
%2 = shl i32 %1, 8
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; FIXME: Cannot test this yet, because the target-independent instruction
|
||||
; selector handles this.
|
||||
; CHECK-LABEL: lsl_zext_i16_i64
|
||||
define i64 @lsl_zext_i16_i64(i16 %b) {
|
||||
%1 = zext i16 %b to i64
|
||||
%2 = shl i64 %1, 8
|
||||
ret i64 %2
|
||||
}
|
||||
|
||||
; FIXME: Cannot test this yet, because the target-independent instruction
|
||||
; selector handles this.
|
||||
; CHECK-LABEL: lsl_sext_i16_i64
|
||||
define i64 @lsl_sext_i16_i64(i16 %b) {
|
||||
%1 = sext i16 %b to i64
|
||||
%2 = shl i64 %1, 8
|
||||
ret i64 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lslv_i32
|
||||
; CHECK: lsl {{w[0-9]*}}, w0, w1
|
||||
define zeroext i32 @lslv_i32(i32 %a, i32 %b) {
|
||||
@ -46,6 +130,26 @@ define zeroext i32 @lsl_i32(i32 %a) {
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
; FIXME: Cannot test this yet, because the target-independent instruction
|
||||
; selector handles this.
|
||||
; CHECK-LABEL: lsl_zext_i32_i64
|
||||
define i64 @lsl_zext_i32_i64(i32 %b) {
|
||||
%1 = zext i32 %b to i64
|
||||
%2 = shl i64 %1, 16
|
||||
ret i64 %2
|
||||
}
|
||||
|
||||
; FIXME: Cannot test this yet, because the target-independent instruction
|
||||
; selector handles this.
|
||||
; CHECK-LABEL: lsl_sext_i32_i64
|
||||
define i64 @lsl_sext_i32_i64(i32 %b) {
|
||||
%1 = sext i32 %b to i64
|
||||
%2 = shl i64 %1, 16
|
||||
ret i64 %2
|
||||
}
|
||||
|
||||
; FIXME: Cannot test this yet, because the target-independent instruction
|
||||
; selector handles this.
|
||||
; CHECK-LABEL: lslv_i64
|
||||
; CHECK: lsl {{x[0-9]*}}, x0, x1
|
||||
define i64 @lslv_i64(i64 %a, i64 %b) {
|
||||
@ -78,6 +182,40 @@ define zeroext i8 @lsr_i8(i8 %a) {
|
||||
ret i8 %1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsr_zext_i8_i16
|
||||
; CHECK: ubfx {{w[0-9]*}}, {{w[0-9]*}}, #4, #4
|
||||
define zeroext i16 @lsr_zext_i8_i16(i8 %b) {
|
||||
%1 = zext i8 %b to i16
|
||||
%2 = lshr i16 %1, 4
|
||||
ret i16 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsr_sext_i8_i16
|
||||
; CHECK: sxtb [[REG:w[0-9]+]], w0
|
||||
; CHECK-NEXT: ubfx {{w[0-9]*}}, [[REG]], #4, #12
|
||||
define signext i16 @lsr_sext_i8_i16(i8 %b) {
|
||||
%1 = sext i8 %b to i16
|
||||
%2 = lshr i16 %1, 4
|
||||
ret i16 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsr_zext_i8_i32
|
||||
; CHECK: ubfx {{w[0-9]*}}, {{w[0-9]*}}, #4, #4
|
||||
define i32 @lsr_zext_i8_i32(i8 %b) {
|
||||
%1 = zext i8 %b to i32
|
||||
%2 = lshr i32 %1, 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsr_sext_i8_i32
|
||||
; CHECK: sxtb [[REG:w[0-9]+]], w0
|
||||
; CHECK-NEXT: lsr {{w[0-9]*}}, [[REG]], #4
|
||||
define i32 @lsr_sext_i8_i32(i8 %b) {
|
||||
%1 = sext i8 %b to i32
|
||||
%2 = lshr i32 %1, 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: lsrv_i16
|
||||
; CHECK: and [[REG1:w[0-9]+]], w0, #0xffff
|
||||
; CHECK-NEXT: and [[REG2:w[0-9]+]], w1, #0xffff
|
||||
@ -141,6 +279,38 @@ define zeroext i8 @asr_i8(i8 %a) {
|
||||
ret i8 %1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: asr_zext_i8_i16
|
||||
; CHECK: ubfx {{w[0-9]*}}, {{w[0-9]*}}, #4, #4
|
||||
define zeroext i16 @asr_zext_i8_i16(i8 %b) {
|
||||
%1 = zext i8 %b to i16
|
||||
%2 = ashr i16 %1, 4
|
||||
ret i16 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: asr_sext_i8_i16
|
||||
; CHECK: sbfx {{w[0-9]*}}, {{w[0-9]*}}, #4, #4
|
||||
define signext i16 @asr_sext_i8_i16(i8 %b) {
|
||||
%1 = sext i8 %b to i16
|
||||
%2 = ashr i16 %1, 4
|
||||
ret i16 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: asr_zext_i8_i32
|
||||
; CHECK: ubfx {{w[0-9]*}}, {{w[0-9]*}}, #4, #4
|
||||
define i32 @asr_zext_i8_i32(i8 %b) {
|
||||
%1 = zext i8 %b to i32
|
||||
%2 = ashr i32 %1, 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: asr_sext_i8_i32
|
||||
; CHECK: sbfx {{w[0-9]*}}, {{w[0-9]*}}, #4, #4
|
||||
define i32 @asr_sext_i8_i32(i8 %b) {
|
||||
%1 = sext i8 %b to i32
|
||||
%2 = ashr i32 %1, 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: asrv_i16
|
||||
; CHECK: sxth [[REG1:w[0-9]+]], w0
|
||||
; CHECK-NEXT: and [[REG2:w[0-9]+]], w1, #0xffff
|
||||
|
Loading…
x
Reference in New Issue
Block a user