diff options
Diffstat (limited to 'lib/Target/ARM/ARMISelDAGToDAG.cpp')
-rw-r--r-- | lib/Target/ARM/ARMISelDAGToDAG.cpp | 213 |
1 files changed, 178 insertions, 35 deletions
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index 8e0e82388251..b349627b67b1 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -1,9 +1,8 @@ //===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -120,8 +119,7 @@ public: SDValue &Offset, SDValue &Opc); bool SelectAddrMode3Offset(SDNode *Op, SDValue N, SDValue &Offset, SDValue &Opc); - bool IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset, - int Lwb, int Upb, bool FP16); + bool IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset, bool FP16); bool SelectAddrMode5(SDValue N, SDValue &Base, SDValue &Offset); bool SelectAddrMode5FP16(SDValue N, SDValue &Base, SDValue &Offset); bool SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,SDValue &Align); @@ -131,6 +129,7 @@ public: // Thumb Addressing Modes: bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset); + bool SelectThumbAddrModeRRSext(SDValue N, SDValue &Base, SDValue &Offset); bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base, SDValue &OffImm); bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base, @@ -147,6 +146,9 @@ public: SDValue &OffImm); bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, SDValue &OffImm); + template<unsigned Shift> + bool SelectT2AddrModeImm7(SDValue N, SDValue &Base, + SDValue &OffImm); bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base, SDValue &OffReg, SDValue &ShImm); bool SelectT2AddrModeExclusive(SDValue N, SDValue &Base, SDValue &OffImm); @@ -452,8 +454,10 @@ unsigned ARMDAGToDAGISel::ConstantMaterializationCost(unsigned Val) const { if (Subtarget->isThumb()) { if (Val <= 255) return 1; // MOV if (Subtarget->hasV6T2Ops() && - (Val <= 0xffff || ARM_AM::getT2SOImmValSplatVal(Val) != -1)) - return 1; // MOVW + (Val <= 0xffff || // MOV + ARM_AM::getT2SOImmVal(Val) != -1 || // MOVW + ARM_AM::getT2SOImmVal(~Val) != -1)) // MVN + return 1; if (Val <= 510) return 2; // MOV + ADDi8 if (~Val <= 255) return 2; // MOV + MVN if (ARM_AM::isThumbImmShiftedVal(Val)) return 2; // MOV + LSL @@ -463,7 +467,7 @@ unsigned ARMDAGToDAGISel::ConstantMaterializationCost(unsigned Val) const { if (Subtarget->hasV6T2Ops() && Val <= 0xffff) return 1; // MOVW if (ARM_AM::isSOImmTwoPartVal(Val)) return 2; // two instrs } - if (Subtarget->useMovt(*MF)) return 2; // MOVW + MOVT + if (Subtarget->useMovt()) return 2; // MOVW + MOVT return 3; // Literal pool load } @@ -900,7 +904,7 @@ bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N, } bool ARMDAGToDAGISel::IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset, - int Lwb, int Upb, bool FP16) { + bool FP16) { if (!CurDAG->isBaseWithConstantOffset(N)) { Base = N; if (N.getOpcode() == ISD::FrameIndex) { @@ -922,7 +926,7 @@ bool ARMDAGToDAGISel::IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offse int RHSC; const int Scale = FP16 ? 2 : 4; - if (isScaledConstantInRange(N.getOperand(1), Scale, Lwb, Upb, RHSC)) { + if (isScaledConstantInRange(N.getOperand(1), Scale, -255, 256, RHSC)) { Base = N.getOperand(0); if (Base.getOpcode() == ISD::FrameIndex) { int FI = cast<FrameIndexSDNode>(Base)->getIndex(); @@ -960,16 +964,12 @@ bool ARMDAGToDAGISel::IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offse bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N, SDValue &Base, SDValue &Offset) { - int Lwb = -256 + 1; - int Upb = 256; - return IsAddressingMode5(N, Base, Offset, Lwb, Upb, /*FP16=*/ false); + return IsAddressingMode5(N, Base, Offset, /*FP16=*/ false); } bool ARMDAGToDAGISel::SelectAddrMode5FP16(SDValue N, SDValue &Base, SDValue &Offset) { - int Lwb = -512 + 1; - int Upb = 512; - return IsAddressingMode5(N, Base, Offset, Lwb, Upb, /*FP16=*/ true); + return IsAddressingMode5(N, Base, Offset, /*FP16=*/ true); } bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr, @@ -1033,8 +1033,22 @@ bool ARMDAGToDAGISel::SelectAddrModePC(SDValue N, // Thumb Addressing Modes //===----------------------------------------------------------------------===// -bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, - SDValue &Base, SDValue &Offset){ +static bool shouldUseZeroOffsetLdSt(SDValue N) { + // Negative numbers are difficult to materialise in thumb1. If we are + // selecting the add of a negative, instead try to select ri with a zero + // offset, so create the add node directly which will become a sub. + if (N.getOpcode() != ISD::ADD) + return false; + + // Look for an imm which is not legal for ld/st, but is legal for sub. + if (auto C = dyn_cast<ConstantSDNode>(N.getOperand(1))) + return C->getSExtValue() < 0 && C->getSExtValue() >= -255; + + return false; +} + +bool ARMDAGToDAGISel::SelectThumbAddrModeRRSext(SDValue N, SDValue &Base, + SDValue &Offset) { if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) { ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N); if (!NC || !NC->isNullValue()) @@ -1049,9 +1063,22 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, return true; } +bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, SDValue &Base, + SDValue &Offset) { + if (shouldUseZeroOffsetLdSt(N)) + return false; // Select ri instead + return SelectThumbAddrModeRRSext(N, Base, Offset); +} + bool ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base, SDValue &OffImm) { + if (shouldUseZeroOffsetLdSt(N)) { + Base = N; + OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32); + return true; + } + if (!CurDAG->isBaseWithConstantOffset(N)) { if (N.getOpcode() == ISD::ADD) { return false; // We want to select register offset instead @@ -1117,25 +1144,28 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N, if (!CurDAG->isBaseWithConstantOffset(N)) return false; - RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0)); - if (N.getOperand(0).getOpcode() == ISD::FrameIndex || - (LHSR && LHSR->getReg() == ARM::SP)) { + if (N.getOperand(0).getOpcode() == ISD::FrameIndex) { // If the RHS is + imm8 * scale, fold into addr mode. int RHSC; if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, 0, 256, RHSC)) { Base = N.getOperand(0); - if (Base.getOpcode() == ISD::FrameIndex) { - int FI = cast<FrameIndexSDNode>(Base)->getIndex(); + int FI = cast<FrameIndexSDNode>(Base)->getIndex(); + // Make sure the offset is inside the object, or we might fail to + // allocate an emergency spill slot. (An out-of-range access is UB, but + // it could show up anyway.) + MachineFrameInfo &MFI = MF->getFrameInfo(); + if (RHSC * 4 < MFI.getObjectSize(FI)) { // For LHS+RHS to result in an offset that's a multiple of 4 the object // indexed by the LHS must be 4-byte aligned. - MachineFrameInfo &MFI = MF->getFrameInfo(); - if (MFI.getObjectAlignment(FI) < 4) + if (!MFI.isFixedObjectIndex(FI) && MFI.getObjectAlignment(FI) < 4) MFI.setObjectAlignment(FI, 4); - Base = CurDAG->getTargetFrameIndex( - FI, TLI->getPointerTy(CurDAG->getDataLayout())); + if (MFI.getObjectAlignment(FI) >= 4) { + Base = CurDAG->getTargetFrameIndex( + FI, TLI->getPointerTy(CurDAG->getDataLayout())); + OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32); + return true; + } } - OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32); - return true; } } @@ -1248,6 +1278,35 @@ bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, return false; } +template<unsigned Shift> +bool ARMDAGToDAGISel::SelectT2AddrModeImm7(SDValue N, + SDValue &Base, SDValue &OffImm) { + if (N.getOpcode() == ISD::SUB || + CurDAG->isBaseWithConstantOffset(N)) { + if (auto RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { + int RHSC = (int)RHS->getZExtValue(); + if (N.getOpcode() == ISD::SUB) + RHSC = -RHSC; + + if (isShiftedInt<7, Shift>(RHSC)) { + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast<FrameIndexSDNode>(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex( + FI, TLI->getPointerTy(CurDAG->getDataLayout())); + } + OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32); + return true; + } + } + } + + // Base only. + Base = N; + OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32); + return true; +} + bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N, SDValue &Base, SDValue &OffReg, SDValue &ShImm) { @@ -2072,10 +2131,12 @@ void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating, default: llvm_unreachable("unhandled vld/vst lane type"); // Double-register operations: case MVT::v8i8: OpcodeIndex = 0; break; + case MVT::v4f16: case MVT::v4i16: OpcodeIndex = 1; break; case MVT::v2f32: case MVT::v2i32: OpcodeIndex = 2; break; // Quad-register operations: + case MVT::v8f16: case MVT::v8i16: OpcodeIndex = 0; break; case MVT::v4f32: case MVT::v4i32: OpcodeIndex = 1; break; @@ -2192,7 +2253,10 @@ void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool IsIntrinsic, case MVT::v8i8: case MVT::v16i8: OpcodeIndex = 0; break; case MVT::v4i16: - case MVT::v8i16: OpcodeIndex = 1; break; + case MVT::v8i16: + case MVT::v4f16: + case MVT::v8f16: + OpcodeIndex = 1; break; case MVT::v2f32: case MVT::v2i32: case MVT::v4f32: @@ -2577,6 +2641,44 @@ void ARMDAGToDAGISel::Select(SDNode *N) { switch (N->getOpcode()) { default: break; + case ISD::STORE: { + // For Thumb1, match an sp-relative store in C++. This is a little + // unfortunate, but I don't think I can make the chain check work + // otherwise. (The chain of the store has to be the same as the chain + // of the CopyFromReg, or else we can't replace the CopyFromReg with + // a direct reference to "SP".) + // + // This is only necessary on Thumb1 because Thumb1 sp-relative stores use + // a different addressing mode from other four-byte stores. + // + // This pattern usually comes up with call arguments. + StoreSDNode *ST = cast<StoreSDNode>(N); + SDValue Ptr = ST->getBasePtr(); + if (Subtarget->isThumb1Only() && ST->isUnindexed()) { + int RHSC = 0; + if (Ptr.getOpcode() == ISD::ADD && + isScaledConstantInRange(Ptr.getOperand(1), /*Scale=*/4, 0, 256, RHSC)) + Ptr = Ptr.getOperand(0); + + if (Ptr.getOpcode() == ISD::CopyFromReg && + cast<RegisterSDNode>(Ptr.getOperand(1))->getReg() == ARM::SP && + Ptr.getOperand(0) == ST->getChain()) { + SDValue Ops[] = {ST->getValue(), + CurDAG->getRegister(ARM::SP, MVT::i32), + CurDAG->getTargetConstant(RHSC, dl, MVT::i32), + getAL(CurDAG, dl), + CurDAG->getRegister(0, MVT::i32), + ST->getChain()}; + MachineSDNode *ResNode = + CurDAG->getMachineNode(ARM::tSTRspi, dl, MVT::Other, Ops); + MachineMemOperand *MemOp = ST->getMemOperand(); + CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemOp}); + ReplaceNode(N, ResNode); + return; + } + } + break; + } case ISD::WRITE_REGISTER: if (tryWriteRegister(N)) return; @@ -2586,6 +2688,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) { return; break; case ISD::INLINEASM: + case ISD::INLINEASM_BR: if (tryInlineAsm(N)) return; break; @@ -2895,6 +2998,16 @@ void ARMDAGToDAGISel::Select(SDNode *N) { // Other cases are autogenerated. break; } + case ARMISD::WLS: { + SDValue Ops[] = { N->getOperand(1), // Loop count + N->getOperand(2), // Exit target + N->getOperand(0) }; + SDNode *LoopStart = + CurDAG->getMachineNode(ARM::t2WhileLoopStart, dl, MVT::Other, Ops); + ReplaceUses(N, LoopStart); + CurDAG->RemoveDeadNode(N); + return; + } case ARMISD::BRCOND: { // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc) @@ -2922,6 +3035,36 @@ void ARMDAGToDAGISel::Select(SDNode *N) { unsigned CC = (unsigned) cast<ConstantSDNode>(N2)->getZExtValue(); if (InFlag.getOpcode() == ARMISD::CMPZ) { + if (InFlag.getOperand(0).getOpcode() == ISD::INTRINSIC_W_CHAIN) { + SDValue Int = InFlag.getOperand(0); + uint64_t ID = cast<ConstantSDNode>(Int->getOperand(1))->getZExtValue(); + + // Handle low-overhead loops. + if (ID == Intrinsic::loop_decrement_reg) { + SDValue Elements = Int.getOperand(2); + SDValue Size = CurDAG->getTargetConstant( + cast<ConstantSDNode>(Int.getOperand(3))->getZExtValue(), dl, + MVT::i32); + + SDValue Args[] = { Elements, Size, Int.getOperand(0) }; + SDNode *LoopDec = + CurDAG->getMachineNode(ARM::t2LoopDec, dl, + CurDAG->getVTList(MVT::i32, MVT::Other), + Args); + ReplaceUses(Int.getNode(), LoopDec); + + SDValue EndArgs[] = { SDValue(LoopDec, 0), N1, Chain }; + SDNode *LoopEnd = + CurDAG->getMachineNode(ARM::t2LoopEnd, dl, MVT::Other, EndArgs); + + ReplaceUses(N, LoopEnd); + CurDAG->RemoveDeadNode(N); + CurDAG->RemoveDeadNode(InFlag.getNode()); + CurDAG->RemoveDeadNode(Int.getNode()); + return; + } + } + bool SwitchEQNEToPLMI; SelectCMPZ(InFlag.getNode(), SwitchEQNEToPLMI); InFlag = N->getOperand(4); @@ -3979,9 +4122,9 @@ bool ARMDAGToDAGISel::tryReadRegister(SDNode *N){ // If an opcode was found then we can lower the read to a VFP instruction. if (Opcode) { - if (!Subtarget->hasVFP2()) + if (!Subtarget->hasVFP2Base()) return false; - if (Opcode == ARM::VMRS_MVFR2 && !Subtarget->hasFPARMv8()) + if (Opcode == ARM::VMRS_MVFR2 && !Subtarget->hasFPARMv8Base()) return false; Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32), @@ -4090,7 +4233,7 @@ bool ARMDAGToDAGISel::tryWriteRegister(SDNode *N){ .Default(0); if (Opcode) { - if (!Subtarget->hasVFP2()) + if (!Subtarget->hasVFP2Base()) return false; Ops = { N->getOperand(2), getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32), N->getOperand(0) }; @@ -4290,7 +4433,7 @@ bool ARMDAGToDAGISel::tryInlineAsm(SDNode *N){ if (!Changed) return false; - SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N), + SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N), CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands); New->setNodeId(-1); ReplaceNode(N, New.getNode()); |