[llvm-commits] [llvm] r113886 - /llvm/trunk/lib/Target/ARM/ARMFastISel.cpp
Eric Christopher
echristo at apple.com
Tue Sep 14 16:03:37 PDT 2010
Author: echristo
Date: Tue Sep 14 18:03:37 2010
New Revision: 113886
URL: http://llvm.org/viewvc/llvm-project?rev=113886&view=rev
Log:
Emit libcalls for SDIV, this requires some call infrastructure
that needs to be shared a bit more widely around.
Modified:
llvm/trunk/lib/Target/ARM/ARMFastISel.cpp
Modified: llvm/trunk/lib/Target/ARM/ARMFastISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMFastISel.cpp?rev=113886&r1=113885&r2=113886&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMFastISel.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMFastISel.cpp Tue Sep 14 18:03:37 2010
@@ -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 @@
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 @@
// 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 @@
}
}
+// 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<Value*, 8> Args;
+ SmallVector<unsigned, 8> ArgRegs;
+ SmallVector<EVT, 8> ArgVTs;
+ SmallVector<ISD::ArgFlagsTy, 8> 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<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CC, false, TM, ArgLocs, F->getContext());
+ CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CCAssignFnForCall(CC, false));
+
+ // Process the args.
+ SmallVector<unsigned, 4> 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<unsigned, 4> UsedRegs;
+ if (RetVT.getSimpleVT().SimpleTy != MVT::isVoid) {
+ SmallVector<CCValAssign, 16> 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<MachineInstr *>(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<const Type*> 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 @@
return ARMSelectBinaryOp(I, ISD::FSUB);
case Instruction::FMul:
return ARMSelectBinaryOp(I, ISD::FMUL);
+ case Instruction::SDiv:
+ return ARMSelectSDiv(I);
default: break;
}
return false;
More information about the llvm-commits
mailing list