From bb3e5dad6685dd54625edae789d1a703f4107a69 Mon Sep 17 00:00:00 2001 From: Eric Christopher Date: Tue, 14 Sep 2010 23:03:37 +0000 Subject: [PATCH] Emit libcalls for SDIV, this requires some call infrastructure that needs to be shared a bit more widely around. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@113886 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMFastISel.cpp | 154 +++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp index 656b4502b14..54433b19a0b 100644 --- a/lib/Target/ARM/ARMFastISel.cpp +++ b/lib/Target/ARM/ARMFastISel.cpp @@ -24,6 +24,7 @@ #include "llvm/GlobalVariable.h" #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" +#include "llvm/Module.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" @@ -121,6 +122,7 @@ class ARMFastISel : public FastISel { virtual bool ARMSelectBinaryOp(const Instruction *I, unsigned ISDOpcode); virtual bool ARMSelectSIToFP(const Instruction *I); virtual bool ARMSelectFPToSI(const Instruction *I); + virtual bool ARMSelectSDiv(const Instruction *I); // Utility routines. private: @@ -139,6 +141,7 @@ class ARMFastISel : public FastISel { // Call handling routines. private: CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool Return); + bool ARMEmitLibcall(const Instruction *I, Function *F); // OptionalDef handling routines. private: @@ -931,6 +934,155 @@ CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC, bool Return) { } } +// A quick function that will emit a call for a named libcall in F with the +// vector of passed arguments for the Instruction in I. We can assume that we +// can emit a call for any libcall we can produce. This is an abridged version +// of the full call infrastructure since we won't need to worry about things +// like computed function pointers or strange arguments at call sites. +// TODO: Try to unify this and the normal call bits for ARM, then try to unify +// with X86. +bool ARMFastISel::ARMEmitLibcall(const Instruction *I, Function *F) { + CallingConv::ID CC = F->getCallingConv(); + + // Handle *simple* calls for now. + const Type *RetTy = F->getReturnType(); + EVT RetVT; + if (RetTy->isVoidTy()) + RetVT = MVT::isVoid; + else if (!isTypeLegal(RetTy, RetVT)) + return false; + + assert(!F->isVarArg() && "Vararg libcall?!"); + + // Abridged from the X86 FastISel call selection mechanism + SmallVector Args; + SmallVector ArgRegs; + SmallVector ArgVTs; + SmallVector ArgFlags; + Args.reserve(I->getNumOperands()); + ArgRegs.reserve(I->getNumOperands()); + ArgVTs.reserve(I->getNumOperands()); + ArgFlags.reserve(I->getNumOperands()); + for (unsigned i = 0; i < Args.size(); ++i) { + Value *Op = I->getOperand(i); + unsigned Arg = getRegForValue(Op); + if (Arg == 0) return false; + + const Type *ArgTy = Op->getType(); + EVT ArgVT; + if (!isTypeLegal(ArgTy, ArgVT)) return false; + + ISD::ArgFlagsTy Flags; + unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy); + Flags.setOrigAlign(OriginalAlignment); + + Args.push_back(Op); + ArgRegs.push_back(Arg); + ArgVTs.push_back(ArgVT); + ArgFlags.push_back(Flags); + } + + SmallVector ArgLocs; + CCState CCInfo(CC, false, TM, ArgLocs, F->getContext()); + CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CCAssignFnForCall(CC, false)); + + // Process the args. + SmallVector RegArgs; + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + unsigned Arg = ArgRegs[VA.getValNo()]; + EVT ArgVT = ArgVTs[VA.getValNo()]; + + // Should we ever have to promote? + switch (VA.getLocInfo()) { + case CCValAssign::Full: break; + default: + assert(false && "Handle arg promotion for libcalls?"); + return false; + } + + // Now copy/store arg to correct locations. + if (VA.isRegLoc()) { + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), + VA.getLocReg()).addReg(Arg); + RegArgs.push_back(VA.getLocReg()); + } else { + // Need to store + return false; + } + } + + // Issue the call, BLr9 for darwin, BL otherwise. + MachineInstrBuilder MIB; + unsigned CallOpc = Subtarget->isTargetDarwin() ? ARM::BLr9 : ARM::BL; + MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CallOpc)) + .addGlobalAddress(F, 0, 0); + + // Add implicit physical register uses to the call. + for (unsigned i = 0, e = RegArgs.size(); i != e; ++i) + MIB.addReg(RegArgs[i]); + + // Now the return value. + SmallVector UsedRegs; + if (RetVT.getSimpleVT().SimpleTy != MVT::isVoid) { + SmallVector RVLocs; + CCState CCInfo(CC, false, TM, RVLocs, F->getContext()); + CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true)); + + // Copy all of the result registers out of their specified physreg. + assert(RVLocs.size() == 1 && "Can't handle multi-value calls!"); + EVT CopyVT = RVLocs[0].getValVT(); + TargetRegisterClass* DstRC = TLI.getRegClassFor(CopyVT); + + unsigned ResultReg = createResultReg(DstRC); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), + ResultReg).addReg(RVLocs[0].getLocReg()); + UsedRegs.push_back(RVLocs[0].getLocReg()); + + // Finally update the result. + UpdateValueMap(I, ResultReg); + } + + // Set all unused physreg defs as dead. + static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); + + return true; +} + +bool ARMFastISel::ARMSelectSDiv(const Instruction *I) { + EVT VT; + const Type *Ty = I->getType(); + if (!isTypeLegal(Ty, VT)) + return false; + + // If we have integer div support we should have gotten already, emit a + // libcall. + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + if (VT == MVT::i16) + LC = RTLIB::SDIV_I16; + else if (VT == MVT::i32) + LC = RTLIB::SDIV_I32; + else if (VT == MVT::i64) + LC = RTLIB::SDIV_I64; + else if (VT == MVT::i128) + LC = RTLIB::SDIV_I128; + assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SDIV!"); + + // Binary operand with all the same type. + std::vector ArgTys; + ArgTys.push_back(Ty); + ArgTys.push_back(Ty); + const FunctionType *FTy = FunctionType::get(Ty, ArgTys, false); + Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, + TLI.getLibcallName(LC)); + if (Subtarget->isAAPCS_ABI()) + F->setCallingConv(CallingConv::ARM_AAPCS); + else + F->setCallingConv(I->getParent()->getParent()->getCallingConv()); + + return ARMEmitLibcall(I, F); +} + // TODO: SoftFP support. bool ARMFastISel::TargetSelectInstruction(const Instruction *I) { // No Thumb-1 for now. @@ -960,6 +1112,8 @@ bool ARMFastISel::TargetSelectInstruction(const Instruction *I) { return ARMSelectBinaryOp(I, ISD::FSUB); case Instruction::FMul: return ARMSelectBinaryOp(I, ISD::FMUL); + case Instruction::SDiv: + return ARMSelectSDiv(I); default: break; } return false; -- 2.34.1