From dd7a7107c16fd6ec19dae44e4e830506a8fec168 Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Wed, 3 Sep 2014 01:38:36 +0000 Subject: [PATCH] [FastISel][AArch64] Add target-dependent instruction selection for Add/Sub. There is already target-dependent instruction selection support for Adds/Subs to support compares and the intrinsics with overflow check. This takes advantage of the existing infrastructure to also support Add/Sub, which allows the folding of immediates, sign-/zero-extends, and shifts. This fixes rdar://problem/18207316. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217007 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/AArch64/AArch64FastISel.cpp | 351 ++++++++++----------- test/CodeGen/AArch64/arm64-fast-isel-gv.ll | 28 +- 2 files changed, 178 insertions(+), 201 deletions(-) diff --git a/lib/Target/AArch64/AArch64FastISel.cpp b/lib/Target/AArch64/AArch64FastISel.cpp index 75163807565..87748c9d98e 100644 --- a/lib/Target/AArch64/AArch64FastISel.cpp +++ b/lib/Target/AArch64/AArch64FastISel.cpp @@ -113,6 +113,7 @@ class AArch64FastISel : public FastISel { private: // Selection routines. + bool selectAddSub(const Instruction *I); bool SelectLoad(const Instruction *I); bool SelectStore(const Instruction *I); bool SelectBranch(const Instruction *I); @@ -149,32 +150,25 @@ private: const Value *Cond); // Emit helper routines. - unsigned emitAddsSubs(bool UseAdds, MVT RetVT, const Value *LHS, - const Value *RHS, bool IsZExt = false, - bool WantResult = true); - unsigned emitAddsSubs_rr(bool UseAdds, MVT RetVT, unsigned LHSReg, - bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, - bool WantResult = true); - unsigned emitAddsSubs_ri(bool UseAdds, MVT RetVT, unsigned LHSReg, - bool LHSIsKill, uint64_t Imm, - bool WantResult = true); + unsigned emitAddSub(bool UseAdd, MVT RetVT, const Value *LHS, + const Value *RHS, bool SetFlags = false, + bool WantResult = true, bool IsZExt = false); + unsigned emitAddSub_rr(bool UseAdd, MVT RetVT, unsigned LHSReg, + bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, + bool SetFlags = false, bool WantResult = true); + unsigned emitAddSub_ri(bool UseAdd, MVT RetVT, unsigned LHSReg, + bool LHSIsKill, uint64_t Imm, bool SetFlags = false, + bool WantResult = true); unsigned emitAddSub_rs(bool UseAdd, MVT RetVT, unsigned LHSReg, bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, AArch64_AM::ShiftExtendType ShiftType, - uint64_t ShiftImm, bool WantResult = true); - unsigned emitAddsSubs_rs(bool UseAdds, MVT RetVT, unsigned LHSReg, - bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, - AArch64_AM::ShiftExtendType ShiftType, - uint64_t ShiftImm, bool WantResult = true); + uint64_t ShiftImm, bool SetFlags = false, + bool WantResult = true); unsigned emitAddSub_rx(bool UseAdd, MVT RetVT, unsigned LHSReg, bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, AArch64_AM::ShiftExtendType ExtType, - uint64_t ShiftImm, bool WantResult = true); - - unsigned emitAddsSubs_rx(bool UseAdds, MVT RetVT, unsigned LHSReg, - bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, - AArch64_AM::ShiftExtendType ExtType, - uint64_t ShiftImm, bool WantResult = true); + uint64_t ShiftImm, bool SetFlags = false, + bool WantResult = true); // Emit functions. bool emitCmp(const Value *LHS, const Value *RHS, bool IsZExt); @@ -187,10 +181,12 @@ private: MachineMemOperand *MMO = nullptr); unsigned EmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt); unsigned Emiti1Ext(unsigned SrcReg, MVT DestVT, bool isZExt); - unsigned emitAdds(MVT RetVT, const Value *LHS, const Value *RHS, - bool IsZExt = false, bool WantResult = true); - unsigned emitSubs(MVT RetVT, const Value *LHS, const Value *RHS, - bool IsZExt = false, bool WantResult = true); + unsigned emitAdd(MVT RetVT, const Value *LHS, const Value *RHS, + bool SetFlags = false, bool WantResult = true, + bool IsZExt = false); + unsigned emitSub(MVT RetVT, const Value *LHS, const Value *RHS, + bool SetFlags = false, bool WantResult = true, + bool IsZExt = false); unsigned emitSubs_rr(MVT RetVT, unsigned LHSReg, bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, bool WantResult = true); unsigned emitSubs_rs(MVT RetVT, unsigned LHSReg, bool LHSIsKill, @@ -855,9 +851,9 @@ void AArch64FastISel::AddLoadStoreOperands(Address &Addr, MIB.addMemOperand(MMO); } -unsigned AArch64FastISel::emitAddsSubs(bool UseAdds, MVT RetVT, - const Value *LHS, const Value *RHS, - bool IsZExt, bool WantResult) { +unsigned AArch64FastISel::emitAddSub(bool UseAdd, MVT RetVT, const Value *LHS, + const Value *RHS, bool SetFlags, + bool WantResult, bool IsZExt) { AArch64_AM::ShiftExtendType ExtendType = AArch64_AM::InvalidShiftExtend; bool NeedExtend = false; switch (RetVT.SimpleTy) { @@ -882,11 +878,11 @@ unsigned AArch64FastISel::emitAddsSubs(bool UseAdds, MVT RetVT, RetVT.SimpleTy = std::max(RetVT.SimpleTy, MVT::i32); // Canonicalize immediates to the RHS first. - if (UseAdds && isa(LHS) && !isa(RHS)) + if (UseAdd && isa(LHS) && !isa(RHS)) std::swap(LHS, RHS); // Canonicalize shift immediate to the RHS. - if (UseAdds && isValueAvailable(LHS)) + if (UseAdd && isValueAvailable(LHS)) if (const auto *SI = dyn_cast(LHS)) if (isa(SI->getOperand(1))) if (SI->getOpcode() == Instruction::Shl || @@ -906,11 +902,11 @@ unsigned AArch64FastISel::emitAddsSubs(bool UseAdds, MVT RetVT, if (const auto *C = dyn_cast(RHS)) { uint64_t Imm = IsZExt ? C->getZExtValue() : C->getSExtValue(); if (C->isNegative()) - ResultReg = - emitAddsSubs_ri(!UseAdds, RetVT, LHSReg, LHSIsKill, -Imm, WantResult); + ResultReg = emitAddSub_ri(!UseAdd, RetVT, LHSReg, LHSIsKill, -Imm, + SetFlags, WantResult); else - ResultReg = - emitAddsSubs_ri(UseAdds, RetVT, LHSReg, LHSIsKill, Imm, WantResult); + ResultReg = emitAddSub_ri(UseAdd, RetVT, LHSReg, LHSIsKill, Imm, SetFlags, + WantResult); } if (ResultReg) return ResultReg; @@ -924,16 +920,16 @@ unsigned AArch64FastISel::emitAddsSubs(bool UseAdds, MVT RetVT, if (!RHSReg) return 0; bool RHSIsKill = hasTrivialKill(SI->getOperand(0)); - return emitAddsSubs_rx(UseAdds, RetVT, LHSReg, LHSIsKill, RHSReg, - RHSIsKill, ExtendType, C->getZExtValue(), - WantResult); + return emitAddSub_rx(UseAdd, RetVT, LHSReg, LHSIsKill, RHSReg, + RHSIsKill, ExtendType, C->getZExtValue(), + SetFlags, WantResult); } unsigned RHSReg = getRegForValue(RHS); if (!RHSReg) return 0; bool RHSIsKill = hasTrivialKill(RHS); - return emitAddsSubs_rx(UseAdds, RetVT, LHSReg, LHSIsKill, RHSReg, RHSIsKill, - ExtendType, 0, WantResult); + return emitAddSub_rx(UseAdd, RetVT, LHSReg, LHSIsKill, RHSReg, RHSIsKill, + ExtendType, 0, SetFlags, WantResult); } // Check if the shift can be folded into the instruction. @@ -953,8 +949,9 @@ unsigned AArch64FastISel::emitAddsSubs(bool UseAdds, MVT RetVT, if (!RHSReg) return 0; bool RHSIsKill = hasTrivialKill(SI->getOperand(0)); - return emitAddsSubs_rs(UseAdds, RetVT, LHSReg, LHSIsKill, RHSReg, - RHSIsKill, ShiftType, ShiftVal, WantResult); + return emitAddSub_rs(UseAdd, RetVT, LHSReg, LHSIsKill, RHSReg, + RHSIsKill, ShiftType, ShiftVal, SetFlags, + WantResult); } } } @@ -967,31 +964,34 @@ unsigned AArch64FastISel::emitAddsSubs(bool UseAdds, MVT RetVT, if (NeedExtend) RHSReg = EmitIntExt(SrcVT, RHSReg, RetVT, IsZExt); - return emitAddsSubs_rr(UseAdds, RetVT, LHSReg, LHSIsKill, RHSReg, RHSIsKill, - WantResult); + return emitAddSub_rr(UseAdd, RetVT, LHSReg, LHSIsKill, RHSReg, RHSIsKill, + SetFlags, WantResult); } -unsigned AArch64FastISel::emitAddsSubs_rr(bool UseAdds, MVT RetVT, - unsigned LHSReg, bool LHSIsKill, - unsigned RHSReg, bool RHSIsKill, - bool WantResult) { +unsigned AArch64FastISel::emitAddSub_rr(bool UseAdd, MVT RetVT, unsigned LHSReg, + bool LHSIsKill, unsigned RHSReg, + bool RHSIsKill, bool SetFlags, + bool WantResult) { assert(LHSReg && RHSReg && "Invalid register number."); if (RetVT != MVT::i32 && RetVT != MVT::i64) return 0; - static const unsigned OpcTable[2][2] = { - { AArch64::ADDSWrr, AArch64::ADDSXrr }, - { AArch64::SUBSWrr, AArch64::SUBSXrr } + static const unsigned OpcTable[2][2][2] = { + { { AArch64::SUBWrr, AArch64::SUBXrr }, + { AArch64::ADDWrr, AArch64::ADDXrr } }, + { { AArch64::SUBSWrr, AArch64::SUBSXrr }, + { AArch64::ADDSWrr, AArch64::ADDSXrr } } }; - unsigned Opc = OpcTable[!UseAdds][(RetVT == MVT::i64)]; + bool Is64Bit = RetVT == MVT::i64; + unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit]; + const TargetRegisterClass *RC = + Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; unsigned ResultReg; - if (WantResult) { - const TargetRegisterClass *RC = - (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; + if (WantResult) ResultReg = createResultReg(RC); - } else - ResultReg = (RetVT == MVT::i64) ? AArch64::XZR : AArch64::WZR; + else + ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR; const MCInstrDesc &II = TII.get(Opc); LHSReg = constrainOperandRegClass(II, LHSReg, II.getNumDefs()); @@ -999,13 +999,12 @@ unsigned AArch64FastISel::emitAddsSubs_rr(bool UseAdds, MVT RetVT, BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg) .addReg(LHSReg, getKillRegState(LHSIsKill)) .addReg(RHSReg, getKillRegState(RHSIsKill)); - return ResultReg; } -unsigned AArch64FastISel::emitAddsSubs_ri(bool UseAdds, MVT RetVT, - unsigned LHSReg, bool LHSIsKill, - uint64_t Imm, bool WantResult) { +unsigned AArch64FastISel::emitAddSub_ri(bool UseAdd, MVT RetVT, unsigned LHSReg, + bool LHSIsKill, uint64_t Imm, + bool SetFlags, bool WantResult) { assert(LHSReg && "Invalid register number."); if (RetVT != MVT::i32 && RetVT != MVT::i64) @@ -1020,18 +1019,24 @@ unsigned AArch64FastISel::emitAddsSubs_ri(bool UseAdds, MVT RetVT, } else return 0; - static const unsigned OpcTable[2][2] = { - { AArch64::ADDSWri, AArch64::ADDSXri }, - { AArch64::SUBSWri, AArch64::SUBSXri } + static const unsigned OpcTable[2][2][2] = { + { { AArch64::SUBWri, AArch64::SUBXri }, + { AArch64::ADDWri, AArch64::ADDXri } }, + { { AArch64::SUBSWri, AArch64::SUBSXri }, + { AArch64::ADDSWri, AArch64::ADDSXri } } }; - unsigned Opc = OpcTable[!UseAdds][(RetVT == MVT::i64)]; + bool Is64Bit = RetVT == MVT::i64; + unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit]; + const TargetRegisterClass *RC; + if (SetFlags) + RC = Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; + else + RC = Is64Bit ? &AArch64::GPR64spRegClass : &AArch64::GPR32spRegClass; unsigned ResultReg; - if (WantResult) { - const TargetRegisterClass *RC = - (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; + if (WantResult) ResultReg = createResultReg(RC); - } else - ResultReg = (RetVT == MVT::i64) ? AArch64::XZR : AArch64::WZR; + else + ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR; const MCInstrDesc &II = TII.get(Opc); LHSReg = constrainOperandRegClass(II, LHSReg, II.getNumDefs()); @@ -1039,32 +1044,35 @@ unsigned AArch64FastISel::emitAddsSubs_ri(bool UseAdds, MVT RetVT, .addReg(LHSReg, getKillRegState(LHSIsKill)) .addImm(Imm) .addImm(getShifterImm(AArch64_AM::LSL, ShiftImm)); - return ResultReg; } -unsigned AArch64FastISel::emitAddSub_rs(bool UseAdd, MVT RetVT, - unsigned LHSReg, bool LHSIsKill, - unsigned RHSReg, bool RHSIsKill, +unsigned AArch64FastISel::emitAddSub_rs(bool UseAdd, MVT RetVT, unsigned LHSReg, + bool LHSIsKill, unsigned RHSReg, + bool RHSIsKill, AArch64_AM::ShiftExtendType ShiftType, - uint64_t ShiftImm, bool WantResult) { + uint64_t ShiftImm, bool SetFlags, + bool WantResult) { assert(LHSReg && RHSReg && "Invalid register number."); if (RetVT != MVT::i32 && RetVT != MVT::i64) return 0; - static const unsigned OpcTable[2][2] = { - { AArch64::ADDWrs, AArch64::ADDXrs }, - { AArch64::SUBWrs, AArch64::SUBXrs } + static const unsigned OpcTable[2][2][2] = { + { { AArch64::SUBWrs, AArch64::SUBXrs }, + { AArch64::ADDWrs, AArch64::ADDXrs } }, + { { AArch64::SUBSWrs, AArch64::SUBSXrs }, + { AArch64::ADDSWrs, AArch64::ADDSXrs } } }; - unsigned Opc = OpcTable[!UseAdd][(RetVT == MVT::i64)]; + bool Is64Bit = RetVT == MVT::i64; + unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit]; + const TargetRegisterClass *RC = + Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; unsigned ResultReg; - if (WantResult) { - const TargetRegisterClass *RC = - (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; + if (WantResult) ResultReg = createResultReg(RC); - } else - ResultReg = (RetVT == MVT::i64) ? AArch64::XZR : AArch64::WZR; + else + ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR; const MCInstrDesc &II = TII.get(Opc); LHSReg = constrainOperandRegClass(II, LHSReg, II.getNumDefs()); @@ -1073,66 +1081,38 @@ unsigned AArch64FastISel::emitAddSub_rs(bool UseAdd, MVT RetVT, .addReg(LHSReg, getKillRegState(LHSIsKill)) .addReg(RHSReg, getKillRegState(RHSIsKill)) .addImm(getShifterImm(ShiftType, ShiftImm)); - return ResultReg; } -unsigned AArch64FastISel::emitAddsSubs_rs(bool UseAdds, MVT RetVT, - unsigned LHSReg, bool LHSIsKill, - unsigned RHSReg, bool RHSIsKill, - AArch64_AM::ShiftExtendType ShiftType, - uint64_t ShiftImm, bool WantResult) { - assert(LHSReg && RHSReg && "Invalid register number."); - - if (RetVT != MVT::i32 && RetVT != MVT::i64) - return 0; - - static const unsigned OpcTable[2][2] = { - { AArch64::ADDSWrs, AArch64::ADDSXrs }, - { AArch64::SUBSWrs, AArch64::SUBSXrs } - }; - unsigned Opc = OpcTable[!UseAdds][(RetVT == MVT::i64)]; - unsigned ResultReg; - if (WantResult) { - const TargetRegisterClass *RC = - (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; - ResultReg = createResultReg(RC); - } else - ResultReg = (RetVT == MVT::i64) ? AArch64::XZR : AArch64::WZR; - - const MCInstrDesc &II = TII.get(Opc); - LHSReg = constrainOperandRegClass(II, LHSReg, II.getNumDefs()); - RHSReg = constrainOperandRegClass(II, RHSReg, II.getNumDefs() + 1); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg) - .addReg(LHSReg, getKillRegState(LHSIsKill)) - .addReg(RHSReg, getKillRegState(RHSIsKill)) - .addImm(getShifterImm(ShiftType, ShiftImm)); - - return ResultReg; -} - -unsigned AArch64FastISel::emitAddSub_rx(bool UseAdd, MVT RetVT, - unsigned LHSReg, bool LHSIsKill, - unsigned RHSReg, bool RHSIsKill, +unsigned AArch64FastISel::emitAddSub_rx(bool UseAdd, MVT RetVT, unsigned LHSReg, + bool LHSIsKill, unsigned RHSReg, + bool RHSIsKill, AArch64_AM::ShiftExtendType ExtType, - uint64_t ShiftImm, bool WantResult) { + uint64_t ShiftImm, bool SetFlags, + bool WantResult) { assert(LHSReg && RHSReg && "Invalid register number."); if (RetVT != MVT::i32 && RetVT != MVT::i64) return 0; - static const unsigned OpcTable[2][2] = { - { AArch64::ADDWrx, AArch64::ADDXrx }, - { AArch64::SUBWrx, AArch64::SUBXrx } + static const unsigned OpcTable[2][2][2] = { + { { AArch64::SUBWrx, AArch64::SUBXrx }, + { AArch64::ADDWrx, AArch64::ADDXrx } }, + { { AArch64::SUBSWrx, AArch64::SUBSXrx }, + { AArch64::ADDSWrx, AArch64::ADDSXrx } } }; - unsigned Opc = OpcTable[!UseAdd][(RetVT == MVT::i64)]; + bool Is64Bit = RetVT == MVT::i64; + unsigned Opc = OpcTable[SetFlags][UseAdd][Is64Bit]; + const TargetRegisterClass *RC = nullptr; + if (SetFlags) + RC = Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; + else + RC = Is64Bit ? &AArch64::GPR64spRegClass : &AArch64::GPR32spRegClass; unsigned ResultReg; - if (WantResult) { - const TargetRegisterClass *RC = - (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; + if (WantResult) ResultReg = createResultReg(RC); - } else - ResultReg = (RetVT == MVT::i64) ? AArch64::XZR : AArch64::WZR; + else + ResultReg = Is64Bit ? AArch64::XZR : AArch64::WZR; const MCInstrDesc &II = TII.get(Opc); LHSReg = constrainOperandRegClass(II, LHSReg, II.getNumDefs()); @@ -1141,41 +1121,6 @@ unsigned AArch64FastISel::emitAddSub_rx(bool UseAdd, MVT RetVT, .addReg(LHSReg, getKillRegState(LHSIsKill)) .addReg(RHSReg, getKillRegState(RHSIsKill)) .addImm(getArithExtendImm(ExtType, ShiftImm)); - - return ResultReg; -} - -unsigned AArch64FastISel::emitAddsSubs_rx(bool UseAdds, MVT RetVT, - unsigned LHSReg, bool LHSIsKill, - unsigned RHSReg, bool RHSIsKill, - AArch64_AM::ShiftExtendType ExtType, - uint64_t ShiftImm, bool WantResult) { - assert(LHSReg && RHSReg && "Invalid register number."); - - if (RetVT != MVT::i32 && RetVT != MVT::i64) - return 0; - - static const unsigned OpcTable[2][2] = { - { AArch64::ADDSWrx, AArch64::ADDSXrx }, - { AArch64::SUBSWrx, AArch64::SUBSXrx } - }; - unsigned Opc = OpcTable[!UseAdds][(RetVT == MVT::i64)]; - unsigned ResultReg; - if (WantResult) { - const TargetRegisterClass *RC = - (RetVT == MVT::i64) ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass; - ResultReg = createResultReg(RC); - } else - ResultReg = (RetVT == MVT::i64) ? AArch64::XZR : AArch64::WZR; - - const MCInstrDesc &II = TII.get(Opc); - LHSReg = constrainOperandRegClass(II, LHSReg, II.getNumDefs()); - RHSReg = constrainOperandRegClass(II, RHSReg, II.getNumDefs() + 1); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg) - .addReg(LHSReg, getKillRegState(LHSIsKill)) - .addReg(RHSReg, getKillRegState(RHSIsKill)) - .addImm(getArithExtendImm(ExtType, ShiftImm)); - return ResultReg; } @@ -1203,13 +1148,14 @@ bool AArch64FastISel::emitCmp(const Value *LHS, const Value *RHS, bool IsZExt) { bool AArch64FastISel::emitICmp(MVT RetVT, const Value *LHS, const Value *RHS, bool IsZExt) { - return emitSubs(RetVT, LHS, RHS, IsZExt, /*WantResult=*/false) != 0; + return emitSub(RetVT, LHS, RHS, /*SetFlags=*/true, /*WantResult=*/false, + IsZExt) != 0; } bool AArch64FastISel::emitICmp_ri(MVT RetVT, unsigned LHSReg, bool LHSIsKill, uint64_t Imm) { - return emitAddsSubs_ri(false, RetVT, LHSReg, LHSIsKill, Imm, - /*WantResult=*/false) != 0; + return emitAddSub_ri(/*UseAdd=*/false, RetVT, LHSReg, LHSIsKill, Imm, + /*SetFlags=*/true, /*WantResult=*/false) != 0; } bool AArch64FastISel::emitFCmp(MVT RetVT, const Value *LHS, const Value *RHS) { @@ -1247,23 +1193,23 @@ bool AArch64FastISel::emitFCmp(MVT RetVT, const Value *LHS, const Value *RHS) { return true; } -unsigned AArch64FastISel::emitAdds(MVT RetVT, const Value *LHS, - const Value *RHS, bool IsZExt, - bool WantResult) { - return emitAddsSubs(true, RetVT, LHS, RHS, IsZExt, WantResult); +unsigned AArch64FastISel::emitAdd(MVT RetVT, const Value *LHS, const Value *RHS, + bool SetFlags, bool WantResult, bool IsZExt) { + return emitAddSub(/*UseAdd=*/true, RetVT, LHS, RHS, SetFlags, WantResult, + IsZExt); } -unsigned AArch64FastISel::emitSubs(MVT RetVT, const Value *LHS, - const Value *RHS, bool IsZExt, - bool WantResult) { - return emitAddsSubs(false, RetVT, LHS, RHS, IsZExt, WantResult); +unsigned AArch64FastISel::emitSub(MVT RetVT, const Value *LHS, const Value *RHS, + bool SetFlags, bool WantResult, bool IsZExt) { + return emitAddSub(/*UseAdd=*/false, RetVT, LHS, RHS, SetFlags, WantResult, + IsZExt); } unsigned AArch64FastISel::emitSubs_rr(MVT RetVT, unsigned LHSReg, bool LHSIsKill, unsigned RHSReg, bool RHSIsKill, bool WantResult) { - return emitAddsSubs_rr(false, RetVT, LHSReg, LHSIsKill, RHSReg, RHSIsKill, - WantResult); + return emitAddSub_rr(/*UseAdd=*/false, RetVT, LHSReg, LHSIsKill, RHSReg, + RHSIsKill, /*SetFlags=*/true, WantResult); } unsigned AArch64FastISel::emitSubs_rs(MVT RetVT, unsigned LHSReg, @@ -1271,8 +1217,9 @@ unsigned AArch64FastISel::emitSubs_rs(MVT RetVT, unsigned LHSReg, bool RHSIsKill, AArch64_AM::ShiftExtendType ShiftType, uint64_t ShiftImm, bool WantResult) { - return emitAddsSubs_rs(false, RetVT, LHSReg, LHSIsKill, RHSReg, RHSIsKill, - ShiftType, ShiftImm, WantResult); + return emitAddSub_rs(/*UseAdd=*/false, RetVT, LHSReg, LHSIsKill, RHSReg, + RHSIsKill, ShiftType, ShiftImm, /*SetFlags=*/true, + WantResult); } // FIXME: This should be eventually generated automatically by tblgen. @@ -1376,6 +1323,24 @@ bool AArch64FastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address Addr, return true; } +bool AArch64FastISel::selectAddSub(const Instruction *I) { + MVT VT; + if (!isTypeSupported(I->getType(), VT)) + return false; + + unsigned ResultReg; + if (I->getOpcode() == Instruction::Add) + ResultReg = emitAdd(VT, I->getOperand(0), I->getOperand(1)); + else if (I->getOpcode() == Instruction::Sub) + ResultReg = emitSub(VT, I->getOperand(0), I->getOperand(1)); + else + llvm_unreachable("Unexpected instruction."); + + assert(ResultReg && "Couldn't select Add/Sub instruction."); + UpdateValueMap(I, ResultReg); + return true; +} + bool AArch64FastISel::SelectLoad(const Instruction *I) { MVT VT; // Verify we have a legal type before going any further. Currently, we handle @@ -2512,13 +2477,21 @@ bool AArch64FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { switch (II->getIntrinsicID()) { default: llvm_unreachable("Unexpected intrinsic!"); case Intrinsic::sadd_with_overflow: - ResultReg1 = emitAdds(VT, LHS, RHS); CC = AArch64CC::VS; break; + ResultReg1 = emitAdd(VT, LHS, RHS, /*SetFlags=*/true); + CC = AArch64CC::VS; + break; case Intrinsic::uadd_with_overflow: - ResultReg1 = emitAdds(VT, LHS, RHS); CC = AArch64CC::HS; break; + ResultReg1 = emitAdd(VT, LHS, RHS, /*SetFlags=*/true); + CC = AArch64CC::HS; + break; case Intrinsic::ssub_with_overflow: - ResultReg1 = emitSubs(VT, LHS, RHS); CC = AArch64CC::VS; break; + ResultReg1 = emitSub(VT, LHS, RHS, /*SetFlags=*/true); + CC = AArch64CC::VS; + break; case Intrinsic::usub_with_overflow: - ResultReg1 = emitSubs(VT, LHS, RHS); CC = AArch64CC::LO; break; + ResultReg1 = emitSub(VT, LHS, RHS, /*SetFlags=*/true); + CC = AArch64CC::LO; + break; case Intrinsic::smul_with_overflow: { CC = AArch64CC::NE; unsigned LHSReg = getRegForValue(LHS); @@ -3442,11 +3415,15 @@ bool AArch64FastISel::TargetSelectInstruction(const Instruction *I) { default: return false; case Instruction::Add: - return SelectBinaryOp(I, ISD::ADD); + if (!selectAddSub(I)) + return SelectBinaryOp(I, ISD::ADD); + return true; + case Instruction::Sub: + if (!selectAddSub(I)) + return SelectBinaryOp(I, ISD::SUB); + return true; case Instruction::FAdd: return SelectBinaryOp(I, ISD::FADD); - case Instruction::Sub: - return SelectBinaryOp(I, ISD::SUB); case Instruction::FSub: // FNeg is currently represented in LLVM IR as a special case of FSub. if (BinaryOperator::isFNeg(I)) diff --git a/test/CodeGen/AArch64/arm64-fast-isel-gv.ll b/test/CodeGen/AArch64/arm64-fast-isel-gv.ll index 78a4717c9a0..cd55e964224 100644 --- a/test/CodeGen/AArch64/arm64-fast-isel-gv.ll +++ b/test/CodeGen/AArch64/arm64-fast-isel-gv.ll @@ -6,9 +6,9 @@ define void @Initrand() nounwind { entry: ; CHECK: @Initrand -; CHECK: adrp x[[REG:[0-9]+]], _seed@GOTPAGE -; CHECK: ldr x[[REG2:[0-9]+]], [x[[REG]], _seed@GOTPAGEOFF] -; CHECK: str x{{[0-9]+}}, [x[[REG2]]] +; CHECK: adrp [[REG:x[0-9]+]], _seed@GOTPAGE +; CHECK: ldr [[REG2:x[0-9]+]], {{\[}}[[REG]], _seed@GOTPAGEOFF{{\]}} +; CHECK: str {{x[0-9]+}}, {{\[}}[[REG2]]{{\]}} store i64 74755, i64* @seed, align 8 ret void } @@ -16,17 +16,17 @@ entry: define i32 @Rand() nounwind { entry: ; CHECK: @Rand -; CHECK: adrp x[[REG:[0-9]+]], _seed@GOTPAGE -; CHECK: ldr x[[REG2:[0-9]+]], [x[[REG]], _seed@GOTPAGEOFF] -; CHECK: movz x[[REG3:[0-9]+]], #0x51d -; CHECK: ldr x[[REG4:[0-9]+]], [x[[REG2]]] -; CHECK: mul x[[REG5:[0-9]+]], x[[REG4]], x[[REG3]] -; CHECK: movz x[[REG6:[0-9]+]], #0x3619 -; CHECK: add x[[REG7:[0-9]+]], x[[REG5]], x[[REG6]] -; CHECK: orr x[[REG8:[0-9]+]], xzr, #0xffff -; CHECK: and x[[REG9:[0-9]+]], x[[REG7]], x[[REG8]] -; CHECK: str x[[REG9]], [x[[REG]]] -; CHECK: ldr x{{[0-9]+}}, [x[[REG]]] +; CHECK: adrp [[REG1:x[0-9]+]], _seed@GOTPAGE +; CHECK: ldr [[REG2:x[0-9]+]], {{\[}}[[REG1]], _seed@GOTPAGEOFF{{\]}} +; CHECK: movz [[REG3:x[0-9]+]], #0x3619 +; CHECK: movz [[REG4:x[0-9]+]], #0x51d +; CHECK: ldr [[REG5:x[0-9]+]], {{\[}}[[REG2]]{{\]}} +; CHECK: mul [[REG6:x[0-9]+]], [[REG5]], [[REG4]] +; CHECK: add [[REG7:x[0-9]+]], [[REG6]], [[REG3]] +; CHECK: orr [[REG8:x[0-9]+]], xzr, #0xffff +; CHECK: and [[REG9:x[0-9]+]], [[REG7]], [[REG8]] +; CHECK: str [[REG9]], {{\[}}[[REG1]]{{\]}} +; CHECK: ldr {{x[0-9]+}}, {{\[}}[[REG1]]{{\]}} %0 = load i64* @seed, align 8 %mul = mul nsw i64 %0, 1309 %add = add nsw i64 %mul, 13849