[FastISel][AArch64] Add support for shift-immediate.

Currently the shift-immediate versions are not supported by tblgen and
hopefully this can be later removed, once the required support has been
added to tblgen.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@214345 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Juergen Ributzka 2014-07-30 22:04:22 +00:00
parent 5624046453
commit b0dba10fa6
2 changed files with 190 additions and 1 deletions

View File

@ -109,6 +109,7 @@ private:
bool SelectTrunc(const Instruction *I);
bool SelectIntExt(const Instruction *I);
bool SelectMul(const Instruction *I);
bool SelectShift(const Instruction *I, bool IsLeftShift, bool IsArithmetic);
// Utility helper routines.
bool isTypeLegal(Type *Ty, MVT &VT);
@ -129,6 +130,9 @@ private:
bool UseUnscaled = false);
unsigned EmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt);
unsigned Emiti1Ext(unsigned SrcReg, MVT DestVT, bool isZExt);
unsigned Emit_LSL_ri(MVT RetVT, unsigned Op0, bool Op0IsKill, uint64_t Imm);
unsigned Emit_LSR_ri(MVT RetVT, unsigned Op0, bool Op0IsKill, uint64_t Imm);
unsigned Emit_ASR_ri(MVT RetVT, unsigned Op0, bool Op0IsKill, uint64_t Imm);
unsigned AArch64MaterializeFP(const ConstantFP *CFP, MVT VT);
unsigned AArch64MaterializeGV(const GlobalValue *GV);
@ -1722,6 +1726,60 @@ unsigned AArch64FastISel::Emiti1Ext(unsigned SrcReg, MVT DestVT, bool isZExt) {
}
}
unsigned AArch64FastISel::Emit_LSL_ri(MVT RetVT, unsigned Op0, bool Op0IsKill,
uint64_t Shift) {
unsigned Opc, ImmR, ImmS;
switch (RetVT.SimpleTy) {
default: return 0;
case MVT::i8:
case MVT::i16:
case MVT::i32:
RetVT = 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;
}
return FastEmitInst_rii(Opc, TLI.getRegClassFor(RetVT), Op0, Op0IsKill, ImmR,
ImmS);
}
unsigned AArch64FastISel::Emit_LSR_ri(MVT RetVT, unsigned Op0, bool Op0IsKill,
uint64_t Shift) {
unsigned Opc, ImmS;
switch (RetVT.SimpleTy) {
default: return 0;
case MVT::i8:
case MVT::i16:
case MVT::i32:
RetVT = MVT::i32;
Opc = AArch64::UBFMWri; ImmS = 31; break;
case MVT::i64:
Opc = AArch64::UBFMXri; ImmS = 63; break;
}
return FastEmitInst_rii(Opc, TLI.getRegClassFor(RetVT), Op0, Op0IsKill, Shift,
ImmS);
}
unsigned AArch64FastISel::Emit_ASR_ri(MVT RetVT, unsigned Op0, bool Op0IsKill,
uint64_t Shift) {
unsigned Opc, ImmS;
switch (RetVT.SimpleTy) {
default: return 0;
case MVT::i8:
case MVT::i16:
case MVT::i32:
RetVT = MVT::i32;
Opc = AArch64::SBFMWri; ImmS = 31; break;
case MVT::i64:
Opc = AArch64::SBFMXri; ImmS = 63; break;
}
return FastEmitInst_rii(Opc, TLI.getRegClassFor(RetVT), Op0, Op0IsKill, Shift,
ImmS);
}
unsigned AArch64FastISel::EmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
bool isZExt) {
assert(DestVT != MVT::i1 && "ZeroExt/SignExt an i1?");
@ -1908,6 +1966,40 @@ bool AArch64FastISel::SelectMul(const Instruction *I) {
return true;
}
bool AArch64FastISel::SelectShift(const Instruction *I, bool IsLeftShift,
bool IsArithmetic) {
EVT RetEVT = TLI.getValueType(I->getType(), true);
if (!RetEVT.isSimple())
return false;
MVT RetVT = RetEVT.getSimpleVT();
if (!isa<ConstantInt>(I->getOperand(1)))
return false;
unsigned Op0Reg = getRegForValue(I->getOperand(0));
if (!Op0Reg)
return false;
bool Op0IsKill = hasTrivialKill(I->getOperand(0));
uint64_t ShiftVal = cast<ConstantInt>(I->getOperand(1))->getZExtValue();
unsigned ResultReg;
if (IsLeftShift)
ResultReg = Emit_LSL_ri(RetVT, Op0Reg, Op0IsKill, ShiftVal);
else {
if (IsArithmetic)
ResultReg = Emit_ASR_ri(RetVT, Op0Reg, Op0IsKill, ShiftVal);
else
ResultReg = Emit_LSR_ri(RetVT, Op0Reg, Op0IsKill, ShiftVal);
}
if (!ResultReg)
return false;
UpdateValueMap(I, ResultReg);
return true;
}
bool AArch64FastISel::TargetSelectInstruction(const Instruction *I) {
switch (I->getOpcode()) {
default:
@ -1948,9 +2040,17 @@ bool AArch64FastISel::TargetSelectInstruction(const Instruction *I) {
case Instruction::ZExt:
case Instruction::SExt:
return SelectIntExt(I);
// FIXME: All of these should really be handled by the target-independent
// selector -> improve FastISel tblgen.
case Instruction::Mul:
// FIXME: This really should be handled by the target-independent selector.
return SelectMul(I);
case Instruction::Shl:
return SelectShift(I, /*IsLeftShift=*/true, /*IsArithmetic=*/false);
case Instruction::LShr:
return SelectShift(I, /*IsLeftShift=*/false, /*IsArithmetic=*/false);
case Instruction::AShr:
return SelectShift(I, /*IsLeftShift=*/false, /*IsArithmetic=*/true);
}
return false;
// Silence warnings.

View File

@ -0,0 +1,89 @@
; RUN: llc -fast-isel -fast-isel-abort -mtriple=arm64-apple-darwin < %s | FileCheck %s
; CHECK-LABEL: lsl_i8
; CHECK: lsl {{w[0-9]*}}, {{w[0-9]*}}, #4
define zeroext i8 @lsl_i8(i8 %a) {
%1 = shl i8 %a, 4
ret i8 %1
}
; CHECK-LABEL: lsl_i16
; CHECK: lsl {{w[0-9]*}}, {{w[0-9]*}}, #8
define zeroext i16 @lsl_i16(i16 %a) {
%1 = shl i16 %a, 8
ret i16 %1
}
; CHECK-LABEL: lsl_i32
; CHECK: lsl {{w[0-9]*}}, {{w[0-9]*}}, #16
define zeroext i32 @lsl_i32(i32 %a) {
%1 = shl i32 %a, 16
ret i32 %1
}
; FIXME: This shouldn't use the variable shift version.
; CHECK-LABEL: lsl_i64
; CHECK: lsl {{x[0-9]*}}, {{x[0-9]*}}, {{x[0-9]*}}
define i64 @lsl_i64(i64 %a) {
%1 = shl i64 %a, 32
ret i64 %1
}
; CHECK-LABEL: lsr_i8
; CHECK: lsr {{w[0-9]*}}, {{w[0-9]*}}, #4
define zeroext i8 @lsr_i8(i8 %a) {
%1 = lshr i8 %a, 4
ret i8 %1
}
; CHECK-LABEL: lsr_i16
; CHECK: lsr {{w[0-9]*}}, {{w[0-9]*}}, #8
define zeroext i16 @lsr_i16(i16 %a) {
%1 = lshr i16 %a, 8
ret i16 %1
}
; CHECK-LABEL: lsr_i32
; CHECK: lsr {{w[0-9]*}}, {{w[0-9]*}}, #16
define zeroext i32 @lsr_i32(i32 %a) {
%1 = lshr i32 %a, 16
ret i32 %1
}
; FIXME: This shouldn't use the variable shift version.
; CHECK-LABEL: lsr_i64
; CHECK: lsr {{x[0-9]*}}, {{x[0-9]*}}, {{x[0-9]*}}
define i64 @lsr_i64(i64 %a) {
%1 = lshr i64 %a, 32
ret i64 %1
}
; CHECK-LABEL: asr_i8
; CHECK: asr {{w[0-9]*}}, {{w[0-9]*}}, #4
define zeroext i8 @asr_i8(i8 %a) {
%1 = ashr i8 %a, 4
ret i8 %1
}
; CHECK-LABEL: asr_i16
; CHECK: asr {{w[0-9]*}}, {{w[0-9]*}}, #8
define zeroext i16 @asr_i16(i16 %a) {
%1 = ashr i16 %a, 8
ret i16 %1
}
; CHECK-LABEL: asr_i32
; CHECK: asr {{w[0-9]*}}, {{w[0-9]*}}, #16
define zeroext i32 @asr_i32(i32 %a) {
%1 = ashr i32 %a, 16
ret i32 %1
}
; FIXME: This shouldn't use the variable shift version.
; CHECK-LABEL: asr_i64
; CHECK: asr {{x[0-9]*}}, {{x[0-9]*}}, {{x[0-9]*}}
define i64 @asr_i64(i64 %a) {
%1 = ashr i64 %a, 32
ret i64 %1
}