diff options
Diffstat (limited to 'lib/Target/AArch64/AArch64FastISel.cpp')
| -rw-r--r-- | lib/Target/AArch64/AArch64FastISel.cpp | 123 |
1 files changed, 115 insertions, 8 deletions
diff --git a/lib/Target/AArch64/AArch64FastISel.cpp b/lib/Target/AArch64/AArch64FastISel.cpp index e2ab7ab79be1..fe2c2d4550a7 100644 --- a/lib/Target/AArch64/AArch64FastISel.cpp +++ b/lib/Target/AArch64/AArch64FastISel.cpp @@ -134,6 +134,7 @@ private: bool selectFRem(const Instruction *I); bool selectSDiv(const Instruction *I); bool selectGetElementPtr(const Instruction *I); + bool selectAtomicCmpXchg(const AtomicCmpXchgInst *I); // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); @@ -185,6 +186,8 @@ private: MachineMemOperand *MMO = nullptr); bool emitStore(MVT VT, unsigned SrcReg, Address Addr, MachineMemOperand *MMO = nullptr); + bool emitStoreRelease(MVT VT, unsigned SrcReg, unsigned AddrReg, + MachineMemOperand *MMO = nullptr); unsigned emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt); unsigned emiti1Ext(unsigned SrcReg, MVT DestVT, bool isZExt); unsigned emitAdd(MVT RetVT, const Value *LHS, const Value *RHS, @@ -554,7 +557,7 @@ bool AArch64FastISel::computeAddress(const Value *Obj, Address &Addr, Type *Ty) for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U); GTI != E; ++GTI) { const Value *Op = GTI.getOperand(); - if (StructType *STy = dyn_cast<StructType>(*GTI)) { + if (StructType *STy = GTI.getStructTypeOrNull()) { const StructLayout *SL = DL.getStructLayout(STy); unsigned Idx = cast<ConstantInt>(Op)->getZExtValue(); TmpOffset += SL->getElementOffset(Idx); @@ -1997,6 +2000,28 @@ bool AArch64FastISel::selectLoad(const Instruction *I) { return true; } +bool AArch64FastISel::emitStoreRelease(MVT VT, unsigned SrcReg, + unsigned AddrReg, + MachineMemOperand *MMO) { + unsigned Opc; + switch (VT.SimpleTy) { + default: return false; + case MVT::i8: Opc = AArch64::STLRB; break; + case MVT::i16: Opc = AArch64::STLRH; break; + case MVT::i32: Opc = AArch64::STLRW; break; + case MVT::i64: Opc = AArch64::STLRX; break; + } + + const MCInstrDesc &II = TII.get(Opc); + SrcReg = constrainOperandRegClass(II, SrcReg, 0); + AddrReg = constrainOperandRegClass(II, AddrReg, 1); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II) + .addReg(SrcReg) + .addReg(AddrReg) + .addMemOperand(MMO); + return true; +} + bool AArch64FastISel::emitStore(MVT VT, unsigned SrcReg, Address Addr, MachineMemOperand *MMO) { if (!TLI.allowsMisalignedMemoryAccesses(VT)) @@ -2071,8 +2096,7 @@ bool AArch64FastISel::selectStore(const Instruction *I) { // Verify we have a legal type before going any further. Currently, we handle // simple types that will directly fit in a register (i32/f32/i64/f64) or // those that can be sign or zero-extended to a basic operation (i1/i8/i16). - if (!isTypeSupported(Op0->getType(), VT, /*IsVectorAllowed=*/true) || - cast<StoreInst>(I)->isAtomic()) + if (!isTypeSupported(Op0->getType(), VT, /*IsVectorAllowed=*/true)) return false; const Value *PtrV = I->getOperand(1); @@ -2109,9 +2133,23 @@ bool AArch64FastISel::selectStore(const Instruction *I) { if (!SrcReg) return false; + auto *SI = cast<StoreInst>(I); + + // Try to emit a STLR for seq_cst/release. + if (SI->isAtomic()) { + AtomicOrdering Ord = SI->getOrdering(); + // The non-atomic instructions are sufficient for relaxed stores. + if (isReleaseOrStronger(Ord)) { + // The STLR addressing mode only supports a base reg; pass that directly. + unsigned AddrReg = getRegForValue(PtrV); + return emitStoreRelease(VT, SrcReg, AddrReg, + createMachineMemOperandFor(I)); + } + } + // See if we can handle this address. Address Addr; - if (!computeAddress(I->getOperand(1), Addr, I->getOperand(0)->getType())) + if (!computeAddress(PtrV, Addr, Op0->getType())) return false; if (!emitStore(VT, SrcReg, Addr, createMachineMemOperandFor(I))) @@ -2822,7 +2860,7 @@ bool AArch64FastISel::fastLowerArguments() { return false; CallingConv::ID CC = F->getCallingConv(); - if (CC != CallingConv::C) + if (CC != CallingConv::C && CC != CallingConv::Swift) return false; // Only handle simple cases of up to 8 GPR and FPR each. @@ -3328,8 +3366,8 @@ bool AArch64FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) { switch (II->getIntrinsicID()) { default: return false; case Intrinsic::frameaddress: { - MachineFrameInfo *MFI = FuncInfo.MF->getFrameInfo(); - MFI->setFrameAddressIsTaken(true); + MachineFrameInfo &MFI = FuncInfo.MF->getFrameInfo(); + MFI.setFrameAddressIsTaken(true); const AArch64RegisterInfo *RegInfo = static_cast<const AArch64RegisterInfo *>(Subtarget->getRegisterInfo()); @@ -4847,7 +4885,7 @@ bool AArch64FastISel::selectGetElementPtr(const Instruction *I) { for (gep_type_iterator GTI = gep_type_begin(I), E = gep_type_end(I); GTI != E; ++GTI) { const Value *Idx = GTI.getOperand(); - if (auto *StTy = dyn_cast<StructType>(*GTI)) { + if (auto *StTy = GTI.getStructTypeOrNull()) { unsigned Field = cast<ConstantInt>(Idx)->getZExtValue(); // N = N + Offset if (Field) @@ -4903,6 +4941,73 @@ bool AArch64FastISel::selectGetElementPtr(const Instruction *I) { return true; } +bool AArch64FastISel::selectAtomicCmpXchg(const AtomicCmpXchgInst *I) { + assert(TM.getOptLevel() == CodeGenOpt::None && + "cmpxchg survived AtomicExpand at optlevel > -O0"); + + auto *RetPairTy = cast<StructType>(I->getType()); + Type *RetTy = RetPairTy->getTypeAtIndex(0U); + assert(RetPairTy->getTypeAtIndex(1U)->isIntegerTy(1) && + "cmpxchg has a non-i1 status result"); + + MVT VT; + if (!isTypeLegal(RetTy, VT)) + return false; + + const TargetRegisterClass *ResRC; + unsigned Opc, CmpOpc; + // This only supports i32/i64, because i8/i16 aren't legal, and the generic + // extractvalue selection doesn't support that. + if (VT == MVT::i32) { + Opc = AArch64::CMP_SWAP_32; + CmpOpc = AArch64::SUBSWrs; + ResRC = &AArch64::GPR32RegClass; + } else if (VT == MVT::i64) { + Opc = AArch64::CMP_SWAP_64; + CmpOpc = AArch64::SUBSXrs; + ResRC = &AArch64::GPR64RegClass; + } else { + return false; + } + + const MCInstrDesc &II = TII.get(Opc); + + const unsigned AddrReg = constrainOperandRegClass( + II, getRegForValue(I->getPointerOperand()), II.getNumDefs()); + const unsigned DesiredReg = constrainOperandRegClass( + II, getRegForValue(I->getCompareOperand()), II.getNumDefs() + 1); + const unsigned NewReg = constrainOperandRegClass( + II, getRegForValue(I->getNewValOperand()), II.getNumDefs() + 2); + + const unsigned ResultReg1 = createResultReg(ResRC); + const unsigned ResultReg2 = createResultReg(&AArch64::GPR32RegClass); + const unsigned ScratchReg = createResultReg(&AArch64::GPR32RegClass); + + // FIXME: MachineMemOperand doesn't support cmpxchg yet. + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II) + .addDef(ResultReg1) + .addDef(ScratchReg) + .addUse(AddrReg) + .addUse(DesiredReg) + .addUse(NewReg); + + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CmpOpc)) + .addDef(VT == MVT::i32 ? AArch64::WZR : AArch64::XZR) + .addUse(ResultReg1) + .addUse(DesiredReg) + .addImm(0); + + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AArch64::CSINCWr)) + .addDef(ResultReg2) + .addUse(AArch64::WZR) + .addUse(AArch64::WZR) + .addImm(AArch64CC::NE); + + assert((ResultReg1 + 1) == ResultReg2 && "Nonconsecutive result registers."); + updateValueMap(I, ResultReg1, 2); + return true; +} + bool AArch64FastISel::fastSelectInstruction(const Instruction *I) { switch (I->getOpcode()) { default: @@ -4976,6 +5081,8 @@ bool AArch64FastISel::fastSelectInstruction(const Instruction *I) { return selectFRem(I); case Instruction::GetElementPtr: return selectGetElementPtr(I); + case Instruction::AtomicCmpXchg: + return selectAtomicCmpXchg(cast<AtomicCmpXchgInst>(I)); } // fall-back to target-independent instruction selection. |
