Index: lib/Target/Mips/MipsCallingConv.td =================================================================== --- lib/Target/Mips/MipsCallingConv.td +++ lib/Target/Mips/MipsCallingConv.td @@ -13,7 +13,7 @@ class CCIfSubtarget : CCIf" - "(State.getMachineFunction().getSubtarget()).", + "(State.getMachineFunction().getSubtarget()).", F), A>; @@ -51,6 +51,19 @@ // Mips O32 Calling Convention //===----------------------------------------------------------------------===// +def CC_MipsO32 : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i1, i8, i16], CCPromoteToType>, + + // Integer values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>>, + + // Integer values get stored in stack slots that are 8 bytes in + // size and 8-byte aligned. + CCIfType<[f64], CCAssignToStack<8, 8>> +]>; + // Only the return rules are defined here for O32. The rules for argument // passing are defined in MipsISelLowering.cpp. def RetCC_MipsO32 : CallingConv<[ Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -68,6 +68,8 @@ // Convenience variables to avoid some queries. LLVMContext *Context; + bool fastLowerCall(CallLoweringInfo &CLI) override; + bool TargetSupported; bool UnsupportedFPMode; // To allow fast-isel to proceed and just not handle // floating point but not reject doing fast-isel in other @@ -90,14 +92,17 @@ bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); bool computeAddress(const Value *Obj, Address &Addr); - + bool computeCallAddress(const Value *V, Address &Addr); // Emit helper routines. bool emitCmp(unsigned DestReg, const CmpInst *CI); bool emitLoad(MVT VT, unsigned &ResultReg, Address &Addr, unsigned Alignment = 0); + bool emitStore(MVT VT, unsigned SrcReg, Address Addr, + MachineMemOperand *MMO = nullptr); bool emitStore(MVT VT, unsigned SrcReg, Address &Addr, unsigned Alignment = 0); + unsigned emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt); bool emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg, bool IsZExt); @@ -140,6 +145,13 @@ return 0; } + // Call handling routines. +private: + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC) const; + bool processCallArgs(CallLoweringInfo &CLI, SmallVectorImpl &ArgVTs, + unsigned &NumBytes); + bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes); + public: // Backend specific FastISel code. unsigned fastMaterializeConstant(const Constant *C) override; @@ -166,6 +178,40 @@ }; } // end anonymous namespace. +#include "MipsGenCallingConv.inc" + +bool (*UnusedMipsFastISel1)(unsigned int, llvm::MVT, llvm::MVT, + CCValAssign::LocInfo, ISD::ArgFlagsTy, + llvm::CCState &) = CC_Mips16RetHelper; + +bool (*UnusedMipsFastISel2)(unsigned int, llvm::MVT, llvm::MVT, + CCValAssign::LocInfo, ISD::ArgFlagsTy, + llvm::CCState &) = CC_MipsN; + +bool (*UnusedMipsFastISel3)(unsigned int, llvm::MVT, llvm::MVT, + CCValAssign::LocInfo, ISD::ArgFlagsTy, + llvm::CCState &) = CC_MipsN_VarArg; + +bool (*UnusedMipsFastISel4)(unsigned int, llvm::MVT, llvm::MVT, + CCValAssign::LocInfo, ISD::ArgFlagsTy, + llvm::CCState &) = CC_Mips_FastCC; + +bool (*UnusedMipsFastISel5)(unsigned int, llvm::MVT, llvm::MVT, + CCValAssign::LocInfo, ISD::ArgFlagsTy, + llvm::CCState &) = RetCC_F128; + +bool (*UnusedMipsFastISel6)(unsigned int, llvm::MVT, llvm::MVT, + CCValAssign::LocInfo, ISD::ArgFlagsTy, + llvm::CCState &) = CC_MipsO32; + +bool (*UnusedMipsFastISel8)(unsigned int, llvm::MVT, llvm::MVT, + CCValAssign::LocInfo, ISD::ArgFlagsTy, + llvm::CCState &) = RetCC_Mips; + +CCAssignFn *MipsFastISel::CCAssignFnForCall(CallingConv::ID CC) const { + return CC_MipsO32; +} + unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) { if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) return 0; @@ -284,6 +330,19 @@ return Addr.getReg() != 0; } +bool MipsFastISel::computeCallAddress(const Value *V, Address &Addr) { + const GlobalValue *GV = dyn_cast(V); + if (GV && isa(GV) && dyn_cast(GV)->isIntrinsic()) + return false; + if (!GV) + return false; + if (const GlobalValue *GV = dyn_cast(V)) { + Addr.setGlobalValue(GV); + return true; + } + return false; +} + bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) { EVT evt = TLI.getValueType(Ty, true); // Only handle simple types. @@ -694,6 +753,248 @@ return true; } // +bool MipsFastISel::processCallArgs(CallLoweringInfo &CLI, + SmallVectorImpl &OutVTs, + unsigned &NumBytes) { + // for now we don't handle any arguments + CallingConv::ID CC = CLI.CallConv; + SmallVector ArgLocs; + CCState CCInfo(CC, false, *FuncInfo.MF, ArgLocs, *Context); + CCInfo.AnalyzeCallOperands(OutVTs, CLI.OutFlags, CCAssignFnForCall(CC)); + // Get a count of how many bytes are to be pushed on the stack. + NumBytes = CCInfo.getNextStackOffset(); + // this is the minimum argument area, used for A0-A3 if needed + if (NumBytes < 16) + NumBytes = 16; + + emitInst(Mips::ADJCALLSTACKDOWN).addImm(16); + // Process the args. + MVT firstMVT; + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + const Value *ArgVal = CLI.OutVals[VA.getValNo()]; + MVT ArgVT = OutVTs[VA.getValNo()]; + + if (i == 0) { + firstMVT = ArgVT; + if (ArgVT == MVT::f32) { + VA.convertToReg(Mips::F12); + } else if (ArgVT == MVT::f64) { + VA.convertToReg(Mips::D6); + } + } else if (i == 1) { + if ((firstMVT == MVT::f32) || (firstMVT == MVT::f64)) { + if (ArgVT == MVT::f32) { + VA.convertToReg(Mips::F14); + } else if (ArgVT == MVT::f64) { + VA.convertToReg(Mips::D7); + } + } + } + if (((ArgVT == MVT::i32) || (ArgVT == MVT::f32)) && VA.isMemLoc()) { + switch (VA.getLocMemOffset()) { + case 0: + VA.convertToReg(Mips::A0); + break; + case 4: + VA.convertToReg(Mips::A1); + break; + case 8: + VA.convertToReg(Mips::A2); + break; + case 12: + VA.convertToReg(Mips::A3); + break; + default: + break; + } + } + unsigned ArgReg = getRegForValue(ArgVal); + if (!ArgReg) + return false; + + // Handle arg promotion: SExt, ZExt, AExt. + switch (VA.getLocInfo()) { + case CCValAssign::Full: + break; + case CCValAssign::SExt: { + MVT DestVT = VA.getLocVT(); + MVT SrcVT = ArgVT; + ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/false); + if (!ArgReg) + return false; + break; + } + case CCValAssign::AExt: + // Intentional fall-through. + case CCValAssign::ZExt: { + MVT DestVT = VA.getLocVT(); + MVT SrcVT = ArgVT; + ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/true); + if (!ArgReg) + return false; + break; + } + default: + llvm_unreachable("Unknown arg promotion!"); + } + + // Now copy/store arg to correct locations. + if (VA.isRegLoc() && !VA.needsCustom()) { + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(ArgReg); + CLI.OutRegs.push_back(VA.getLocReg()); + } else if (VA.needsCustom()) { + // FIXME: Handle custom args. + return false; + } else { + assert(VA.isMemLoc() && "Assuming store on stack."); + // Don't emit stores for undef values. + if (isa(ArgVal)) + continue; + + // Need to store on the stack. + unsigned ArgSize = (ArgVT.getSizeInBits() + 7) / 8; + + unsigned BEAlign = 0; + if (ArgSize < 8 && !Subtarget->isLittle()) + BEAlign = 8 - ArgSize; + + Address Addr; + Addr.setKind(Address::RegBase); + Addr.setReg(Mips::SP); + Addr.setOffset(VA.getLocMemOffset() + BEAlign); + + unsigned Alignment = DL.getABITypeAlignment(ArgVal->getType()); + MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand( + MachinePointerInfo::getStack(Addr.getOffset()), + MachineMemOperand::MOStore, ArgVT.getStoreSize(), Alignment); + (void)(MMO); + // if (!emitStore(ArgVT, ArgReg, Addr, MMO)) + return false; // can't store on the stack yet. + } + } + + if (NumBytes < 16) + NumBytes = 16; + return true; +} + +bool MipsFastISel::finishCall(CallLoweringInfo &CLI, MVT RetVT, + unsigned NumBytes) { + CallingConv::ID CC = CLI.CallConv; + emitInst(Mips::ADJCALLSTACKUP).addImm(16); + if (RetVT != MVT::isVoid) { + SmallVector RVLocs; + CCState CCInfo(CC, false, *FuncInfo.MF, RVLocs, *Context); + CCInfo.AnalyzeCallResult(RetVT, RetCC_Mips); + + // Only handle a single return value. + if (RVLocs.size() != 1) + return false; + // Copy all of the result registers out of their specified physreg. + MVT CopyVT = RVLocs[0].getValVT(); + // Special handling for extended integers. + if (RetVT == MVT::i1 || RetVT == MVT::i8 || RetVT == MVT::i16) + CopyVT = MVT::i32; + + unsigned ResultReg = createResultReg(TLI.getRegClassFor(CopyVT)); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), + ResultReg).addReg(RVLocs[0].getLocReg()); + CLI.InRegs.push_back(RVLocs[0].getLocReg()); + + CLI.ResultReg = ResultReg; + CLI.NumResultRegs = 1; + } + return true; +} + +bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) { + CallingConv::ID CC = CLI.CallConv; + bool IsTailCall = CLI.IsTailCall; + bool IsVarArg = CLI.IsVarArg; + const Value *Callee = CLI.Callee; + // const char *SymName = CLI.SymName; + + // Allow SelectionDAG isel to handle tail calls. + if (IsTailCall) + return false; + + // Let SDISel handle vararg functions. + if (IsVarArg) + return false; + + // FIXME: Only handle *simple* calls for now. + MVT RetVT; + if (CLI.RetTy->isVoidTy()) + RetVT = MVT::isVoid; + else if (!isTypeLegal(CLI.RetTy, RetVT)) + return false; + + for (auto Flag : CLI.OutFlags) + if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal()) + return false; + + // Set up the argument vectors. + SmallVector OutVTs; + OutVTs.reserve(CLI.OutVals.size()); + + for (auto *Val : CLI.OutVals) { + MVT VT; + if (!isTypeLegal(Val->getType(), VT) && + !(VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16)) + return false; + + // We don't handle vector parameters yet. + if (VT.isVector() || VT.getSizeInBits() > 64) + return false; + + OutVTs.push_back(VT); + } + + Address Addr; + if (!computeCallAddress(Callee, Addr)) + return false; + + // Handle the arguments now that we've gotten them. + unsigned NumBytes; + if (!processCallArgs(CLI, OutVTs, NumBytes)) + return false; + + // Issue the call. + // emitInst(Mips::ADDu, Mips::GP).addReg(MFI->getGlobalBaseReg()).addReg( + // Mips::ZERO); + unsigned DestAddress = materializeGV(Addr.getGlobalValue(), MVT::i32); + emitInst(TargetOpcode::COPY, Mips::T9).addReg(DestAddress); + MachineInstrBuilder MIB = + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::JALR), + Mips::RA).addReg(Mips::T9); + // Mips::RA).addReg(DestAddress) + + // Add implicit physical register uses to the call. + for (auto Reg : CLI.OutRegs) + MIB.addReg(Reg, RegState::Implicit); + + // Add a register mask with the call-preserved registers. + // Proper defs for return values will be added by setPhysRegsDeadExcept(). + MIB.addRegMask(TRI.getCallPreservedMask(CC)); + + CLI.Call = MIB; + + // Add implicit physical register uses to the call. + for (auto Reg : CLI.OutRegs) + MIB.addReg(Reg, RegState::Implicit); + + // Add a register mask with the call-preserved registers. Proper + // defs for return values will be added by setPhysRegsDeadExcept(). + MIB.addRegMask(TRI.getCallPreservedMask(CC)); + + CLI.Call = MIB; + // Finish off the call including any return values. + return finishCall(CLI, RetVT, NumBytes); +} + bool MipsFastISel::selectRet(const Instruction *I) { const ReturnInst *Ret = cast(I); @@ -823,6 +1124,13 @@ return emitIntZExt(SrcVT, SrcReg, DestVT, DestReg); return emitIntSExt(SrcVT, SrcReg, DestVT, DestReg); } + +unsigned MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + bool isZExt) { + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + return emitIntExt(SrcVT, SrcReg, DestVT, DestReg, isZExt); +} + bool MipsFastISel::fastSelectInstruction(const Instruction *I) { if (!TargetSupported) return false; @@ -872,7 +1180,6 @@ return VReg; } - namespace llvm { FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) { Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -601,6 +601,53 @@ MachineBasicBlock *emitSEL_D(MachineInstr *MI, MachineBasicBlock *BB) const; }; + + class MipsCCState : public CCState { + private: + /// Identify lowered values that originated from f128 arguments and record + /// this for use by RetCC_MipsN. + void + PreAnalyzeCallResultForF128(const SmallVectorImpl &Ins, + const TargetLowering::CallLoweringInfo &CLI); + + /// Identify lowered values that originated from f128 arguments and record + /// this for use by RetCC_MipsN. + void PreAnalyzeReturnForF128(const SmallVectorImpl &Outs); + + /// Records whether the value has been lowered from an f128. + SmallVector OriginalArgWasF128; + + public: + MipsCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, + SmallVectorImpl &locs, LLVMContext &C) + : CCState(CC, isVarArg, MF, locs, C) {} + + void AnalyzeCallResult(const SmallVectorImpl &Ins, + CCAssignFn Fn, + const TargetLowering::CallLoweringInfo &CLI) { + PreAnalyzeCallResultForF128(Ins, CLI); + CCState::AnalyzeCallResult(Ins, Fn); + OriginalArgWasF128.clear(); + } + + void AnalyzeReturn(const SmallVectorImpl &Outs, + CCAssignFn Fn) { + PreAnalyzeReturnForF128(Outs); + CCState::AnalyzeReturn(Outs, Fn); + OriginalArgWasF128.clear(); + } + + bool CheckReturn(const SmallVectorImpl &ArgsFlags, + CCAssignFn Fn) { + PreAnalyzeReturnForF128(ArgsFlags); + bool Return = CCState::CheckReturn(ArgsFlags, Fn); + OriginalArgWasF128.clear(); + return Return; + } + + bool WasOriginalArgF128(unsigned ValNo) { return OriginalArgWasF128[ValNo]; } + }; + /// Create MipsTargetLowering objects. const MipsTargetLowering * createMips16TargetLowering(const MipsTargetMachine &TM, @@ -615,4 +662,5 @@ } } + #endif Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -73,63 +73,24 @@ static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode); -namespace { -class MipsCCState : public CCState { -private: - /// Identify lowered values that originated from f128 arguments and record - /// this for use by RetCC_MipsN. - void - PreAnalyzeCallResultForF128(const SmallVectorImpl &Ins, - const TargetLowering::CallLoweringInfo &CLI) { - for (unsigned i = 0; i < Ins.size(); ++i) - OriginalArgWasF128.push_back( - originalTypeIsF128(CLI.RetTy, CLI.Callee.getNode())); - } - - /// Identify lowered values that originated from f128 arguments and record - /// this for use by RetCC_MipsN. - void PreAnalyzeReturnForF128(const SmallVectorImpl &Outs) { - const MachineFunction &MF = getMachineFunction(); - for (unsigned i = 0; i < Outs.size(); ++i) - OriginalArgWasF128.push_back( - originalTypeIsF128(MF.getFunction()->getReturnType(), nullptr)); - } - - /// Records whether the value has been lowered from an f128. - SmallVector OriginalArgWasF128; - -public: - MipsCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, - SmallVectorImpl &locs, LLVMContext &C) - : CCState(CC, isVarArg, MF, locs, C) {} - - void AnalyzeCallResult(const SmallVectorImpl &Ins, - CCAssignFn Fn, - const TargetLowering::CallLoweringInfo &CLI) { - PreAnalyzeCallResultForF128(Ins, CLI); - CCState::AnalyzeCallResult(Ins, Fn); - OriginalArgWasF128.clear(); - } - void AnalyzeReturn(const SmallVectorImpl &Outs, - CCAssignFn Fn) { - PreAnalyzeReturnForF128(Outs); - CCState::AnalyzeReturn(Outs, Fn); - OriginalArgWasF128.clear(); - } - - bool CheckReturn(const SmallVectorImpl &ArgsFlags, - CCAssignFn Fn) { - PreAnalyzeReturnForF128(ArgsFlags); - bool Return = CCState::CheckReturn(ArgsFlags, Fn); - OriginalArgWasF128.clear(); - return Return; - } +void llvm::MipsCCState::PreAnalyzeCallResultForF128(const SmallVectorImpl &Ins, + const TargetLowering::CallLoweringInfo &CLI) { + for (unsigned i = 0; i < Ins.size(); ++i) + OriginalArgWasF128.push_back( + originalTypeIsF128(CLI.RetTy, CLI.Callee.getNode())); +} - bool WasOriginalArgF128(unsigned ValNo) { return OriginalArgWasF128[ValNo]; } -}; +/// Identify lowered values that originated from f128 arguments and record +/// this for use by RetCC_MipsN. +void llvm::MipsCCState::PreAnalyzeReturnForF128(const SmallVectorImpl &Outs) { + const MachineFunction &MF = getMachineFunction(); + for (unsigned i = 0; i < Outs.size(); ++i) + OriginalArgWasF128.push_back( + originalTypeIsF128(MF.getFunction()->getReturnType(), nullptr)); } + // If I is a shifted mask, set the size (Size) and the first bit of the // mask (Pos), and return true. // For example, if I is 0x003ff800, (Pos, Size) = (11, 11).