<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Very cool. This should be useful for all kinds of stuff. A few minor comments below.<div><br><div><div>On Sep 14, 2010, at 4:03 PM, Eric Christopher wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>Author: echristo<br>Date: Tue Sep 14 18:03:37 2010<br>New Revision: 113886<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=113886&view=rev">http://llvm.org/viewvc/llvm-project?rev=113886&view=rev</a><br>Log:<br>Emit libcalls for SDIV, this requires some call infrastructure<br>that needs to be shared a bit more widely around.<br><font class="Apple-style-span" color="#000000"><font class="Apple-style-span" color="#144FAE"><br></font></font></div></blockquote><blockquote type="cite"><div>Modified:<br>    llvm/trunk/lib/Target/ARM/ARMFastISel.cpp<br><br>Modified: llvm/trunk/lib/Target/ARM/ARMFastISel.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMFastISel.cpp?rev=113886&r1=113885&r2=113886&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMFastISel.cpp?rev=113886&r1=113885&r2=113886&view=diff</a><br>==============================================================================<br>--- llvm/trunk/lib/Target/ARM/ARMFastISel.cpp (original)<br>+++ llvm/trunk/lib/Target/ARM/ARMFastISel.cpp Tue Sep 14 18:03:37 2010<br>@@ -24,6 +24,7 @@<br> #include "llvm/GlobalVariable.h"<br> #include "llvm/Instructions.h"<br> #include "llvm/IntrinsicInst.h"<br>+#include "llvm/Module.h"<br> #include "llvm/CodeGen/Analysis.h"<br> #include "llvm/CodeGen/FastISel.h"<br> #include "llvm/CodeGen/FunctionLoweringInfo.h"<br>@@ -121,6 +122,7 @@<br>     virtual bool ARMSelectBinaryOp(const Instruction *I, unsigned ISDOpcode);<br>     virtual bool ARMSelectSIToFP(const Instruction *I);<br>     virtual bool ARMSelectFPToSI(const Instruction *I);<br>+    virtual bool ARMSelectSDiv(const Instruction *I);<br><br></div></blockquote><div><br></div><div>You can remove the "ARM" prefix from these function names. They're members of the ARMFastISel class already, so no need to specify "ARM" twice.</div><div><br></div><div>If the idea is to differentiate from Thumb, it might be better to follow the idiom of the RegisterInfo classes and have a completely separate class for that, perhaps with a common base class if there's shared bits (probably will be; there is for the not-so-fast-isel).</div><div><br></div><br><blockquote type="cite"><div>     // Utility routines.<br>   private:<br>@@ -139,6 +141,7 @@<br>     // Call handling routines.<br>   private:<br>     CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool Return);<br>+    bool ARMEmitLibcall(const Instruction *I, Function *F);</div></blockquote><blockquote type="cite"><div>     // OptionalDef handling routines.<br>   private:<br>@@ -931,6 +934,155 @@<br>   }<br> }<br><br>+// A quick function that will emit a call for a named libcall in F with the<br>+// vector of passed arguments for the Instruction in I. We can assume that we<br>+// can emit a call for any libcall we can produce. This is an abridged version <br>+// of the full call infrastructure since we won't need to worry about things <br>+// like computed function pointers or strange arguments at call sites.<br>+// TODO: Try to unify this and the normal call bits for ARM, then try to unify<br>+// with X86.<br></div></blockquote><div><br></div><div>This stuff assumes the arguments all fit in registers for the time being if I follow right. Is that correct? Probably worth putting in a "return false" for cases where that's not true.</div><div><br></div><div><br></div><br><blockquote type="cite"><div>+bool ARMFastISel::ARMEmitLibcall(const Instruction *I, Function *F) {<br>+  CallingConv::ID CC = F->getCallingConv();<br>+  <br>+  // Handle *simple* calls for now.<br>+  const Type *RetTy = F->getReturnType();<br>+  EVT RetVT;<br>+  if (RetTy->isVoidTy())<br>+    RetVT = MVT::isVoid;<br>+  else if (!isTypeLegal(RetTy, RetVT))<br>+    return false;<br>+  <br>+  assert(!F->isVarArg() && "Vararg libcall?!");<br>+<br>+  // Abridged from the X86 FastISel call selection mechanism<br>+  SmallVector<Value*, 8> Args;<br>+  SmallVector<unsigned, 8> ArgRegs;<br>+  SmallVector<EVT, 8> ArgVTs;<br>+  SmallVector<ISD::ArgFlagsTy, 8> ArgFlags;<br>+  Args.reserve(I->getNumOperands());<br>+  ArgRegs.reserve(I->getNumOperands());<br>+  ArgVTs.reserve(I->getNumOperands());<br>+  ArgFlags.reserve(I->getNumOperands());<br>+  for (unsigned i = 0; i < Args.size(); ++i) {<br>+    Value *Op = I->getOperand(i);<br>+    unsigned Arg = getRegForValue(Op);<br>+    if (Arg == 0) return false;<br>+    <br>+    const Type *ArgTy = Op->getType();<br>+    EVT ArgVT;<br>+    if (!isTypeLegal(ArgTy, ArgVT)) return false;<br>+    <br>+    ISD::ArgFlagsTy Flags;<br>+    unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy);<br>+    Flags.setOrigAlign(OriginalAlignment);<br>+    <br>+    Args.push_back(Op);<br>+    ArgRegs.push_back(Arg);<br>+    ArgVTs.push_back(ArgVT);<br>+    ArgFlags.push_back(Flags);<br>+  }<br>+  <br>+  SmallVector<CCValAssign, 16> ArgLocs;</div></blockquote><blockquote type="cite"><div>+  CCState CCInfo(CC, false, TM, ArgLocs, F->getContext());<br>+  CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CCAssignFnForCall(CC, false));<br>+  <br>+  // Process the args.<br>+  SmallVector<unsigned, 4> RegArgs;<br>+  for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {<br>+    CCValAssign &VA = ArgLocs[i];<br>+    unsigned Arg = ArgRegs[VA.getValNo()];<br>+    EVT ArgVT = ArgVTs[VA.getValNo()];<br>+    <br>+    // Should we ever have to promote?<br>+    switch (VA.getLocInfo()) {<br>+      case CCValAssign::Full: break;<br>+      default:<br>+        assert(false && "Handle arg promotion for libcalls?");<br>+        return false;<br>+    }<br>+    <br>+    // Now copy/store arg to correct locations.<br>+    if (VA.isRegLoc()) {<br>+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY),<br>+        VA.getLocReg()).addReg(Arg);<br></div></blockquote><div><br></div><div>The COPY opcode automatically handles stuff like moving a value across register classes (e.g., floating point values being passed in GPRs), if I recall correctly, so this should be fine. Possibly worth validating that, though.</div><div><br></div><blockquote type="cite"><div>+      RegArgs.push_back(VA.getLocReg());<br>+    } else {<br>+      // Need to store<br>+      return false;<br>+    }<br>+  }<br>+  <br>+  // Issue the call, BLr9 for darwin, BL otherwise.<br></div></blockquote><blockquote type="cite"><div>+  MachineInstrBuilder MIB;<br>+  unsigned CallOpc = Subtarget->isTargetDarwin() ? ARM::BLr9 : ARM::BL;<br>+  MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CallOpc))<br>+        .addGlobalAddress(F, 0, 0);<br>+  <br>+  // Add implicit physical register uses to the call.<br>+  for (unsigned i = 0, e = RegArgs.size(); i != e; ++i)<br>+    MIB.addReg(RegArgs[i]);<br>+    <br>+  // Now the return value.<br>+  SmallVector<unsigned, 4> UsedRegs;<br>+  if (RetVT.getSimpleVT().SimpleTy != MVT::isVoid) {<br>+    SmallVector<CCValAssign, 16> RVLocs;<br>+    CCState CCInfo(CC, false, TM, RVLocs, F->getContext());<br>+    CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true));<br>+<br>+    // Copy all of the result registers out of their specified physreg.<br>+    assert(RVLocs.size() == 1 && "Can't handle multi-value calls!");<br>+    EVT CopyVT = RVLocs[0].getValVT();<br>+    TargetRegisterClass* DstRC = TLI.getRegClassFor(CopyVT);<br>+    <br>+    unsigned ResultReg = createResultReg(DstRC);<br>+    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY),<br>+            ResultReg).addReg(RVLocs[0].getLocReg());<br>+    UsedRegs.push_back(RVLocs[0].getLocReg());<br>+    <br>+    // Finally update the result.        <br>+    UpdateValueMap(I, ResultReg);<br>+  }<br>+  <br>+  // Set all unused physreg defs as dead.<br>+  static_cast<MachineInstr *>(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI);<br>+<br>+  return true;<br>+}<br>+<br>+bool ARMFastISel::ARMSelectSDiv(const Instruction *I) {<br>+  EVT VT;<br>+  const Type *Ty = I->getType();<br>+  if (!isTypeLegal(Ty, VT))<br>+    return false;<br>+    <br>+  // If we have integer div support we should have gotten already, emit a<br></div></blockquote><div><br></div><div>Should have gotten what already?</div><div><br></div><div>Might be worth considering an assert on !Subtarget->hasHWDiv() just for giggles.</div><br><blockquote type="cite"><div>+  // libcall.<br>+  RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL;<br>+  if (VT == MVT::i16)<br>+    LC = RTLIB::SDIV_I16;<br>+  else if (VT == MVT::i32)<br>+    LC = RTLIB::SDIV_I32;<br>+  else if (VT == MVT::i64)<br>+    LC = RTLIB::SDIV_I64;<br>+  else if (VT == MVT::i128)<br>+    LC = RTLIB::SDIV_I128;<br>+  assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SDIV!");<br>+  <br>+  // Binary operand with all the same type.<br>+  std::vector<const Type*> ArgTys;<br>+  ArgTys.push_back(Ty);<br>+  ArgTys.push_back(Ty);<br>+  const FunctionType *FTy = FunctionType::get(Ty, ArgTys, false);<br>+  Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,<br>+                                 TLI.getLibcallName(LC));<br>+  if (Subtarget->isAAPCS_ABI())<br>+    F->setCallingConv(CallingConv::ARM_AAPCS);<br>+  else<br>+    F->setCallingConv(I->getParent()->getParent()->getCallingConv());<br>+  <br>+  return ARMEmitLibcall(I, F);<br>+}<br>+<br> // TODO: SoftFP support.<br> bool ARMFastISel::TargetSelectInstruction(const Instruction *I) {<br>   // No Thumb-1 for now.<br>@@ -960,6 +1112,8 @@<br>       return ARMSelectBinaryOp(I, ISD::FSUB);<br>     case Instruction::FMul:<br>       return ARMSelectBinaryOp(I, ISD::FMUL);<br>+    case Instruction::SDiv:<br>+      return ARMSelectSDiv(I);<br>     default: break;<br>   }<br>   return false;<br><br><br>_______________________________________________<br>llvm-commits mailing list<br><a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits<br></div></blockquote></div><br></div></body></html>