diff options
Diffstat (limited to 'llvm/lib/Target/M68k/M68kISelLowering.cpp')
| -rw-r--r-- | llvm/lib/Target/M68k/M68kISelLowering.cpp | 223 |
1 files changed, 188 insertions, 35 deletions
diff --git a/llvm/lib/Target/M68k/M68kISelLowering.cpp b/llvm/lib/Target/M68k/M68kISelLowering.cpp index 87ce56a5b9a9..af3af6760ae1 100644 --- a/llvm/lib/Target/M68k/M68kISelLowering.cpp +++ b/llvm/lib/Target/M68k/M68kISelLowering.cpp @@ -73,16 +73,16 @@ M68kTargetLowering::M68kTargetLowering(const M68kTargetMachine &TM, setTruncStoreAction(MVT::i32, MVT::i8, Expand); setTruncStoreAction(MVT::i16, MVT::i8, Expand); - setOperationAction(ISD::MUL, MVT::i8, Promote); - setOperationAction(ISD::MUL, MVT::i16, Legal); + setOperationAction({ISD::MUL, ISD::SDIV, ISD::UDIV}, MVT::i8, Promote); + setOperationAction({ISD::MUL, ISD::SDIV, ISD::UDIV}, MVT::i16, Legal); if (Subtarget.atLeastM68020()) - setOperationAction(ISD::MUL, MVT::i32, Legal); + setOperationAction({ISD::MUL, ISD::SDIV, ISD::UDIV}, MVT::i32, Legal); else - setOperationAction(ISD::MUL, MVT::i32, LibCall); + setOperationAction({ISD::MUL, ISD::SDIV, ISD::UDIV}, MVT::i32, LibCall); setOperationAction(ISD::MUL, MVT::i64, LibCall); for (auto OP : - {ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM, ISD::UDIVREM, ISD::SDIVREM, + {ISD::SREM, ISD::UREM, ISD::UDIVREM, ISD::SDIVREM, ISD::MULHS, ISD::MULHU, ISD::UMUL_LOHI, ISD::SMUL_LOHI}) { setOperationAction(OP, MVT::i8, Promote); setOperationAction(OP, MVT::i16, Legal); @@ -163,6 +163,8 @@ M68kTargetLowering::M68kTargetLowering(const M68kTargetMachine &TM, setOperationAction(ISD::ATOMIC_CMP_SWAP, {MVT::i8, MVT::i16, MVT::i32}, Subtarget.atLeastM68020() ? Legal : LibCall); + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + // M68k does not have native read-modify-write support, so expand all of them // to `__sync_fetch_*` for target < M68020, otherwise expand to CmpxChg. // See `shouldExpandAtomicRMWInIR` below. @@ -178,12 +180,11 @@ M68kTargetLowering::M68kTargetLowering(const M68kTargetMachine &TM, ISD::ATOMIC_LOAD_MAX, ISD::ATOMIC_LOAD_UMIN, ISD::ATOMIC_LOAD_UMAX, + ISD::ATOMIC_SWAP, }, {MVT::i8, MVT::i16, MVT::i32}, LibCall); - // 2^2 bytes - // FIXME can it be just 2^1? - setMinFunctionAlignment(Align::Constant<2>()); + setMinFunctionAlignment(Align(2)); } TargetLoweringBase::AtomicExpansionKind @@ -193,6 +194,24 @@ M68kTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const { : TargetLoweringBase::AtomicExpansionKind::None; } +Register +M68kTargetLowering::getExceptionPointerRegister(const Constant *) const { + return M68k::D0; +} + +Register +M68kTargetLowering::getExceptionSelectorRegister(const Constant *) const { + return M68k::D1; +} + +unsigned +M68kTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const { + return StringSwitch<unsigned>(ConstraintCode) + .Case("Q", InlineAsm::Constraint_Q) + .Case("U", InlineAsm::Constraint_Um) // We borrow Constraint_Um for 'U'. + .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode)); +} + EVT M68kTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const { // M68k SETcc producess either 0x00 or 0xFF @@ -748,11 +767,11 @@ SDValue M68kTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // Build a sequence of copy-to-reg nodes chained together with token chain // and flag operands which copy the outgoing args into registers. - SDValue InFlag; + SDValue InGlue; for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[i].first, - RegsToPass[i].second, InFlag); - InFlag = Chain.getValue(1); + RegsToPass[i].second, InGlue); + InGlue = Chain.getValue(1); } if (Callee->getOpcode() == ISD::GlobalAddress) { @@ -796,8 +815,8 @@ SDValue M68kTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVector<SDValue, 8> Ops; if (!IsSibcall && IsTailCall) { - Chain = DAG.getCALLSEQ_END(Chain, NumBytesToPop, 0, InFlag, DL); - InFlag = Chain.getValue(1); + Chain = DAG.getCALLSEQ_END(Chain, NumBytesToPop, 0, InGlue, DL); + InGlue = Chain.getValue(1); } Ops.push_back(Chain); @@ -818,8 +837,8 @@ SDValue M68kTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, Ops.push_back(DAG.getRegisterMask(Mask)); - if (InFlag.getNode()) - Ops.push_back(InFlag); + if (InGlue.getNode()) + Ops.push_back(InGlue); if (IsTailCall) { MF.getFrameInfo().setHasTailCall(); @@ -827,7 +846,7 @@ SDValue M68kTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, } Chain = DAG.getNode(M68kISD::CALL, DL, NodeTys, Ops); - InFlag = Chain.getValue(1); + InGlue = Chain.getValue(1); // Create the CALLSEQ_END node. unsigned NumBytesForCalleeToPop; @@ -851,18 +870,18 @@ SDValue M68kTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // Returns a flag for retval copy to use. if (!IsSibcall) { Chain = DAG.getCALLSEQ_END(Chain, NumBytesToPop, NumBytesForCalleeToPop, - InFlag, DL); - InFlag = Chain.getValue(1); + InGlue, DL); + InGlue = Chain.getValue(1); } // Handle result values, copying them out of physregs into vregs that we // return. - return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, DL, DAG, + return LowerCallResult(Chain, InGlue, CallConv, IsVarArg, Ins, DL, DAG, InVals); } SDValue M68kTargetLowering::LowerCallResult( - SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool IsVarArg, + SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { @@ -878,14 +897,14 @@ SDValue M68kTargetLowering::LowerCallResult( EVT CopyVT = VA.getLocVT(); /// ??? is this correct? - Chain = DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), CopyVT, InFlag) + Chain = DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), CopyVT, InGlue) .getValue(1); SDValue Val = Chain.getValue(0); if (VA.isExtInLoc() && VA.getValVT().getScalarType() == MVT::i1) Val = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Val); - InFlag = Chain.getValue(2); + InGlue = Chain.getValue(2); InVals.push_back(Val); } @@ -986,7 +1005,7 @@ SDValue M68kTargetLowering::LowerFormalArguments( } } - unsigned StackSize = CCInfo.getNextStackOffset(); + unsigned StackSize = CCInfo.getStackSize(); // Align stack specially for tail calls. if (shouldGuaranteeTCO(CCID, MF.getTarget().Options.GuaranteedTailCallOpt)) StackSize = GetAlignedArgumentStackSize(StackSize, DAG); @@ -1039,6 +1058,14 @@ SDValue M68kTargetLowering::LowerFormalArguments( // Return Value Calling Convention Implementation //===----------------------------------------------------------------------===// +bool M68kTargetLowering::CanLowerReturn( + CallingConv::ID CCID, MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CCID, IsVarArg, MF, RVLocs, Context); + return CCInfo.CheckReturn(Outs, RetCC_M68k); +} + SDValue M68kTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CCID, bool IsVarArg, @@ -1052,7 +1079,7 @@ M68kTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CCID, CCState CCInfo(CCID, IsVarArg, MF, RVLocs, *DAG.getContext()); CCInfo.AnalyzeReturn(Outs, RetCC_M68k); - SDValue Flag; + SDValue Glue; SmallVector<SDValue, 6> RetOps; // Operand #0 = Chain (updated below) RetOps.push_back(Chain); @@ -1080,8 +1107,8 @@ M68kTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CCID, } else if (VA.getLocInfo() == CCValAssign::BCvt) ValToCopy = DAG.getBitcast(VA.getLocVT(), ValToCopy); - Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), ValToCopy, Flag); - Flag = Chain.getValue(1); + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), ValToCopy, Glue); + Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); } @@ -1123,8 +1150,8 @@ M68kTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CCID, // ??? How will this work if CC does not use registers for args passing? // ??? What if I return multiple structs? unsigned RetValReg = M68k::D0; - Chain = DAG.getCopyToReg(Chain, DL, RetValReg, Val, Flag); - Flag = Chain.getValue(1); + Chain = DAG.getCopyToReg(Chain, DL, RetValReg, Val, Glue); + Glue = Chain.getValue(1); RetOps.push_back( DAG.getRegister(RetValReg, getPointerTy(DAG.getDataLayout()))); @@ -1132,9 +1159,9 @@ M68kTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CCID, RetOps[0] = Chain; // Update chain. - // Add the flag if we have it. - if (Flag.getNode()) - RetOps.push_back(Flag); + // Add the glue if we have it. + if (Glue.getNode()) + RetOps.push_back(Glue); return DAG.getNode(M68kISD::RET, DL, MVT::Other, RetOps); } @@ -1267,9 +1294,9 @@ bool M68kTargetLowering::IsEligibleForTailCallOptimization( CCState CCInfo(CalleeCC, IsVarArg, MF, ArgLocs, C); CCInfo.AnalyzeCallOperands(Outs, CC_M68k); - StackArgsSize = CCInfo.getNextStackOffset(); + StackArgsSize = CCInfo.getStackSize(); - if (CCInfo.getNextStackOffset()) { + if (StackArgsSize) { // Check if the arguments are already laid out in the right way as // the caller's fixed stack objects. MachineFrameInfo &MFI = MF.getFrameInfo(); @@ -1391,7 +1418,108 @@ SDValue M68kTargetLowering::LowerOperation(SDValue Op, return LowerShiftRightParts(Op, DAG, true); case ISD::SRL_PARTS: return LowerShiftRightParts(Op, DAG, false); + case ISD::ATOMIC_FENCE: + return LowerATOMICFENCE(Op, DAG); + case ISD::GlobalTLSAddress: + return LowerGlobalTLSAddress(Op, DAG); + } +} + +SDValue M68kTargetLowering::LowerExternalSymbolCall(SelectionDAG &DAG, + SDLoc Loc, + llvm::StringRef SymbolName, + ArgListTy &&ArgList) const { + PointerType *PtrTy = PointerType::get(*DAG.getContext(), 0); + CallLoweringInfo CLI(DAG); + CLI.setDebugLoc(Loc) + .setChain(DAG.getEntryNode()) + .setLibCallee(CallingConv::C, PtrTy, + DAG.getExternalSymbol(SymbolName.data(), + getPointerMemTy(DAG.getDataLayout())), + std::move(ArgList)); + return LowerCallTo(CLI).first; +} + +SDValue M68kTargetLowering::getTLSGetAddr(GlobalAddressSDNode *GA, + SelectionDAG &DAG, + unsigned TargetFlags) const { + SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); + SDValue TGA = DAG.getTargetGlobalAddress( + GA->getGlobal(), GA, GA->getValueType(0), GA->getOffset(), TargetFlags); + SDValue Arg = DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, GOT, TGA); + + PointerType *PtrTy = PointerType::get(*DAG.getContext(), 0); + + ArgListTy Args; + ArgListEntry Entry; + Entry.Node = Arg; + Entry.Ty = PtrTy; + Args.push_back(Entry); + return LowerExternalSymbolCall(DAG, SDLoc(GA), "__tls_get_addr", + std::move(Args)); +} + +SDValue M68kTargetLowering::getM68kReadTp(SDLoc Loc, SelectionDAG &DAG) const { + return LowerExternalSymbolCall(DAG, Loc, "__m68k_read_tp", ArgListTy()); +} + +SDValue M68kTargetLowering::LowerTLSGeneralDynamic(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + return getTLSGetAddr(GA, DAG, M68kII::MO_TLSGD); +} + +SDValue M68kTargetLowering::LowerTLSLocalDynamic(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + SDValue Addr = getTLSGetAddr(GA, DAG, M68kII::MO_TLSLDM); + SDValue TGA = + DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0), + GA->getOffset(), M68kII::MO_TLSLD); + return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, Addr); +} + +SDValue M68kTargetLowering::LowerTLSInitialExec(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); + SDValue Tp = getM68kReadTp(SDLoc(GA), DAG); + SDValue TGA = + DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0), + GA->getOffset(), M68kII::MO_TLSIE); + SDValue Addr = DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, GOT); + SDValue Offset = + DAG.getLoad(MVT::i32, SDLoc(GA), DAG.getEntryNode(), Addr, + MachinePointerInfo::getGOT(DAG.getMachineFunction())); + + return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, Offset, Tp); +} + +SDValue M68kTargetLowering::LowerTLSLocalExec(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + SDValue Tp = getM68kReadTp(SDLoc(GA), DAG); + SDValue TGA = + DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0), + GA->getOffset(), M68kII::MO_TLSLE); + return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, Tp); +} + +SDValue M68kTargetLowering::LowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { + assert(Subtarget.isTargetELF()); + + auto *GA = cast<GlobalAddressSDNode>(Op); + TLSModel::Model AccessModel = DAG.getTarget().getTLSModel(GA->getGlobal()); + + switch (AccessModel) { + case TLSModel::GeneralDynamic: + return LowerTLSGeneralDynamic(GA, DAG); + case TLSModel::LocalDynamic: + return LowerTLSLocalDynamic(GA, DAG); + case TLSModel::InitialExec: + return LowerTLSInitialExec(GA, DAG); + case TLSModel::LocalExec: + return LowerTLSLocalExec(GA, DAG); } + + llvm_unreachable("Unexpected TLS access model type"); } bool M68kTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT, @@ -1553,12 +1681,12 @@ static unsigned TranslateM68kCC(ISD::CondCode SetCCOpcode, const SDLoc &DL, SelectionDAG &DAG) { if (!IsFP) { if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) { - if (SetCCOpcode == ISD::SETGT && RHSC->isAllOnesValue()) { + if (SetCCOpcode == ISD::SETGT && RHSC->isAllOnes()) { // X > -1 -> X == 0, jump !sign. RHS = DAG.getConstant(0, DL, RHS.getValueType()); return M68k::COND_PL; } - if (SetCCOpcode == ISD::SETLT && RHSC->isNullValue()) { + if (SetCCOpcode == ISD::SETLT && RHSC->isZero()) { // X < 0 -> X == 0, jump on sign. return M68k::COND_MI; } @@ -2756,6 +2884,9 @@ M68kTargetLowering::getConstraintType(StringRef Constraint) const { break; } break; + case 'Q': + case 'U': + return C_Memory; default: break; } @@ -3220,6 +3351,28 @@ SDValue M68kTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { MachinePointerInfo(SV)); } +SDValue M68kTargetLowering::LowerATOMICFENCE(SDValue Op, + SelectionDAG &DAG) const { + // Lower to a memory barrier created from inline asm. + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + LLVMContext &Ctx = *DAG.getContext(); + + const unsigned Flags = InlineAsm::Extra_MayLoad | InlineAsm::Extra_MayStore | + InlineAsm::Extra_HasSideEffects; + const SDValue AsmOperands[4] = { + Op.getOperand(0), // Input chain + DAG.getTargetExternalSymbol( + "", TLI.getProgramPointerTy( + DAG.getDataLayout())), // Empty inline asm string + DAG.getMDNode(MDNode::get(Ctx, {})), // (empty) srcloc + DAG.getTargetConstant(Flags, SDLoc(Op), + TLI.getPointerTy(DAG.getDataLayout())), // Flags + }; + + return DAG.getNode(ISD::INLINEASM, SDLoc(Op), + DAG.getVTList(MVT::Other, MVT::Glue), AsmOperands); +} + // Lower dynamic stack allocation to _alloca call for Cygwin/Mingw targets. // Calls to _alloca are needed to probe the stack when allocating more than 4k // bytes in one go. Touching the stack at 4K increments is necessary to ensure |
