diff options
| author | Juergen Ributzka <juergen@apple.com> | 2014-08-01 01:25:55 +0000 |
|---|---|---|
| committer | Juergen Ributzka <juergen@apple.com> | 2014-08-01 01:25:55 +0000 |
| commit | 82ecc7ff2a206068be74559134755e036ca9481e (patch) | |
| tree | 33506c910194f476602057019aa2c6ac55278d83 /llvm/lib/Target/AArch64/AArch64FastISel.cpp | |
| parent | 3604bf7fe7a263b9a4f1fbfc284fb205f2a5de33 (diff) | |
| download | bcm5719-llvm-82ecc7ff2a206068be74559134755e036ca9481e.tar.gz bcm5719-llvm-82ecc7ff2a206068be74559134755e036ca9481e.zip | |
[FastISel][AArch64] Fix the immediate versions of the {s|u}{add|sub}.with.overflow intrinsics.
ADDS and SUBS cannot encode negative immediates or immediates larger than 12bit.
This fix checks if the immediate version can be used under this constraints and
if we can convert ADDS to SUBS or vice versa to support negative immediates.
Also update the test cases to test the immediate versions.
llvm-svn: 214470
Diffstat (limited to 'llvm/lib/Target/AArch64/AArch64FastISel.cpp')
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64FastISel.cpp | 97 |
1 files changed, 49 insertions, 48 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp index 8d7bddbea95..bfbf10a1ea1 100644 --- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp +++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp @@ -1759,59 +1759,53 @@ bool AArch64FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { return false; bool LHSIsKill = hasTrivialKill(LHS); - unsigned RHSReg = 0; - bool RHSIsKill = false; - bool UseImm = true; - if (!isa<ConstantInt>(RHS)) { - RHSReg = getRegForValue(RHS); - if (!RHSReg) - return false; - RHSIsKill = hasTrivialKill(RHS); - UseImm = false; + // Check if the immediate can be encoded in the instruction and if we should + // invert the instruction (adds -> subs) to handle negative immediates. + bool UseImm = false; + bool UseInverse = false; + uint64_t Imm = 0; + if (const auto *C = dyn_cast<ConstantInt>(RHS)) { + if (C->isNegative()) { + UseInverse = true; + Imm = -(C->getSExtValue()); + } else + Imm = C->getZExtValue(); + + if (isUInt<12>(Imm)) + UseImm = true; + + UseInverse = UseImm && UseInverse; } + static const unsigned OpcTable[2][2][2] = { + { {AArch64::ADDSWrr, AArch64::ADDSXrr}, + {AArch64::ADDSWri, AArch64::ADDSXri} }, + { {AArch64::SUBSWrr, AArch64::SUBSXrr}, + {AArch64::SUBSWri, AArch64::SUBSXri} } + }; unsigned Opc = 0; unsigned MulReg = 0; + unsigned RHSReg = 0; + bool RHSIsKill = false; AArch64CC::CondCode CC = AArch64CC::Invalid; bool Is64Bit = VT == MVT::i64; switch (II->getIntrinsicID()) { default: llvm_unreachable("Unexpected intrinsic!"); case Intrinsic::sadd_with_overflow: - if (UseImm) - Opc = Is64Bit ? AArch64::ADDSXri : AArch64::ADDSWri; - else - Opc = Is64Bit ? AArch64::ADDSXrr : AArch64::ADDSWrr; - CC = AArch64CC::VS; - break; + Opc = OpcTable[UseInverse][UseImm][Is64Bit]; CC = AArch64CC::VS; break; case Intrinsic::uadd_with_overflow: - if (UseImm) - Opc = Is64Bit ? AArch64::ADDSXri : AArch64::ADDSWri; - else - Opc = Is64Bit ? AArch64::ADDSXrr : AArch64::ADDSWrr; - CC = AArch64CC::HS; - break; + Opc = OpcTable[UseInverse][UseImm][Is64Bit]; CC = AArch64CC::HS; break; case Intrinsic::ssub_with_overflow: - if (UseImm) - Opc = Is64Bit ? AArch64::SUBSXri : AArch64::SUBSWri; - else - Opc = Is64Bit ? AArch64::SUBSXrr : AArch64::SUBSWrr; - CC = AArch64CC::VS; - break; + Opc = OpcTable[!UseInverse][UseImm][Is64Bit]; CC = AArch64CC::VS; break; case Intrinsic::usub_with_overflow: - if (UseImm) - Opc = Is64Bit ? AArch64::SUBSXri : AArch64::SUBSWri; - else - Opc = Is64Bit ? AArch64::SUBSXrr : AArch64::SUBSWrr; - CC = AArch64CC::LO; - break; + Opc = OpcTable[!UseInverse][UseImm][Is64Bit]; CC = AArch64CC::LO; break; case Intrinsic::smul_with_overflow: { CC = AArch64CC::NE; - if (UseImm) { - RHSReg = getRegForValue(RHS); - if (!RHSReg) - return false; - RHSIsKill = hasTrivialKill(RHS); - } + RHSReg = getRegForValue(RHS); + if (!RHSReg) + return false; + RHSIsKill = hasTrivialKill(RHS); + if (VT == MVT::i32) { MulReg = Emit_SMULL_rr(MVT::i64, LHSReg, LHSIsKill, RHSReg, RHSIsKill); unsigned ShiftReg = Emit_LSR_ri(MVT::i64, MulReg, false, 32); @@ -1841,12 +1835,11 @@ bool AArch64FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { } case Intrinsic::umul_with_overflow: { CC = AArch64CC::NE; - if (UseImm) { - RHSReg = getRegForValue(RHS); - if (!RHSReg) - return false; - RHSIsKill = hasTrivialKill(RHS); - } + RHSReg = getRegForValue(RHS); + if (!RHSReg) + return false; + RHSIsKill = hasTrivialKill(RHS); + if (VT == MVT::i32) { MulReg = Emit_UMULL_rr(MVT::i64, LHSReg, LHSIsKill, RHSReg, RHSIsKill); unsigned CmpReg = createResultReg(TLI.getRegClassFor(MVT::i64)); @@ -1872,15 +1865,23 @@ bool AArch64FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { } } + if (!UseImm) { + RHSReg = getRegForValue(RHS); + if (!RHSReg) + return false; + RHSIsKill = hasTrivialKill(RHS); + } + unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT)); if (Opc) { MachineInstrBuilder MIB; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) .addReg(LHSReg, getKillRegState(LHSIsKill)); - if (UseImm) - MIB.addImm(cast<ConstantInt>(RHS)->getZExtValue()); - else + if (UseImm) { + MIB.addImm(Imm); + MIB.addImm(0); + } else MIB.addReg(RHSReg, getKillRegState(RHSIsKill)); } else |

