[llvm] r214345 - [FastISel][AArch64] Add support for shift-immediate.
Juergen Ributzka
juergen at apple.com
Mon Aug 4 15:07:32 PDT 2014
Thanks Chad,
this should be fixed in r214788. I tweaked the parameters to UBFM/SBFM to get the zero-/sign-extension for free.
This way we don’t need to emit a instruction afterwards to mask out the upper bits.
Cheers,
Juergen
On Aug 2, 2014, at 8:39 PM, Chad Rosier <mcrosier at codeaurora.org> wrote:
> Hi Juergen,
> A shift with a non-legal value type (i.e., i8/i16) requires special
> handling. Consider the following testcase:
>
> target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
> target triple = "aarch64--linux-gnu"
>
> @C = constant i8 65, align 4
>
> define i32 @main(i32 %argc, i8** %argv) {
> entry:
> %load = load i8* @C, align 1
> %shl = shl i8 %load, 4
> %ashr = ashr i8 %shl, 4
> %cast = sext i8 %ashr to i32
> ret i32 %cast
> }
>
> Fast-isel produces 65, but the correct value is 1. The first solution
> that comes to mind would be to emit an ANDri with the appropriate mask
> after a left-shift.
>
> When you have a moment, please take a look..
>
> Regards,
> Chad
>
>> Author: ributzka
>> Date: Wed Jul 30 17:04:22 2014
>> New Revision: 214345
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=214345&view=rev
>> Log:
>> [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.
>>
>> Added:
>> llvm/trunk/test/CodeGen/AArch64/fast-isel-shift.ll
>> Modified:
>> llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp
>>
>> Modified: llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp?rev=214345&r1=214344&r2=214345&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp (original)
>> +++ llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp Wed Jul 30 17:04:22
>> 2014
>> @@ -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(unsi
>> }
>> }
>>
>> +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 In
>> 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::TargetSelectInstru
>> 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.
>>
>> Added: llvm/trunk/test/CodeGen/AArch64/fast-isel-shift.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/fast-isel-shift.ll?rev=214345&view=auto
>> ==============================================================================
>> --- llvm/trunk/test/CodeGen/AArch64/fast-isel-shift.ll (added)
>> +++ llvm/trunk/test/CodeGen/AArch64/fast-isel-shift.ll Wed Jul 30 17:04:22
>> 2014
>> @@ -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
>> +}
>> +
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> hosted by The Linux Foundation
>
More information about the llvm-commits
mailing list