From 14bc04583890b8df825e56bc9e919a190fd8c38f Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Thu, 14 Aug 2014 17:10:54 +0000 Subject: [PATCH] Revert "[FastISel][AArch64] Add support for more addressing modes." This reverts commits r215597, because it might have broken the build bots. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215659 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/AArch64/AArch64FastISel.cpp | 457 +++++++----------- .../AArch64/fast-isel-addressing-modes.ll | 425 ---------------- 2 files changed, 168 insertions(+), 714 deletions(-) delete mode 100644 test/CodeGen/AArch64/fast-isel-addressing-modes.ll diff --git a/lib/Target/AArch64/AArch64FastISel.cpp b/lib/Target/AArch64/AArch64FastISel.cpp index 58a4fd16b61..902a9f1ee07 100644 --- a/lib/Target/AArch64/AArch64FastISel.cpp +++ b/lib/Target/AArch64/AArch64FastISel.cpp @@ -41,6 +41,7 @@ using namespace llvm; namespace { class AArch64FastISel : public FastISel { + class Address { public: typedef enum { @@ -50,23 +51,17 @@ class AArch64FastISel : public FastISel { private: BaseKind Kind; - AArch64_AM::ShiftExtendType ExtType; union { unsigned Reg; int FI; } Base; - unsigned OffsetReg; - unsigned Shift; int64_t Offset; const GlobalValue *GV; public: - Address() : Kind(RegBase), ExtType(AArch64_AM::InvalidShiftExtend), - OffsetReg(0), Shift(0), Offset(0), GV(nullptr) { Base.Reg = 0; } + Address() : Kind(RegBase), Offset(0), GV(nullptr) { Base.Reg = 0; } void setKind(BaseKind K) { Kind = K; } BaseKind getKind() const { return Kind; } - void setExtendType(AArch64_AM::ShiftExtendType E) { ExtType = E; } - AArch64_AM::ShiftExtendType getExtendType() const { return ExtType; } bool isRegBase() const { return Kind == RegBase; } bool isFIBase() const { return Kind == FrameIndexBase; } void setReg(unsigned Reg) { @@ -77,14 +72,6 @@ class AArch64FastISel : public FastISel { assert(isRegBase() && "Invalid base register access!"); return Base.Reg; } - void setOffsetReg(unsigned Reg) { - assert(isRegBase() && "Invalid offset register access!"); - OffsetReg = Reg; - } - unsigned getOffsetReg() const { - assert(isRegBase() && "Invalid offset register access!"); - return OffsetReg; - } void setFI(unsigned FI) { assert(isFIBase() && "Invalid base frame index access!"); Base.FI = FI; @@ -95,11 +82,11 @@ class AArch64FastISel : public FastISel { } void setOffset(int64_t O) { Offset = O; } int64_t getOffset() { return Offset; } - void setShift(unsigned S) { Shift = S; } - unsigned getShift() { return Shift; } void setGlobalValue(const GlobalValue *G) { GV = G; } const GlobalValue *getGlobalValue() { return GV; } + + bool isValid() { return isFIBase() || (isRegBase() && getReg() != 0); } }; /// Subtarget - Keep a pointer to the AArch64Subtarget around so that we can @@ -134,12 +121,13 @@ private: // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadStoreTypeLegal(Type *Ty, MVT &VT); - bool ComputeAddress(const Value *Obj, Address &Addr, Type *Ty = nullptr); + bool ComputeAddress(const Value *Obj, Address &Addr); bool ComputeCallAddress(const Value *V, Address &Addr); - bool SimplifyAddress(Address &Addr, MVT VT); + bool SimplifyAddress(Address &Addr, MVT VT, int64_t ScaleFactor, + bool UseUnscaled); void AddLoadStoreOperands(Address &Addr, const MachineInstrBuilder &MIB, - unsigned Flags, unsigned ScaleFactor, - MachineMemOperand *MMO); + unsigned Flags, MachineMemOperand *MMO, + bool UseUnscaled); bool IsMemCpySmall(uint64_t Len, unsigned Alignment); bool TryEmitSmallMemCpy(Address Dest, Address Src, uint64_t Len, unsigned Alignment); @@ -149,9 +137,9 @@ private: // Emit functions. bool EmitCmp(Value *Src1Value, Value *Src2Value, bool isZExt); bool EmitLoad(MVT VT, unsigned &ResultReg, Address Addr, - MachineMemOperand *MMO = nullptr); + MachineMemOperand *MMO = nullptr, bool UseUnscaled = false); bool EmitStore(MVT VT, unsigned SrcReg, Address Addr, - MachineMemOperand *MMO = nullptr); + MachineMemOperand *MMO = nullptr, bool UseUnscaled = false); unsigned EmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt); unsigned Emiti1Ext(unsigned SrcReg, MVT DestVT, bool isZExt); unsigned Emit_MUL_rr(MVT RetVT, unsigned Op0, bool Op0IsKill, @@ -349,8 +337,7 @@ unsigned AArch64FastISel::TargetMaterializeConstant(const Constant *C) { } // Computes the address to get to an object. -bool AArch64FastISel::ComputeAddress(const Value *Obj, Address &Addr, Type *Ty) -{ +bool AArch64FastISel::ComputeAddress(const Value *Obj, Address &Addr) { const User *U = nullptr; unsigned Opcode = Instruction::UserOp1; if (const Instruction *I = dyn_cast(Obj)) { @@ -377,18 +364,18 @@ bool AArch64FastISel::ComputeAddress(const Value *Obj, Address &Addr, Type *Ty) break; case Instruction::BitCast: { // Look through bitcasts. - return ComputeAddress(U->getOperand(0), Addr, Ty); + return ComputeAddress(U->getOperand(0), Addr); } case Instruction::IntToPtr: { // Look past no-op inttoptrs. if (TLI.getValueType(U->getOperand(0)->getType()) == TLI.getPointerTy()) - return ComputeAddress(U->getOperand(0), Addr, Ty); + return ComputeAddress(U->getOperand(0), Addr); break; } case Instruction::PtrToInt: { // Look past no-op ptrtoints. if (TLI.getValueType(U->getType()) == TLI.getPointerTy()) - return ComputeAddress(U->getOperand(0), Addr, Ty); + return ComputeAddress(U->getOperand(0), Addr); break; } case Instruction::GetElementPtr: { @@ -430,7 +417,7 @@ bool AArch64FastISel::ComputeAddress(const Value *Obj, Address &Addr, Type *Ty) // Try to grab the base operand now. Addr.setOffset(TmpOffset); - if (ComputeAddress(U->getOperand(0), Addr, Ty)) + if (ComputeAddress(U->getOperand(0), Addr)) return true; // We failed, restore everything and try the other options. @@ -450,86 +437,19 @@ bool AArch64FastISel::ComputeAddress(const Value *Obj, Address &Addr, Type *Ty) } break; } - case Instruction::Add: { + case Instruction::Add: // Adds of constants are common and easy enough. - const Value *LHS = U->getOperand(0); - const Value *RHS = U->getOperand(1); - - if (isa(LHS)) - std::swap(LHS, RHS); - - if (const ConstantInt *CI = dyn_cast(RHS)) { + if (const ConstantInt *CI = dyn_cast(U->getOperand(1))) { Addr.setOffset(Addr.getOffset() + (uint64_t)CI->getSExtValue()); - return ComputeAddress(LHS, Addr, Ty); - } - - Address Backup = Addr; - if (ComputeAddress(LHS, Addr, Ty) && ComputeAddress(RHS, Addr, Ty)) - return true; - Addr = Backup; - - break; - } - case Instruction::Shl: - if (Addr.getOffsetReg()) - break; - - if (const auto *CI = dyn_cast(U->getOperand(1))) { - unsigned Val = CI->getZExtValue(); - if (Val < 1 || Val > 3) - break; - - uint64_t NumBytes = 0; - if (Ty && Ty->isSized()) { - uint64_t NumBits = DL.getTypeSizeInBits(Ty); - NumBytes = NumBits / 8; - if (!isPowerOf2_64(NumBits)) - NumBytes = 0; - } - - if (NumBytes != (1ULL << Val)) - break; - - Addr.setShift(Val); - Addr.setExtendType(AArch64_AM::LSL); - - if (const auto *I = dyn_cast(U->getOperand(0))) - if (FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) - U = I; - - if (const auto *ZE = dyn_cast(U)) - if (ZE->getOperand(0)->getType()->isIntegerTy(32)) - Addr.setExtendType(AArch64_AM::UXTW); - - if (const auto *SE = dyn_cast(U)) - if (SE->getOperand(0)->getType()->isIntegerTy(32)) - Addr.setExtendType(AArch64_AM::SXTW); - - unsigned Reg = getRegForValue(U->getOperand(0)); - if (!Reg) - return false; - Addr.setOffsetReg(Reg); - return true; + return ComputeAddress(U->getOperand(0), Addr); } break; } - if (Addr.getReg()) { - if (!Addr.getOffsetReg()) { - unsigned Reg = getRegForValue(Obj); - if (!Reg) - return false; - Addr.setOffsetReg(Reg); - return true; - } - return false; - } - - unsigned Reg = getRegForValue(Obj); - if (!Reg) - return false; - Addr.setReg(Reg); - return true; + // Try to get this in a register if nothing else has worked. + if (!Addr.isValid()) + Addr.setReg(getRegForValue(Obj)); + return Addr.isValid(); } bool AArch64FastISel::ComputeCallAddress(const Value *V, Address &Addr) { @@ -611,80 +531,50 @@ bool AArch64FastISel::isLoadStoreTypeLegal(Type *Ty, MVT &VT) { return false; } -bool AArch64FastISel::SimplifyAddress(Address &Addr, MVT VT) { - unsigned ScaleFactor; +bool AArch64FastISel::SimplifyAddress(Address &Addr, MVT VT, + int64_t ScaleFactor, bool UseUnscaled) { + bool needsLowering = false; + int64_t Offset = Addr.getOffset(); switch (VT.SimpleTy) { - default: return false; - case MVT::i1: // fall-through - case MVT::i8: ScaleFactor = 1; break; - case MVT::i16: ScaleFactor = 2; break; - case MVT::i32: // fall-through - case MVT::f32: ScaleFactor = 4; break; - case MVT::i64: // fall-through - case MVT::f64: ScaleFactor = 8; break; + default: + return false; + case MVT::i1: + case MVT::i8: + case MVT::i16: + case MVT::i32: + case MVT::i64: + case MVT::f32: + case MVT::f64: + if (!UseUnscaled) + // Using scaled, 12-bit, unsigned immediate offsets. + needsLowering = ((Offset & 0xfff) != Offset); + else + // Using unscaled, 9-bit, signed immediate offsets. + needsLowering = (Offset > 256 || Offset < -256); + break; } - bool ImmediateOffsetNeedsLowering = false; - bool RegisterOffsetNeedsLowering = false; - int64_t Offset = Addr.getOffset(); - if (((Offset < 0) || (Offset & (ScaleFactor - 1))) && !isInt<9>(Offset)) - ImmediateOffsetNeedsLowering = true; - else if (Offset > 0 && !(Offset & (ScaleFactor - 1)) && - !isUInt<12>(Offset / ScaleFactor)) - ImmediateOffsetNeedsLowering = true; - - // Cannot encode an offset register and an immediate offset in the same - // instruction. Fold the immediate offset into the load/store instruction and - // emit an additonal add to take care of the offset register. - if (!ImmediateOffsetNeedsLowering && Addr.getOffset() && Addr.isRegBase() && - Addr.getOffsetReg()) - RegisterOffsetNeedsLowering = true; - - // If this is a stack pointer and the offset needs to be simplified then put + //If this is a stack pointer and the offset needs to be simplified then put // the alloca address into a register, set the base type back to register and // continue. This should almost never happen. - if (ImmediateOffsetNeedsLowering && Addr.isFIBase()) { + if (needsLowering && Addr.getKind() == Address::FrameIndexBase) { unsigned ResultReg = createResultReg(&AArch64::GPR64RegClass); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AArch64::ADDXri), ResultReg) - .addFrameIndex(Addr.getFI()) - .addImm(0) - .addImm(0); + .addFrameIndex(Addr.getFI()) + .addImm(0) + .addImm(0); Addr.setKind(Address::RegBase); Addr.setReg(ResultReg); } - if (RegisterOffsetNeedsLowering) { - unsigned ResultReg = 0; - if (Addr.getReg()) { - ResultReg = createResultReg(&AArch64::GPR64RegClass); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(AArch64::ADDXrs), ResultReg) - .addReg(Addr.getReg()) - .addReg(Addr.getOffsetReg()) - .addImm(Addr.getShift()); - } else - ResultReg = Emit_LSL_ri(MVT::i64, Addr.getOffsetReg(), - /*Op0IsKill=*/false, Addr.getShift()); - if (!ResultReg) - return false; - - Addr.setReg(ResultReg); - Addr.setOffsetReg(0); - Addr.setShift(0); - } - // Since the offset is too large for the load/store instruction get the // reg+offset into a register. - if (ImmediateOffsetNeedsLowering) { - unsigned ResultReg = 0; - if (Addr.getReg()) - ResultReg = FastEmit_ri_(MVT::i64, ISD::ADD, Addr.getReg(), - /*IsKill=*/false, Offset, MVT::i64); - else - ResultReg = FastEmit_i(MVT::i64, MVT::i64, ISD::Constant, Offset); - - if (!ResultReg) + if (needsLowering) { + uint64_t UnscaledOffset = Addr.getOffset() * ScaleFactor; + unsigned ResultReg = FastEmit_ri_(MVT::i64, ISD::ADD, Addr.getReg(), false, + UnscaledOffset, MVT::i64); + if (ResultReg == 0) return false; Addr.setReg(ResultReg); Addr.setOffset(0); @@ -695,11 +585,11 @@ bool AArch64FastISel::SimplifyAddress(Address &Addr, MVT VT) { void AArch64FastISel::AddLoadStoreOperands(Address &Addr, const MachineInstrBuilder &MIB, unsigned Flags, - unsigned ScaleFactor, - MachineMemOperand *MMO) { - int64_t Offset = Addr.getOffset() / ScaleFactor; + MachineMemOperand *MMO, + bool UseUnscaled) { + int64_t Offset = Addr.getOffset(); // Frame base works a bit differently. Handle it separately. - if (Addr.isFIBase()) { + if (Addr.getKind() == Address::FrameIndexBase) { int FI = Addr.getFI(); // FIXME: We shouldn't be using getObjectSize/getObjectAlignment. The size // and alignment should be based on the VT. @@ -709,19 +599,9 @@ void AArch64FastISel::AddLoadStoreOperands(Address &Addr, // Now add the rest of the operands. MIB.addFrameIndex(FI).addImm(Offset); } else { - assert(Addr.isRegBase() && "Unexpected address kind."); - if (Addr.getOffsetReg()) { - assert(Addr.getOffset() == 0 && "Unexpected offset"); - bool IsSigned = Addr.getExtendType() == AArch64_AM::SXTW || - Addr.getExtendType() == AArch64_AM::SXTX; - MIB.addReg(Addr.getReg()); - MIB.addReg(Addr.getOffsetReg()); - MIB.addImm(IsSigned); - MIB.addImm(Addr.getShift() != 0); - } else { - MIB.addReg(Addr.getReg()); - MIB.addImm(Offset); - } + // Now add the rest of the operands. + MIB.addReg(Addr.getReg()); + MIB.addImm(Offset); } if (MMO) @@ -729,68 +609,72 @@ void AArch64FastISel::AddLoadStoreOperands(Address &Addr, } bool AArch64FastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address Addr, - MachineMemOperand *MMO) { - // Simplify this down to something we can handle. - if (!SimplifyAddress(Addr, VT)) - return false; - - unsigned ScaleFactor; - switch (VT.SimpleTy) { - default: llvm_unreachable("Unexpected value type."); - case MVT::i1: // fall-through - case MVT::i8: ScaleFactor = 1; break; - case MVT::i16: ScaleFactor = 2; break; - case MVT::i32: // fall-through - case MVT::f32: ScaleFactor = 4; break; - case MVT::i64: // fall-through - case MVT::f64: ScaleFactor = 8; break; - } - + MachineMemOperand *MMO, bool UseUnscaled) { // Negative offsets require unscaled, 9-bit, signed immediate offsets. // Otherwise, we try using scaled, 12-bit, unsigned immediate offsets. - bool UseScaled = true; - if ((Addr.getOffset() < 0) || (Addr.getOffset() & (ScaleFactor - 1))) { - UseScaled = false; - ScaleFactor = 1; - } - - static const unsigned OpcTable[4][6] = { - { AArch64::LDURBBi, AArch64::LDURHHi, AArch64::LDURWi, AArch64::LDURXi, - AArch64::LDURSi, AArch64::LDURDi }, - { AArch64::LDRBBui, AArch64::LDRHHui, AArch64::LDRWui, AArch64::LDRXui, - AArch64::LDRSui, AArch64::LDRDui }, - { AArch64::LDRBBroX, AArch64::LDRHHroX, AArch64::LDRWroX, AArch64::LDRXroX, - AArch64::LDRSroX, AArch64::LDRDroX }, - { AArch64::LDRBBroW, AArch64::LDRHHroW, AArch64::LDRWroW, AArch64::LDRXroW, - AArch64::LDRSroW, AArch64::LDRDroW } - }; + if (!UseUnscaled && Addr.getOffset() < 0) + UseUnscaled = true; unsigned Opc; const TargetRegisterClass *RC; bool VTIsi1 = false; - bool UseRegOffset = Addr.isRegBase() && !Addr.getOffset() && Addr.getReg() && - Addr.getOffsetReg(); - unsigned Idx = UseRegOffset ? 2 : UseScaled ? 1 : 0; - if (Addr.getExtendType() == AArch64_AM::UXTW || - Addr.getExtendType() == AArch64_AM::SXTW) - Idx++; - + int64_t ScaleFactor = 0; switch (VT.SimpleTy) { - default: llvm_unreachable("Unexpected value type."); - case MVT::i1: VTIsi1 = true; // Intentional fall-through. - case MVT::i8: Opc = OpcTable[Idx][0]; RC = &AArch64::GPR32RegClass; break; - case MVT::i16: Opc = OpcTable[Idx][1]; RC = &AArch64::GPR32RegClass; break; - case MVT::i32: Opc = OpcTable[Idx][2]; RC = &AArch64::GPR32RegClass; break; - case MVT::i64: Opc = OpcTable[Idx][3]; RC = &AArch64::GPR64RegClass; break; - case MVT::f32: Opc = OpcTable[Idx][4]; RC = &AArch64::FPR32RegClass; break; - case MVT::f64: Opc = OpcTable[Idx][5]; RC = &AArch64::FPR64RegClass; break; + default: + return false; + case MVT::i1: + VTIsi1 = true; + // Intentional fall-through. + case MVT::i8: + Opc = UseUnscaled ? AArch64::LDURBBi : AArch64::LDRBBui; + RC = &AArch64::GPR32RegClass; + ScaleFactor = 1; + break; + case MVT::i16: + Opc = UseUnscaled ? AArch64::LDURHHi : AArch64::LDRHHui; + RC = &AArch64::GPR32RegClass; + ScaleFactor = 2; + break; + case MVT::i32: + Opc = UseUnscaled ? AArch64::LDURWi : AArch64::LDRWui; + RC = &AArch64::GPR32RegClass; + ScaleFactor = 4; + break; + case MVT::i64: + Opc = UseUnscaled ? AArch64::LDURXi : AArch64::LDRXui; + RC = &AArch64::GPR64RegClass; + ScaleFactor = 8; + break; + case MVT::f32: + Opc = UseUnscaled ? AArch64::LDURSi : AArch64::LDRSui; + RC = TLI.getRegClassFor(VT); + ScaleFactor = 4; + break; + case MVT::f64: + Opc = UseUnscaled ? AArch64::LDURDi : AArch64::LDRDui; + RC = TLI.getRegClassFor(VT); + ScaleFactor = 8; + break; } + // Scale the offset. + if (!UseUnscaled) { + int64_t Offset = Addr.getOffset(); + if (Offset & (ScaleFactor - 1)) + // Retry using an unscaled, 9-bit, signed immediate offset. + return EmitLoad(VT, ResultReg, Addr, MMO, /*UseUnscaled*/ true); + + Addr.setOffset(Offset / ScaleFactor); + } + + // Simplify this down to something we can handle. + if (!SimplifyAddress(Addr, VT, UseUnscaled ? 1 : ScaleFactor, UseUnscaled)) + return false; // Create the base instruction, then add the operands. ResultReg = createResultReg(RC); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg); - AddLoadStoreOperands(Addr, MIB, MachineMemOperand::MOLoad, ScaleFactor, MMO); + AddLoadStoreOperands(Addr, MIB, MachineMemOperand::MOLoad, MMO, UseUnscaled); // Loading an i1 requires special handling. if (VTIsi1) { @@ -798,8 +682,8 @@ bool AArch64FastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address Addr, unsigned ANDReg = createResultReg(&AArch64::GPR32spRegClass); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AArch64::ANDWri), ANDReg) - .addReg(ResultReg) - .addImm(AArch64_AM::encodeLogicalImmediate(1, 32)); + .addReg(ResultReg) + .addImm(AArch64_AM::encodeLogicalImmediate(1, 32)); ResultReg = ANDReg; } return true; @@ -815,7 +699,7 @@ bool AArch64FastISel::SelectLoad(const Instruction *I) { // See if we can handle this address. Address Addr; - if (!ComputeAddress(I->getOperand(0), Addr, I->getType())) + if (!ComputeAddress(I->getOperand(0), Addr)) return false; unsigned ResultReg; @@ -827,63 +711,59 @@ bool AArch64FastISel::SelectLoad(const Instruction *I) { } bool AArch64FastISel::EmitStore(MVT VT, unsigned SrcReg, Address Addr, - MachineMemOperand *MMO) { - // Simplify this down to something we can handle. - if (!SimplifyAddress(Addr, VT)) - return false; - - unsigned ScaleFactor; - switch (VT.SimpleTy) { - default: llvm_unreachable("Unexpected value type."); - case MVT::i1: // fall-through - case MVT::i8: ScaleFactor = 1; break; - case MVT::i16: ScaleFactor = 2; break; - case MVT::i32: // fall-through - case MVT::f32: ScaleFactor = 4; break; - case MVT::i64: // fall-through - case MVT::f64: ScaleFactor = 8; break; - } - + MachineMemOperand *MMO, bool UseUnscaled) { // Negative offsets require unscaled, 9-bit, signed immediate offsets. // Otherwise, we try using scaled, 12-bit, unsigned immediate offsets. - bool UseScaled = true; - if ((Addr.getOffset() < 0) || (Addr.getOffset() & (ScaleFactor - 1))) { - UseScaled = false; - ScaleFactor = 1; - } + if (!UseUnscaled && Addr.getOffset() < 0) + UseUnscaled = true; - - static const unsigned OpcTable[4][6] = { - { AArch64::STURBBi, AArch64::STURHHi, AArch64::STURWi, AArch64::STURXi, - AArch64::STURSi, AArch64::STURDi }, - { AArch64::STRBBui, AArch64::STRHHui, AArch64::STRWui, AArch64::STRXui, - AArch64::STRSui, AArch64::STRDui }, - { AArch64::STRBBroX, AArch64::STRHHroX, AArch64::STRWroX, AArch64::STRXroX, - AArch64::STRSroX, AArch64::STRDroX }, - { AArch64::STRBBroW, AArch64::STRHHroW, AArch64::STRWroW, AArch64::STRXroW, - AArch64::STRSroW, AArch64::STRDroW } - - }; - - unsigned Opc; + unsigned StrOpc; bool VTIsi1 = false; - bool UseRegOffset = Addr.isRegBase() && !Addr.getOffset() && Addr.getReg() && - Addr.getOffsetReg(); - unsigned Idx = UseRegOffset ? 2 : UseScaled ? 1 : 0; - if (Addr.getExtendType() == AArch64_AM::UXTW || - Addr.getExtendType() == AArch64_AM::SXTW) - Idx++; - + int64_t ScaleFactor = 0; + // Using scaled, 12-bit, unsigned immediate offsets. switch (VT.SimpleTy) { - default: llvm_unreachable("Unexpected value type."); - case MVT::i1: VTIsi1 = true; - case MVT::i8: Opc = OpcTable[Idx][0]; break; - case MVT::i16: Opc = OpcTable[Idx][1]; break; - case MVT::i32: Opc = OpcTable[Idx][2]; break; - case MVT::i64: Opc = OpcTable[Idx][3]; break; - case MVT::f32: Opc = OpcTable[Idx][4]; break; - case MVT::f64: Opc = OpcTable[Idx][5]; break; + default: + return false; + case MVT::i1: + VTIsi1 = true; + case MVT::i8: + StrOpc = UseUnscaled ? AArch64::STURBBi : AArch64::STRBBui; + ScaleFactor = 1; + break; + case MVT::i16: + StrOpc = UseUnscaled ? AArch64::STURHHi : AArch64::STRHHui; + ScaleFactor = 2; + break; + case MVT::i32: + StrOpc = UseUnscaled ? AArch64::STURWi : AArch64::STRWui; + ScaleFactor = 4; + break; + case MVT::i64: + StrOpc = UseUnscaled ? AArch64::STURXi : AArch64::STRXui; + ScaleFactor = 8; + break; + case MVT::f32: + StrOpc = UseUnscaled ? AArch64::STURSi : AArch64::STRSui; + ScaleFactor = 4; + break; + case MVT::f64: + StrOpc = UseUnscaled ? AArch64::STURDi : AArch64::STRDui; + ScaleFactor = 8; + break; } + // Scale the offset. + if (!UseUnscaled) { + int64_t Offset = Addr.getOffset(); + if (Offset & (ScaleFactor - 1)) + // Retry using an unscaled, 9-bit, signed immediate offset. + return EmitStore(VT, SrcReg, Addr, MMO, /*UseUnscaled*/ true); + + Addr.setOffset(Offset / ScaleFactor); + } + + // Simplify this down to something we can handle. + if (!SimplifyAddress(Addr, VT, UseUnscaled ? 1 : ScaleFactor, UseUnscaled)) + return false; // Storing an i1 requires special handling. if (VTIsi1) { @@ -891,15 +771,14 @@ bool AArch64FastISel::EmitStore(MVT VT, unsigned SrcReg, Address Addr, unsigned ANDReg = createResultReg(&AArch64::GPR32spRegClass); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AArch64::ANDWri), ANDReg) - .addReg(SrcReg) - .addImm(AArch64_AM::encodeLogicalImmediate(1, 32)); + .addReg(SrcReg) + .addImm(AArch64_AM::encodeLogicalImmediate(1, 32)); SrcReg = ANDReg; } // Create the base instruction, then add the operands. MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(Opc)) - .addReg(SrcReg); - AddLoadStoreOperands(Addr, MIB, MachineMemOperand::MOStore, ScaleFactor, MMO); + TII.get(StrOpc)).addReg(SrcReg); + AddLoadStoreOperands(Addr, MIB, MachineMemOperand::MOStore, MMO, UseUnscaled); return true; } @@ -921,7 +800,7 @@ bool AArch64FastISel::SelectStore(const Instruction *I) { // See if we can handle this address. Address Addr; - if (!ComputeAddress(I->getOperand(1), Addr, I->getOperand(0)->getType())) + if (!ComputeAddress(I->getOperand(1), Addr)) return false; if (!EmitStore(VT, SrcReg, Addr, createMachineMemOperandFor(I))) diff --git a/test/CodeGen/AArch64/fast-isel-addressing-modes.ll b/test/CodeGen/AArch64/fast-isel-addressing-modes.ll deleted file mode 100644 index 11b95f92bf2..00000000000 --- a/test/CodeGen/AArch64/fast-isel-addressing-modes.ll +++ /dev/null @@ -1,425 +0,0 @@ -; RUN: llc -mtriple=aarch64-apple-darwin < %s | FileCheck %s --check-prefix=CHECK --check-prefix=SDAG -; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel -fast-isel-abort < %s | FileCheck %s --check-prefix=CHECK --check-prefix=FAST - -; Load / Store Base Register only -define zeroext i1 @load_breg_i1(i1* %a) { -; CHECK-LABEL: load_breg_i1 -; CHECK: ldrb {{w[0-9]+}}, [x0] - %1 = load i1* %a - ret i1 %1 -} - -define zeroext i8 @load_breg_i8(i8* %a) { -; CHECK-LABEL: load_breg_i8 -; CHECK: ldrb {{w[0-9]+}}, [x0] - %1 = load i8* %a - ret i8 %1 -} - -define zeroext i16 @load_breg_i16(i16* %a) { -; CHECK-LABEL: load_breg_i16 -; CHECK: ldrh {{w[0-9]+}}, [x0] - %1 = load i16* %a - ret i16 %1 -} - -define i32 @load_breg_i32(i32* %a) { -; CHECK-LABEL: load_breg_i32 -; CHECK: ldr {{w[0-9]+}}, [x0] - %1 = load i32* %a - ret i32 %1 -} - -define i64 @load_breg_i64(i64* %a) { -; CHECK-LABEL: load_breg_i64 -; CHECK: ldr {{x[0-9]+}}, [x0] - %1 = load i64* %a - ret i64 %1 -} - -define float @load_breg_f32(float* %a) { -; CHECK-LABEL: load_breg_f32 -; CHECK: ldr {{s[0-9]+}}, [x0] - %1 = load float* %a - ret float %1 -} - -define double @load_breg_f64(double* %a) { -; CHECK-LABEL: load_breg_f64 -; CHECK: ldr {{d[0-9]+}}, [x0] - %1 = load double* %a - ret double %1 -} - -define void @store_breg_i1(i1* %a) { -; CHECK-LABEL: store_breg_i1 -; CHECK: strb {{wzr|w[0-9]+}}, [x0] - store i1 0, i1* %a - ret void -} - -define void @store_breg_i8(i8* %a) { -; CHECK-LABEL: store_breg_i8 -; CHECK: strb wzr, [x0] - store i8 0, i8* %a - ret void -} - -define void @store_breg_i16(i16* %a) { -; CHECK-LABEL: store_breg_i16 -; CHECK: strh wzr, [x0] - store i16 0, i16* %a - ret void -} - -define void @store_breg_i32(i32* %a) { -; CHECK-LABEL: store_breg_i32 -; CHECK: str wzr, [x0] - store i32 0, i32* %a - ret void -} - -define void @store_breg_i64(i64* %a) { -; CHECK-LABEL: store_breg_i64 -; CHECK: str xzr, [x0] - store i64 0, i64* %a - ret void -} - -define void @store_breg_f32(float* %a) { -; CHECK-LABEL: store_breg_f32 -; CHECK: str {{wzr|s[0-9]+}}, [x0] - store float 0.0, float* %a - ret void -} - -define void @store_breg_f64(double* %a) { -; CHECK-LABEL: store_breg_f64 -; CHECK: str {{xzr|d[0-9]+}}, [x0] - store double 0.0, double* %a - ret void -} - -; Load / Store Base Register + Immediate Offset -; Max supported negative offset -define i32 @load_breg_immoff_1(i64 %a) { -; CHECK-LABEL: load_breg_immoff_1 -; CHECK: ldur {{w[0-9]+}}, [x0, #-256] - %1 = add i64 %a, -256 - %2 = inttoptr i64 %1 to i32* - %3 = load i32* %2 - ret i32 %3 -} - -; Min not-supported negative offset -define i32 @load_breg_immoff_2(i64 %a) { -; SDAG-LABEL: load_breg_immoff_2 -; SDAG: sub [[REG:x[0-9]+]], x0, #257 -; SDAG-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]]{{\]}} -; FAST-LABEL: load_breg_immoff_2 -; FAST: add [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]]{{\]}} - %1 = add i64 %a, -257 - %2 = inttoptr i64 %1 to i32* - %3 = load i32* %2 - ret i32 %3 -} - -; Max supported unscaled offset -define i32 @load_breg_immoff_3(i64 %a) { -; CHECK-LABEL: load_breg_immoff_3 -; CHECK: ldur {{w[0-9]+}}, [x0, #255] - %1 = add i64 %a, 255 - %2 = inttoptr i64 %1 to i32* - %3 = load i32* %2 - ret i32 %3 -} - -; Min un-supported unscaled offset -define i32 @load_breg_immoff_4(i64 %a) { -; SDAG-LABEL: load_breg_immoff_4 -; SDAG: add [[REG:x[0-9]+]], x0, #257 -; SDAG-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]]{{\]}} -; FAST-LABEL: load_breg_immoff_4 -; FAST: add [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]]{{\]}} - %1 = add i64 %a, 257 - %2 = inttoptr i64 %1 to i32* - %3 = load i32* %2 - ret i32 %3 -} - -; Max supported scaled offset -define i32 @load_breg_immoff_5(i64 %a) { -; CHECK-LABEL: load_breg_immoff_5 -; CHECK: ldr {{w[0-9]+}}, [x0, #16380] - %1 = add i64 %a, 16380 - %2 = inttoptr i64 %1 to i32* - %3 = load i32* %2 - ret i32 %3 -} - -; Min un-supported scaled offset -define i32 @load_breg_immoff_6(i64 %a) { -; SDAG-LABEL: load_breg_immoff_6 -; SDAG: add [[REG:x[0-9]+]], x0, #4, lsl #12 -; SDAG-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]]{{\]}} -; FAST-LABEL: load_breg_immoff_6 -; FAST: add [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]]{{\]}} - %1 = add i64 %a, 16384 - %2 = inttoptr i64 %1 to i32* - %3 = load i32* %2 - ret i32 %3 -} - -; Max supported negative offset -define void @store_breg_immoff_1(i64 %a) { -; CHECK-LABEL: store_breg_immoff_1 -; CHECK: stur wzr, [x0, #-256] - %1 = add i64 %a, -256 - %2 = inttoptr i64 %1 to i32* - store i32 0, i32* %2 - ret void -} - -; Min not-supported negative offset -define void @store_breg_immoff_2(i64 %a) { -; SDAG-LABEL: store_breg_immoff_2 -; SDAG: sub [[REG:x[0-9]+]], x0, #257 -; SDAG-NEXT: str wzr, {{\[}}[[REG]]{{\]}} -; FAST-LABEL: store_breg_immoff_2 -; FAST: add [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: str wzr, {{\[}}[[REG]]{{\]}} - %1 = add i64 %a, -257 - %2 = inttoptr i64 %1 to i32* - store i32 0, i32* %2 - ret void -} - -; Max supported unscaled offset -define void @store_breg_immoff_3(i64 %a) { -; CHECK-LABEL: store_breg_immoff_3 -; CHECK: stur wzr, [x0, #255] - %1 = add i64 %a, 255 - %2 = inttoptr i64 %1 to i32* - store i32 0, i32* %2 - ret void -} - -; Min un-supported unscaled offset -define void @store_breg_immoff_4(i64 %a) { -; SDAG-LABEL: store_breg_immoff_4 -; SDAG: add [[REG:x[0-9]+]], x0, #257 -; SDAG-NEXT: str wzr, {{\[}}[[REG]]{{\]}} -; FAST-LABEL: store_breg_immoff_4 -; FAST: add [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: str wzr, {{\[}}[[REG]]{{\]}} - %1 = add i64 %a, 257 - %2 = inttoptr i64 %1 to i32* - store i32 0, i32* %2 - ret void -} - -; Max supported scaled offset -define void @store_breg_immoff_5(i64 %a) { -; CHECK-LABEL: store_breg_immoff_5 -; CHECK: str wzr, [x0, #16380] - %1 = add i64 %a, 16380 - %2 = inttoptr i64 %1 to i32* - store i32 0, i32* %2 - ret void -} - -; Min un-supported scaled offset -define void @store_breg_immoff_6(i64 %a) { -; SDAG-LABEL: store_breg_immoff_6 -; SDAG: add [[REG:x[0-9]+]], x0, #4, lsl #12 -; SDAG-NEXT: str wzr, {{\[}}[[REG]]{{\]}} -; FAST-LABEL: store_breg_immoff_6 -; FAST: add [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: str wzr, {{\[}}[[REG]]{{\]}} - %1 = add i64 %a, 16384 - %2 = inttoptr i64 %1 to i32* - store i32 0, i32* %2 - ret void -} - -define i64 @load_breg_immoff_7(i64 %a) { -; CHECK-LABEL: load_breg_immoff_7 -; CHECK: ldr {{x[0-9]+}}, [x0, #48] - %1 = add i64 %a, 48 - %2 = inttoptr i64 %1 to i64* - %3 = load i64* %2 - ret i64 %3 -} - -; Flip add operands -define i64 @load_breg_immoff_8(i64 %a) { -; CHECK-LABEL: load_breg_immoff_8 -; CHECK: ldr {{x[0-9]+}}, [x0, #48] - %1 = add i64 48, %a - %2 = inttoptr i64 %1 to i64* - %3 = load i64* %2 - ret i64 %3 -} - -; Load Base Register + Register Offset -define i64 @load_breg_offreg_1(i64 %a, i64 %b) { -; CHECK-LABEL: load_breg_offreg_1 -; CHECK: ldr {{x[0-9]+}}, [x0, x1] - %1 = add i64 %a, %b - %2 = inttoptr i64 %1 to i64* - %3 = load i64* %2 - ret i64 %3 -} - -; Flip add operands -define i64 @load_breg_offreg_2(i64 %a, i64 %b) { -; CHECK-LABEL: load_breg_offreg_2 -; CHECK: ldr {{x[0-9]+}}, [x1, x0] - %1 = add i64 %b, %a - %2 = inttoptr i64 %1 to i64* - %3 = load i64* %2 - ret i64 %3 -} - -; Load Base Register + Register Offset + Immediate Offset -define i64 @load_breg_offreg_immoff_1(i64 %a, i64 %b) { -; CHECK-LABEL: load_breg_offreg_immoff_1 -; CHECK: add [[REG:x[0-9]+]], x0, x1 -; CHECK-NEXT: ldr x0, {{\[}}[[REG]], #48{{\]}} - %1 = add i64 %a, %b - %2 = add i64 %1, 48 - %3 = inttoptr i64 %2 to i64* - %4 = load i64* %3 - ret i64 %4 -} - -define i64 @load_breg_offreg_immoff_2(i64 %a, i64 %b) { -; SDAG-LABEL: load_breg_offreg_immoff_2 -; SDAG: add [[REG1:x[0-9]+]], x0, x1 -; SDAG-NEXT: add [[REG2:x[0-9]+]], [[REG1]], #15, lsl #12 -; SDAG-NEXT: ldr x0, {{\[}}[[REG2]]{{\]}} -; FAST-LABEL: load_breg_offreg_immoff_2 -; FAST: add [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: ldr x0, {{\[}}[[REG]], x1{{\]}} - %1 = add i64 %a, %b - %2 = add i64 %1, 61440 - %3 = inttoptr i64 %2 to i64* - %4 = load i64* %3 - ret i64 %4 -} - -; Load Base Register + Scaled Register Offset -define i32 @load_breg_shift_offreg_1(i64 %a, i64 %b) { -; CHECK-LABEL: load_breg_shift_offreg_1 -; CHECK: ldr {{w[0-9]+}}, [x1, x0, lsl #2] - %1 = shl i64 %a, 2 - %2 = add i64 %1, %b - %3 = inttoptr i64 %2 to i32* - %4 = load i32* %3 - ret i32 %4 -} - -define i32 @load_breg_shift_offreg_2(i64 %a, i64 %b) { -; CHECK-LABEL: load_breg_shift_offreg_2 -; CHECK: ldr {{w[0-9]+}}, [x1, x0, lsl #2] - %1 = shl i64 %a, 2 - %2 = add i64 %b, %1 - %3 = inttoptr i64 %2 to i32* - %4 = load i32* %3 - ret i32 %4 -} - -define i32 @load_breg_shift_offreg_3(i64 %a, i64 %b) { -; SDAG-LABEL: load_breg_shift_offreg_3 -; SDAG: lsl [[REG:x[0-9]+]], x0, #2 -; SDAG-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]], x1, lsl #2{{\]}} -; FAST-LABEL: load_breg_shift_offreg_3 -; FAST: lsl [[REG:x[0-9]+]], x1, {{x[0-9]+}} -; FAST-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]], x0, lsl #2{{\]}} - %1 = shl i64 %a, 2 - %2 = shl i64 %b, 2 - %3 = add i64 %1, %2 - %4 = inttoptr i64 %3 to i32* - %5 = load i32* %4 - ret i32 %5 -} - -define i32 @load_breg_shift_offreg_4(i64 %a, i64 %b) { -; SDAG-LABEL: load_breg_shift_offreg_4 -; SDAG: lsl [[REG:x[0-9]+]], x1, #2 -; SDAG-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]], x0, lsl #2{{\]}} -; FAST-LABEL: load_breg_shift_offreg_4 -; FAST: lsl [[REG:x[0-9]+]], x0, {{x[0-9]+}} -; FAST-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]], x1, lsl #2{{\]}} - %1 = shl i64 %a, 2 - %2 = shl i64 %b, 2 - %3 = add i64 %2, %1 - %4 = inttoptr i64 %3 to i32* - %5 = load i32* %4 - ret i32 %5 -} - -define i32 @load_breg_shift_offreg_5(i64 %a, i64 %b) { -; SDAG-LABEL: load_breg_shift_offreg_5 -; SDAG: lsl [[REG:x[0-9]+]], x1, #3 -; SDAG-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]], x0, lsl #2{{\]}} -; FAST-LABEL: load_breg_shift_offreg_5 -; FAST: lsl [[REG:x[0-9]+]], x1, {{x[0-9]+}} -; FAST-NEXT: ldr {{w[0-9]+}}, {{\[}}[[REG]], x0, lsl #2{{\]}} - %1 = shl i64 %a, 2 - %2 = shl i64 %b, 3 - %3 = add i64 %1, %2 - %4 = inttoptr i64 %3 to i32* - %5 = load i32* %4 - ret i32 %5 -} - - -; Load Base Register + Scaled Register Offset + Sign/Zero extension -define i32 @load_breg_zext_shift_offreg_1(i32 %a, i64 %b) { -; CHECK-LABEL: load_breg_zext_shift_offreg_1 -; CHECK: ldr {{w[0-9]+}}, [x1, w0, uxtw #2] - %1 = zext i32 %a to i64 - %2 = shl i64 %1, 2 - %3 = add i64 %2, %b - %4 = inttoptr i64 %3 to i32* - %5 = load i32* %4 - ret i32 %5 -} - -define i32 @load_breg_zext_shift_offreg_2(i32 %a, i64 %b) { -; CHECK-LABEL: load_breg_zext_shift_offreg_2 -; CHECK: ldr {{w[0-9]+}}, [x1, w0, uxtw #2] - %1 = zext i32 %a to i64 - %2 = shl i64 %1, 2 - %3 = add i64 %b, %2 - %4 = inttoptr i64 %3 to i32* - %5 = load i32* %4 - ret i32 %5 -} - -define i32 @load_breg_sext_shift_offreg_1(i32 %a, i64 %b) { -; CHECK-LABEL: load_breg_sext_shift_offreg_1 -; CHECK: ldr {{w[0-9]+}}, [x1, w0, sxtw #2] - %1 = sext i32 %a to i64 - %2 = shl i64 %1, 2 - %3 = add i64 %2, %b - %4 = inttoptr i64 %3 to i32* - %5 = load i32* %4 - ret i32 %5 -} - -define i32 @load_breg_sext_shift_offreg_2(i32 %a, i64 %b) { -; CHECK-LABEL: load_breg_sext_shift_offreg_2 -; CHECK: ldr {{w[0-9]+}}, [x1, w0, sxtw #2] - %1 = sext i32 %a to i64 - %2 = shl i64 %1, 2 - %3 = add i64 %b, %2 - %4 = inttoptr i64 %3 to i32* - %5 = load i32* %4 - ret i32 %5 -} -