From a107ebd54d18e5f6079cc07b3ffd47129f40770a Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Tue, 15 Jul 2014 05:23:40 +0000 Subject: [PATCH] Revert "[FastISel][X86] Remove no longer needed functions." Revert "[FastISel][X86] Implement the FastLowerIntrinsicCall hook." Revert "[FastISel][X86] Implement the FastLowerCall hook." This reverts commit r213035, r213036, and r213037 to make the buildbots happy again. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213048 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86FastISel.cpp | 559 +++++++++++++++++++-------------- 1 file changed, 315 insertions(+), 244 deletions(-) diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index c093d7bbf81..ce554ba21d6 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -74,8 +74,6 @@ public: const LoadInst *LI) override; bool FastLowerArguments() override; - bool FastLowerCall(CallLoweringInfo &CLI) override; - bool FastLowerIntrinsicCall(const IntrinsicInst *II) override; #include "X86GenFastISel.inc" @@ -126,6 +124,11 @@ private: bool X86SelectFPExt(const Instruction *I); bool X86SelectFPTrunc(const Instruction *I); + bool X86VisitIntrinsicCall(const IntrinsicInst &I); + bool X86SelectCall(const Instruction *I); + + bool DoSelectCall(const Instruction *I, const char *MemIntName); + const X86InstrInfo *getInstrInfo() const { return getTargetMachine()->getInstrInfo(); } @@ -2163,8 +2166,8 @@ bool X86FastISel::TryEmitSmallMemcpy(X86AddressMode DestAM, return true; } -static bool isCommutativeIntrinsic(IntrinsicInst const *II) { - switch (II->getIntrinsicID()) { +static bool isCommutativeIntrinsic(IntrinsicInst const &I) { + switch (I.getIntrinsicID()) { case Intrinsic::sadd_with_overflow: case Intrinsic::uadd_with_overflow: case Intrinsic::smul_with_overflow: @@ -2175,12 +2178,12 @@ static bool isCommutativeIntrinsic(IntrinsicInst const *II) { } } -bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { +bool X86FastISel::X86VisitIntrinsicCall(const IntrinsicInst &I) { // FIXME: Handle more intrinsics. - switch (II->getIntrinsicID()) { + switch (I.getIntrinsicID()) { default: return false; case Intrinsic::frameaddress: { - Type *RetTy = II->getCalledFunction()->getReturnType(); + Type *RetTy = I.getCalledFunction()->getReturnType(); MVT VT; if (!isTypeLegal(RetTy, VT)) @@ -2220,7 +2223,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { // movq (%rax), %rax // ... unsigned DestReg; - unsigned Depth = cast(II->getOperand(0))->getZExtValue(); + unsigned Depth = cast(I.getOperand(0))->getZExtValue(); while (Depth--) { DestReg = createResultReg(RC); addDirectMem(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, @@ -2228,23 +2231,23 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { SrcReg = DestReg; } - UpdateValueMap(II, SrcReg); + UpdateValueMap(&I, SrcReg); return true; } case Intrinsic::memcpy: { - const MemCpyInst *MCI = cast(II); + const MemCpyInst &MCI = cast(I); // Don't handle volatile or variable length memcpys. - if (MCI->isVolatile()) + if (MCI.isVolatile()) return false; - if (isa(MCI->getLength())) { + if (isa(MCI.getLength())) { // Small memcpy's are common enough that we want to do them // without a call if possible. - uint64_t Len = cast(MCI->getLength())->getZExtValue(); + uint64_t Len = cast(MCI.getLength())->getZExtValue(); if (IsMemcpySmall(Len)) { X86AddressMode DestAM, SrcAM; - if (!X86SelectAddress(MCI->getRawDest(), DestAM) || - !X86SelectAddress(MCI->getRawSource(), SrcAM)) + if (!X86SelectAddress(MCI.getRawDest(), DestAM) || + !X86SelectAddress(MCI.getRawSource(), SrcAM)) return false; TryEmitSmallMemcpy(DestAM, SrcAM, Len); return true; @@ -2252,35 +2255,35 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { } unsigned SizeWidth = Subtarget->is64Bit() ? 64 : 32; - if (!MCI->getLength()->getType()->isIntegerTy(SizeWidth)) + if (!MCI.getLength()->getType()->isIntegerTy(SizeWidth)) return false; - if (MCI->getSourceAddressSpace() > 255 || MCI->getDestAddressSpace() > 255) + if (MCI.getSourceAddressSpace() > 255 || MCI.getDestAddressSpace() > 255) return false; - return LowerCallTo(II, "memcpy", II->getNumArgOperands() - 2); + return DoSelectCall(&I, "memcpy"); } case Intrinsic::memset: { - const MemSetInst *MSI = cast(II); + const MemSetInst &MSI = cast(I); - if (MSI->isVolatile()) + if (MSI.isVolatile()) return false; unsigned SizeWidth = Subtarget->is64Bit() ? 64 : 32; - if (!MSI->getLength()->getType()->isIntegerTy(SizeWidth)) + if (!MSI.getLength()->getType()->isIntegerTy(SizeWidth)) return false; - if (MSI->getDestAddressSpace() > 255) + if (MSI.getDestAddressSpace() > 255) return false; - return LowerCallTo(II, "memset", II->getNumArgOperands() - 2); + return DoSelectCall(&I, "memset"); } case Intrinsic::stackprotector: { // Emit code to store the stack guard onto the stack. EVT PtrTy = TLI.getPointerTy(); - const Value *Op1 = II->getArgOperand(0); // The guard's value. - const AllocaInst *Slot = cast(II->getArgOperand(1)); + const Value *Op1 = I.getArgOperand(0); // The guard's value. + const AllocaInst *Slot = cast(I.getArgOperand(1)); MFI.setStackProtectorIndex(FuncInfo.StaticAllocaMap[Slot]); @@ -2291,7 +2294,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { return true; } case Intrinsic::dbg_declare: { - const DbgDeclareInst *DI = cast(II); + const DbgDeclareInst *DI = cast(&I); X86AddressMode AM; assert(DI->getAddress() && "Null address should be checked earlier!"); if (!X86SelectAddress(DI->getAddress(), AM)) @@ -2311,7 +2314,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { if (!Subtarget->hasSSE1()) return false; - Type *RetTy = II->getCalledFunction()->getReturnType(); + Type *RetTy = I.getCalledFunction()->getReturnType(); MVT VT; if (!isTypeLegal(RetTy, VT)) @@ -2333,7 +2336,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { case MVT::f64: Opc = SqrtOpc[1][HasAVX]; RC = &X86::FR64RegClass; break; } - const Value *SrcVal = II->getArgOperand(0); + const Value *SrcVal = I.getArgOperand(0); unsigned SrcReg = getRegForValue(SrcVal); if (SrcReg == 0) @@ -2356,7 +2359,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { MIB.addReg(SrcReg); - UpdateValueMap(II, ResultReg); + UpdateValueMap(&I, ResultReg); return true; } case Intrinsic::sadd_with_overflow: @@ -2367,7 +2370,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { case Intrinsic::umul_with_overflow: { // This implements the basic lowering of the xalu with overflow intrinsics // into add/sub/mul followed by either seto or setb. - const Function *Callee = II->getCalledFunction(); + const Function *Callee = I.getCalledFunction(); auto *Ty = cast(Callee->getReturnType()); Type *RetTy = Ty->getTypeAtIndex(0U); Type *CondTy = Ty->getTypeAtIndex(1); @@ -2379,16 +2382,16 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { if (VT < MVT::i8 || VT > MVT::i64) return false; - const Value *LHS = II->getArgOperand(0); - const Value *RHS = II->getArgOperand(1); + const Value *LHS = I.getArgOperand(0); + const Value *RHS = I.getArgOperand(1); // Canonicalize immediate to the RHS. if (isa(LHS) && !isa(RHS) && - isCommutativeIntrinsic(II)) + isCommutativeIntrinsic(I)) std::swap(LHS, RHS); unsigned BaseOpc, CondOpc; - switch (II->getIntrinsicID()) { + switch (I.getIntrinsicID()) { default: llvm_unreachable("Unexpected intrinsic!"); case Intrinsic::sadd_with_overflow: BaseOpc = ISD::ADD; CondOpc = X86::SETOr; break; @@ -2465,7 +2468,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CondOpc), ResultReg2); - UpdateValueMap(II, ResultReg, 2); + UpdateValueMap(&I, ResultReg, 2); return true; } case Intrinsic::x86_sse_cvttss2si: @@ -2473,7 +2476,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { case Intrinsic::x86_sse2_cvttsd2si: case Intrinsic::x86_sse2_cvttsd2si64: { bool IsInputDouble; - switch (II->getIntrinsicID()) { + switch (I.getIntrinsicID()) { default: llvm_unreachable("Unexpected intrinsic."); case Intrinsic::x86_sse_cvttss2si: case Intrinsic::x86_sse_cvttss2si64: @@ -2489,7 +2492,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { break; } - Type *RetTy = II->getCalledFunction()->getReturnType(); + Type *RetTy = I.getCalledFunction()->getReturnType(); MVT VT; if (!isTypeLegal(RetTy, VT)) return false; @@ -2509,7 +2512,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { } // Check if we can fold insertelement instructions into the convert. - const Value *Op = II->getArgOperand(0); + const Value *Op = I.getArgOperand(0); while (auto *IE = dyn_cast(Op)) { const Value *Index = IE->getOperand(2); if (!isa(Index)) @@ -2531,7 +2534,7 @@ bool X86FastISel::FastLowerIntrinsicCall(const IntrinsicInst *II) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) .addReg(Reg); - UpdateValueMap(II, ResultReg); + UpdateValueMap(&I, ResultReg); return true; } } @@ -2632,52 +2635,53 @@ bool X86FastISel::FastLowerArguments() { return true; } -static unsigned computeBytesPoppedByCallee(const X86Subtarget *Subtarget, - CallingConv::ID CC, - ImmutableCallSite *CS) { - if (Subtarget->is64Bit()) +bool X86FastISel::X86SelectCall(const Instruction *I) { + const CallInst *CI = cast(I); + const Value *Callee = CI->getCalledValue(); + + // Can't handle inline asm yet. + if (isa(Callee)) + return false; + + // Handle intrinsic calls. + if (const IntrinsicInst *II = dyn_cast(CI)) + return X86VisitIntrinsicCall(*II); + + // Allow SelectionDAG isel to handle tail calls. + if (cast(I)->isTailCall()) + return false; + + return DoSelectCall(I, nullptr); +} + +static unsigned computeBytesPoppedByCallee(const X86Subtarget &Subtarget, + const ImmutableCallSite &CS) { + if (Subtarget.is64Bit()) return 0; - if (Subtarget->getTargetTriple().isOSMSVCRT()) + if (Subtarget.getTargetTriple().isOSMSVCRT()) return 0; - if (CC == CallingConv::Fast || CC == CallingConv::GHC || - CC == CallingConv::HiPE) + CallingConv::ID CC = CS.getCallingConv(); + if (CC == CallingConv::Fast || CC == CallingConv::GHC) return 0; - if (CS && !CS->paramHasAttr(1, Attribute::StructRet)) + if (!CS.paramHasAttr(1, Attribute::StructRet)) return 0; - if (CS && CS->paramHasAttr(1, Attribute::InReg)) + if (CS.paramHasAttr(1, Attribute::InReg)) return 0; return 4; } -bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { - auto &OutVals = CLI.OutVals; - auto &OutFlags = CLI.OutFlags; - auto &OutRegs = CLI.OutRegs; - auto &Ins = CLI.Ins; - auto &InRegs = CLI.InRegs; - CallingConv::ID CC = CLI.CallConv; - bool &IsTailCall = CLI.IsTailCall; - bool IsVarArg = CLI.IsVarArg; - const Value *Callee = CLI.Callee; - const char *SymName = CLI.SymName; - - bool Is64Bit = Subtarget->is64Bit(); - bool IsWin64 = Subtarget->isCallingConvWin64(CC); - - // Handle only C, fastcc, and webkit_js calling conventions for now. - switch (CC) { - default: return false; - case CallingConv::C: - case CallingConv::Fast: - case CallingConv::WebKit_JS: - case CallingConv::X86_FastCall: - case CallingConv::X86_64_Win64: - case CallingConv::X86_64_SysV: - break; - } - - // Allow SelectionDAG isel to handle tail calls. - if (IsTailCall) +// Select either a call, or an llvm.memcpy/memmove/memset intrinsic +bool X86FastISel::DoSelectCall(const Instruction *I, const char *MemIntName) { + const CallInst *CI = cast(I); + const Value *Callee = CI->getCalledValue(); + + // Handle only C and fastcc calling conventions for now. + ImmutableCallSite CS(CI); + CallingConv::ID CC = CS.getCallingConv(); + bool isWin64 = Subtarget->isCallingConvWin64(CC); + if (CC != CallingConv::C && CC != CallingConv::Fast && + CC != CallingConv::X86_FastCall && CC != CallingConv::X86_64_Win64 && + CC != CallingConv::X86_64_SysV) return false; // fastcc with -tailcallopt is intended to provide a guaranteed @@ -2685,78 +2689,150 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { if (CC == CallingConv::Fast && TM.Options.GuaranteedTailCallOpt) return false; + PointerType *PT = cast(CS.getCalledValue()->getType()); + FunctionType *FTy = cast(PT->getElementType()); + bool isVarArg = FTy->isVarArg(); + // Don't know how to handle Win64 varargs yet. Nothing special needed for - // x86-32. Special handling for x86-64 is implemented. - if (IsVarArg && IsWin64) + // x86-32. Special handling for x86-64 is implemented. + if (isVarArg && isWin64) return false; // Don't know about inalloca yet. - if (CLI.CS && CLI.CS->hasInAllocaArgument()) + if (CS.hasInAllocaArgument()) return false; // Fast-isel doesn't know about callee-pop yet. - if (X86::isCalleePop(CC, Subtarget->is64Bit(), IsVarArg, + if (X86::isCalleePop(CC, Subtarget->is64Bit(), isVarArg, TM.Options.GuaranteedTailCallOpt)) return false; - // If this is a constant i1/i8/i16 argument, promote to i32 to avoid an extra - // instruction. This is safe because it is common to all FastISel supported - // calling conventions on x86. - for (int i = 0, e = OutVals.size(); i != e; ++i) { - Value *&Val = OutVals[i]; - ISD::ArgFlagsTy Flags = OutFlags[i]; - if (auto *CI = dyn_cast(Val)) { - if (CI->getBitWidth() < 32) { + // Check whether the function can return without sret-demotion. + SmallVector Outs; + GetReturnInfo(I->getType(), CS.getAttributes(), Outs, TLI); + bool CanLowerReturn = TLI.CanLowerReturn(CS.getCallingConv(), + *FuncInfo.MF, FTy->isVarArg(), + Outs, FTy->getContext()); + if (!CanLowerReturn) + return false; + + // Materialize callee address in a register. FIXME: GV address can be + // handled with a CALLpcrel32 instead. + X86AddressMode CalleeAM; + if (!X86SelectCallAddress(Callee, CalleeAM)) + return false; + unsigned CalleeOp = 0; + const GlobalValue *GV = nullptr; + if (CalleeAM.GV != nullptr) { + GV = CalleeAM.GV; + } else if (CalleeAM.Base.Reg != 0) { + CalleeOp = CalleeAM.Base.Reg; + } else + return false; + + // Deal with call operands first. + SmallVector ArgVals; + SmallVector Args; + SmallVector ArgVTs; + SmallVector ArgFlags; + unsigned arg_size = CS.arg_size(); + Args.reserve(arg_size); + ArgVals.reserve(arg_size); + ArgVTs.reserve(arg_size); + ArgFlags.reserve(arg_size); + for (ImmutableCallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end(); + i != e; ++i) { + // If we're lowering a mem intrinsic instead of a regular call, skip the + // last two arguments, which should not passed to the underlying functions. + if (MemIntName && e-i <= 2) + break; + Value *ArgVal = *i; + ISD::ArgFlagsTy Flags; + unsigned AttrInd = i - CS.arg_begin() + 1; + if (CS.paramHasAttr(AttrInd, Attribute::SExt)) + Flags.setSExt(); + if (CS.paramHasAttr(AttrInd, Attribute::ZExt)) + Flags.setZExt(); + + if (CS.paramHasAttr(AttrInd, Attribute::ByVal)) { + PointerType *Ty = cast(ArgVal->getType()); + Type *ElementTy = Ty->getElementType(); + unsigned FrameSize = DL.getTypeAllocSize(ElementTy); + unsigned FrameAlign = CS.getParamAlignment(AttrInd); + if (!FrameAlign) + FrameAlign = TLI.getByValTypeAlignment(ElementTy); + Flags.setByVal(); + Flags.setByValSize(FrameSize); + Flags.setByValAlign(FrameAlign); + if (!IsMemcpySmall(FrameSize)) + return false; + } + + if (CS.paramHasAttr(AttrInd, Attribute::InReg)) + Flags.setInReg(); + if (CS.paramHasAttr(AttrInd, Attribute::Nest)) + Flags.setNest(); + + // If this is an i1/i8/i16 argument, promote to i32 to avoid an extra + // instruction. This is safe because it is common to all fastisel supported + // calling conventions on x86. + if (ConstantInt *CI = dyn_cast(ArgVal)) { + if (CI->getBitWidth() == 1 || CI->getBitWidth() == 8 || + CI->getBitWidth() == 16) { if (Flags.isSExt()) - Val = ConstantExpr::getSExt(CI, Type::getInt32Ty(CI->getContext())); + ArgVal = ConstantExpr::getSExt(CI,Type::getInt32Ty(CI->getContext())); else - Val = ConstantExpr::getZExt(CI, Type::getInt32Ty(CI->getContext())); + ArgVal = ConstantExpr::getZExt(CI,Type::getInt32Ty(CI->getContext())); } } + unsigned ArgReg; + // Passing bools around ends up doing a trunc to i1 and passing it. // Codegen this as an argument + "and 1". - if (auto *TI = dyn_cast(Val)) { - if (TI->getType()->isIntegerTy(1) && CLI.CS && - (TI->getParent() == CLI.CS->getInstruction()->getParent()) && - TI->hasOneUse()) { - Val = cast(Val)->getOperand(0); - unsigned ResultReg = getRegForValue(Val); - - if (!ResultReg) - return false; + if (ArgVal->getType()->isIntegerTy(1) && isa(ArgVal) && + cast(ArgVal)->getParent() == I->getParent() && + ArgVal->hasOneUse()) { + ArgVal = cast(ArgVal)->getOperand(0); + ArgReg = getRegForValue(ArgVal); + if (ArgReg == 0) return false; + + MVT ArgVT; + if (!isTypeLegal(ArgVal->getType(), ArgVT)) return false; + + ArgReg = FastEmit_ri(ArgVT, ArgVT, ISD::AND, ArgReg, + ArgVal->hasOneUse(), 1); + } else { + ArgReg = getRegForValue(ArgVal); + } - MVT ArgVT; - if (!isTypeLegal(Val->getType(), ArgVT)) - return false; + if (ArgReg == 0) return false; - ResultReg = - FastEmit_ri(ArgVT, ArgVT, ISD::AND, ResultReg, Val->hasOneUse(), 1); + Type *ArgTy = ArgVal->getType(); + MVT ArgVT; + if (!isTypeLegal(ArgTy, ArgVT)) + return false; + if (ArgVT == MVT::x86mmx) + return false; + unsigned OriginalAlignment = DL.getABITypeAlignment(ArgTy); + Flags.setOrigAlign(OriginalAlignment); - if (!ResultReg) - return false; - UpdateValueMap(Val, ResultReg); - } - } + Args.push_back(ArgReg); + ArgVals.push_back(ArgVal); + ArgVTs.push_back(ArgVT); + ArgFlags.push_back(Flags); } // Analyze operands of the call, assigning locations to each operand. SmallVector ArgLocs; - CCState CCInfo(CC, IsVarArg, *FuncInfo.MF, TM, ArgLocs, - CLI.RetTy->getContext()); + CCState CCInfo(CC, isVarArg, *FuncInfo.MF, TM, ArgLocs, + I->getParent()->getContext()); // Allocate shadow area for Win64 - if (IsWin64) + if (isWin64) CCInfo.AllocateStack(32, 8); - SmallVector OutVTs; - for (auto *Val : OutVals) { - MVT VT; - if (!isTypeLegal(Val->getType(), VT, true)) - return false; - OutVTs.push_back(VT); - } - CCInfo.AnalyzeCallOperands(OutVTs, OutFlags, CC_X86); + CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CC_X86); // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getNextStackOffset(); @@ -2766,20 +2842,13 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AdjStackDown)) .addImm(NumBytes); - // Walk the register/memloc assignments, inserting copies/loads. - const X86RegisterInfo *RegInfo = - static_cast(TM.getRegisterInfo()); + // Process argument: walk the register/memloc assignments, inserting + // copies / loads. + SmallVector RegArgs; for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { - CCValAssign const &VA = ArgLocs[i]; - const Value *ArgVal = OutVals[VA.getValNo()]; - MVT ArgVT = OutVTs[VA.getValNo()]; - - if (ArgVT == MVT::x86mmx) - return false; - - unsigned ArgReg = getRegForValue(ArgVal); - if (!ArgReg) - return false; + CCValAssign &VA = ArgLocs[i]; + unsigned Arg = Args[VA.getValNo()]; + EVT ArgVT = ArgVTs[VA.getValNo()]; // Promote the value if needed. switch (VA.getLocInfo()) { @@ -2787,8 +2856,8 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { case CCValAssign::SExt: { assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() && "Unexpected extend"); - bool Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), ArgReg, - ArgVT, ArgReg); + bool Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); assert(Emitted && "Failed to emit a sext!"); (void)Emitted; ArgVT = VA.getLocVT(); break; @@ -2796,8 +2865,8 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { case CCValAssign::ZExt: { assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() && "Unexpected extend"); - bool Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), ArgReg, - ArgVT, ArgReg); + bool Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); assert(Emitted && "Failed to emit a zext!"); (void)Emitted; ArgVT = VA.getLocVT(); break; @@ -2805,67 +2874,66 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { case CCValAssign::AExt: { assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() && "Unexpected extend"); - bool Emitted = X86FastEmitExtend(ISD::ANY_EXTEND, VA.getLocVT(), ArgReg, - ArgVT, ArgReg); + bool Emitted = X86FastEmitExtend(ISD::ANY_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); if (!Emitted) - Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), ArgReg, - ArgVT, ArgReg); + Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); if (!Emitted) - Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), ArgReg, - ArgVT, ArgReg); + Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); assert(Emitted && "Failed to emit a aext!"); (void)Emitted; ArgVT = VA.getLocVT(); break; } case CCValAssign::BCvt: { - ArgReg = FastEmit_r(ArgVT, VA.getLocVT(), ISD::BITCAST, ArgReg, - /*TODO: Kill=*/false); - assert(ArgReg && "Failed to emit a bitcast!"); + unsigned BC = FastEmit_r(ArgVT.getSimpleVT(), VA.getLocVT(), + ISD::BITCAST, Arg, /*TODO: Kill=*/false); + assert(BC != 0 && "Failed to emit a bitcast!"); + Arg = BC; ArgVT = VA.getLocVT(); break; } - case CCValAssign::VExt: + case CCValAssign::VExt: // VExt has not been implemented, so this should be impossible to reach // for now. However, fallback to Selection DAG isel once implemented. return false; - case CCValAssign::FPExt: - llvm_unreachable("Unexpected loc info!"); case CCValAssign::Indirect: // FIXME: Indirect doesn't need extending, but fast-isel doesn't fully // support this. return false; + case CCValAssign::FPExt: + llvm_unreachable("Unexpected loc info!"); } if (VA.isRegLoc()) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(ArgReg); - OutRegs.push_back(VA.getLocReg()); + TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(Arg); + RegArgs.push_back(VA.getLocReg()); } else { - assert(VA.isMemLoc()); unsigned LocMemOffset = VA.getLocMemOffset(); X86AddressMode AM; + const X86RegisterInfo *RegInfo = static_cast( + getTargetMachine()->getRegisterInfo()); AM.Base.Reg = RegInfo->getStackRegister(); AM.Disp = LocMemOffset; - ISD::ArgFlagsTy Flags = OutFlags[VA.getValNo()]; - unsigned Alignment = DL.getABITypeAlignment(ArgVal->getType()); - MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand( - MachinePointerInfo::getStack(LocMemOffset), MachineMemOperand::MOStore, - ArgVT.getStoreSize(), Alignment); + const Value *ArgVal = ArgVals[VA.getValNo()]; + ISD::ArgFlagsTy Flags = ArgFlags[VA.getValNo()]; + if (Flags.isByVal()) { X86AddressMode SrcAM; - SrcAM.Base.Reg = ArgReg; - if (!TryEmitSmallMemcpy(AM, SrcAM, Flags.getByValSize())) - return false; + SrcAM.Base.Reg = Arg; + bool Res = TryEmitSmallMemcpy(AM, SrcAM, Flags.getByValSize()); + assert(Res && "memcpy length already checked!"); (void)Res; } else if (isa(ArgVal) || isa(ArgVal)) { // If this is a really simple value, emit this with the Value* version // of X86FastEmitStore. If it isn't simple, we don't want to do this, // as it can cause us to reevaluate the argument. - if (!X86FastEmitStore(ArgVT, ArgVal, AM, MMO)) + if (!X86FastEmitStore(ArgVT, ArgVal, AM)) return false; } else { - bool ValIsKill = hasTrivialKill(ArgVal); - if (!X86FastEmitStore(ArgVT, ArgReg, ValIsKill, AM, MMO)) + if (!X86FastEmitStore(ArgVT, Arg, /*ValIsKill=*/false, AM)) return false; } } @@ -2879,53 +2947,37 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { TII.get(TargetOpcode::COPY), X86::EBX).addReg(Base); } - if (Is64Bit && IsVarArg && !IsWin64) { - // From AMD64 ABI document: - // For calls that may call functions that use varargs or stdargs - // (prototype-less calls or calls to functions containing ellipsis (...) in - // the declaration) %al is used as hidden argument to specify the number - // of SSE registers used. The contents of %al do not need to match exactly - // the number of registers, but must be an ubound on the number of SSE - // registers used and is in the range 0 - 8 inclusive. - + if (Subtarget->is64Bit() && isVarArg && !isWin64) { // Count the number of XMM registers allocated. static const MCPhysReg XMMArgRegs[] = { X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3, X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7 }; unsigned NumXMMRegs = CCInfo.getFirstUnallocated(XMMArgRegs, 8); - assert((Subtarget->hasSSE1() || !NumXMMRegs) - && "SSE registers cannot be used when SSE is disabled"); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOV8ri), X86::AL).addImm(NumXMMRegs); } - // Materialize callee address in a register. FIXME: GV address can be - // handled with a CALLpcrel32 instead. - X86AddressMode CalleeAM; - if (!X86SelectCallAddress(Callee, CalleeAM)) - return false; - - unsigned CalleeOp = 0; - const GlobalValue *GV = nullptr; - if (CalleeAM.GV != nullptr) { - GV = CalleeAM.GV; - } else if (CalleeAM.Base.Reg != 0) { - CalleeOp = CalleeAM.Base.Reg; - } else - return false; - // Issue the call. MachineInstrBuilder MIB; if (CalleeOp) { // Register-indirect call. - unsigned CallOpc = Is64Bit ? X86::CALL64r : CallOpc = X86::CALL32r; + unsigned CallOpc; + if (Subtarget->is64Bit()) + CallOpc = X86::CALL64r; + else + CallOpc = X86::CALL32r; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CallOpc)) .addReg(CalleeOp); + } else { // Direct call. assert(GV && "Not a direct call"); - unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32; + unsigned CallOpc; + if (Subtarget->is64Bit()) + CallOpc = X86::CALL64pcrel32; + else + CallOpc = X86::CALLpcrel32; // See if we need any target-specific flags on the GV operand. unsigned char OpFlags = 0; @@ -2948,97 +3000,114 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { OpFlags = X86II::MO_DARWIN_STUB; } + MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CallOpc)); - if (SymName) - MIB.addExternalSymbol(SymName, OpFlags); + if (MemIntName) + MIB.addExternalSymbol(MemIntName, OpFlags); else MIB.addGlobalAddress(GV, 0, OpFlags); } - // Add a register mask operand representing the call-preserved registers. + // Add a register mask with the call-preserved registers. // Proper defs for return values will be added by setPhysRegsDeadExcept(). - MIB.addRegMask(TRI.getCallPreservedMask(CC)); + MIB.addRegMask(TRI.getCallPreservedMask(CS.getCallingConv())); // Add an implicit use GOT pointer in EBX. if (Subtarget->isPICStyleGOT()) MIB.addReg(X86::EBX, RegState::Implicit); - if (Is64Bit && IsVarArg && !IsWin64) + if (Subtarget->is64Bit() && isVarArg && !isWin64) MIB.addReg(X86::AL, RegState::Implicit); // Add implicit physical register uses to the call. - for (auto Reg : OutRegs) - MIB.addReg(Reg, RegState::Implicit); + for (unsigned i = 0, e = RegArgs.size(); i != e; ++i) + MIB.addReg(RegArgs[i], RegState::Implicit); // Issue CALLSEQ_END - unsigned NumBytesForCalleeToPop = - computeBytesPoppedByCallee(Subtarget, CC, CLI.CS); unsigned AdjStackUp = TII.getCallFrameDestroyOpcode(); + const unsigned NumBytesCallee = computeBytesPoppedByCallee(*Subtarget, CS); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AdjStackUp)) - .addImm(NumBytes).addImm(NumBytesForCalleeToPop); + .addImm(NumBytes).addImm(NumBytesCallee); + + // Build info for return calling conv lowering code. + // FIXME: This is practically a copy-paste from TargetLowering::LowerCallTo. + SmallVector Ins; + SmallVector RetTys; + ComputeValueVTs(TLI, I->getType(), RetTys); + for (unsigned i = 0, e = RetTys.size(); i != e; ++i) { + EVT VT = RetTys[i]; + MVT RegisterVT = TLI.getRegisterType(I->getParent()->getContext(), VT); + unsigned NumRegs = TLI.getNumRegisters(I->getParent()->getContext(), VT); + for (unsigned j = 0; j != NumRegs; ++j) { + ISD::InputArg MyFlags; + MyFlags.VT = RegisterVT; + MyFlags.Used = !CS.getInstruction()->use_empty(); + if (CS.paramHasAttr(0, Attribute::SExt)) + MyFlags.Flags.setSExt(); + if (CS.paramHasAttr(0, Attribute::ZExt)) + MyFlags.Flags.setZExt(); + if (CS.paramHasAttr(0, Attribute::InReg)) + MyFlags.Flags.setInReg(); + Ins.push_back(MyFlags); + } + } // Now handle call return values. + SmallVector UsedRegs; SmallVector RVLocs; - CCState CCRetInfo(CC, IsVarArg, *FuncInfo.MF, TM, RVLocs, - CLI.RetTy->getContext()); + CCState CCRetInfo(CC, false, *FuncInfo.MF, TM, RVLocs, + I->getParent()->getContext()); + unsigned ResultReg = FuncInfo.CreateRegs(I->getType()); CCRetInfo.AnalyzeCallResult(Ins, RetCC_X86); - - // Copy all of the result registers out of their specified physreg. - unsigned ResultReg = FuncInfo.CreateRegs(CLI.RetTy); for (unsigned i = 0; i != RVLocs.size(); ++i) { - CCValAssign &VA = RVLocs[i]; - EVT CopyVT = VA.getValVT(); + EVT CopyVT = RVLocs[i].getValVT(); unsigned CopyReg = ResultReg + i; - // If this is x86-64, and we disabled SSE, we can't return FP values - if ((CopyVT == MVT::f32 || CopyVT == MVT::f64) && - ((Is64Bit || Ins[i].Flags.isInReg()) && !Subtarget->hasSSE1())) { - report_fatal_error("SSE register return with SSE disabled"); - } - - // If this is a call to a function that returns an fp value on the floating - // point stack, we must guarantee the value is popped from the stack, so - // a COPY is not good enough - the copy instruction may be eliminated if the - // return value is not used. We use the FpPOP_RETVAL instruction instead. - if (VA.getLocReg() == X86::ST0 || VA.getLocReg() == X86::ST1) { - // If we prefer to use the value in xmm registers, copy it out as f80 and - // use a truncate to move it from fp stack reg to xmm reg. - if (isScalarFPTypeInSSEReg(VA.getValVT())) { + // If this is a call to a function that returns an fp value on the x87 fp + // stack, but where we prefer to use the value in xmm registers, copy it + // out as F80 and use a truncate to move it from fp stack reg to xmm reg. + if ((RVLocs[i].getLocReg() == X86::ST0 || + RVLocs[i].getLocReg() == X86::ST1)) { + if (isScalarFPTypeInSSEReg(RVLocs[i].getValVT())) { CopyVT = MVT::f80; CopyReg = createResultReg(&X86::RFP80RegClass); } BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::FpPOP_RETVAL), CopyReg); - - // Round the f80 to the right size, which also moves it to the appropriate - // xmm register. This is accomplished by storing the f80 value in memory - // and then loading it back. - if (CopyVT != VA.getValVT()) { - EVT ResVT = VA.getValVT(); - unsigned Opc = ResVT == MVT::f32 ? X86::ST_Fp80m32 : X86::ST_Fp80m64; - unsigned MemSize = ResVT.getSizeInBits()/8; - int FI = MFI.CreateStackObject(MemSize, MemSize, false); - addFrameReference(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(Opc)), FI) - .addReg(CopyReg); - Opc = ResVT == MVT::f32 ? X86::MOVSSrm : X86::MOVSDrm; - addFrameReference(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(Opc), ResultReg + i), FI); - } } else { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, - TII.get(TargetOpcode::COPY), CopyReg).addReg(VA.getLocReg()); - InRegs.push_back(VA.getLocReg()); + TII.get(TargetOpcode::COPY), + CopyReg).addReg(RVLocs[i].getLocReg()); + UsedRegs.push_back(RVLocs[i].getLocReg()); + } + + if (CopyVT != RVLocs[i].getValVT()) { + // Round the F80 the right size, which also moves to the appropriate xmm + // register. This is accomplished by storing the F80 value in memory and + // then loading it back. Ewww... + EVT ResVT = RVLocs[i].getValVT(); + unsigned Opc = ResVT == MVT::f32 ? X86::ST_Fp80m32 : X86::ST_Fp80m64; + unsigned MemSize = ResVT.getSizeInBits()/8; + int FI = MFI.CreateStackObject(MemSize, MemSize, false); + addFrameReference(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(Opc)), FI) + .addReg(CopyReg); + Opc = ResVT == MVT::f32 ? X86::MOVSSrm : X86::MOVSDrm; + addFrameReference(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(Opc), ResultReg + i), FI); } } - CLI.ResultReg = ResultReg; - CLI.NumResultRegs = RVLocs.size(); - CLI.Call = MIB; + if (RVLocs.size()) + UpdateValueMap(I, ResultReg, RVLocs.size()); + + // Set all unused physreg defs as dead. + static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); return true; } + bool X86FastISel::TargetSelectInstruction(const Instruction *I) { switch (I->getOpcode()) { @@ -3056,6 +3125,8 @@ X86FastISel::TargetSelectInstruction(const Instruction *I) { return X86SelectZExt(I); case Instruction::Br: return X86SelectBranch(I); + case Instruction::Call: + return X86SelectCall(I); case Instruction::LShr: case Instruction::AShr: case Instruction::Shl: -- 2.34.1