[llvm-commits] [llvm] r113886 - /llvm/trunk/lib/Target/ARM/ARMFastISel.cpp

Jim Grosbach grosbach at apple.com
Tue Sep 14 17:49:43 PDT 2010


Very cool. This should be useful for all kinds of stuff. A few minor comments below.

On Sep 14, 2010, at 4:03 PM, Eric Christopher wrote:

> 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);
> 

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.

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).


>     // 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.

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.



> +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);

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.

> +      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

Should have gotten what already?

Might be worth considering an assert on !Subtarget->hasHWDiv() just for giggles.

> +  // 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;
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20100914/2ff6f4d0/attachment.html>


More information about the llvm-commits mailing list