[llvm] r221948 - First stage of call lowering for Mips fast-isel

Reed Kotler rkotler at mips.com
Thu Nov 13 15:37:46 PST 2014


Author: rkotler
Date: Thu Nov 13 17:37:45 2014
New Revision: 221948

URL: http://llvm.org/viewvc/llvm-project?rev=221948&view=rev
Log:
First stage of call lowering for Mips fast-isel

Summary:
This has most of what is needed for mips fast-isel call lowering for O32.
What is missing I will add on the next patch because this patch is already too large.
It should not be doing anything wrong but it will punt on some cases that it is basically
capable of doing.

The mechanism is there for parameters to be passed on the stack but I have not enabled it because it serves as a way for now to prevent some of the strange cases of O32 register passing that I have not fully checked yet and have some issues.

The Mips O32 abi rules are very complicated as far how data is passed in floating and integer registers.

However there is a way to think about this all very simply and this implementation reflects that.

Basically, the ABI rules are written as if everything is passed on the stack and aligned as such.
Once that is conceptually done, it is nearly trivial to reassign those locations to registers and
then all the complexity disappears.

So I have told tablegen that all the data is passed on the stack and during the lowering I fix
this by assigning to registers as per the ABI doc.

This has been my approach and you can line up what I did with the ABI document and see 1 to 1 what
is going on.



Test Plan: callabi.ll

Reviewers: dsanders

Reviewed By: dsanders

Subscribers: jholewinski, echristo, ahatanak, llvm-commits, rfuhler

Differential Revision: http://reviews.llvm.org/D5714

Added:
    llvm/trunk/test/CodeGen/Mips/Fast-ISel/callabi.ll
Modified:
    llvm/trunk/lib/Target/Mips/MipsCallingConv.td
    llvm/trunk/lib/Target/Mips/MipsFastISel.cpp
    llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp

Modified: llvm/trunk/lib/Target/Mips/MipsCallingConv.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsCallingConv.td?rev=221948&r1=221947&r2=221948&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsCallingConv.td (original)
+++ llvm/trunk/lib/Target/Mips/MipsCallingConv.td Thu Nov 13 17:37:45 2014
@@ -51,6 +51,19 @@ def RetCC_F128 : CallingConv<[
 // Mips O32 Calling Convention
 //===----------------------------------------------------------------------===//
 
+def CC_MipsO32 : CallingConv<[
+  // Promote i8/i16 arguments to i32.
+  CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
+
+  // Integer values get stored in stack slots that are 4 bytes in
+  // size and 4-byte aligned.
+  CCIfType<[i32, f32], CCAssignToStack<4, 4>>,
+
+  // Integer values get stored in stack slots that are 8 bytes in
+  // size and 8-byte aligned.
+  CCIfType<[f64], CCAssignToStack<8, 8>>
+]>;
+
 // Only the return rules are defined here for O32. The rules for argument
 // passing are defined in MipsISelLowering.cpp.
 def RetCC_MipsO32 : CallingConv<[

Modified: llvm/trunk/lib/Target/Mips/MipsFastISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsFastISel.cpp?rev=221948&r1=221947&r2=221948&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsFastISel.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsFastISel.cpp Thu Nov 13 17:37:45 2014
@@ -8,6 +8,7 @@
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/Target/TargetInstrInfo.h"
 #include "llvm/Target/TargetLibraryInfo.h"
+#include "MipsCCState.h"
 #include "MipsRegisterInfo.h"
 #include "MipsISelLowering.h"
 #include "MipsMachineFunction.h"
@@ -68,6 +69,8 @@ class MipsFastISel final : public FastIS
   // Convenience variables to avoid some queries.
   LLVMContext *Context;
 
+  bool fastLowerCall(CallLoweringInfo &CLI) override;
+
   bool TargetSupported;
   bool UnsupportedFPMode; // To allow fast-isel to proceed and just not handle
   // floating point but not reject doing fast-isel in other
@@ -87,17 +90,20 @@ private:
   bool selectIntExt(const Instruction *I);
 
   // Utility helper routines.
-
   bool isTypeLegal(Type *Ty, MVT &VT);
   bool isLoadTypeLegal(Type *Ty, MVT &VT);
   bool computeAddress(const Value *Obj, Address &Addr);
+  bool computeCallAddress(const Value *V, Address &Addr);
 
   // Emit helper routines.
   bool emitCmp(unsigned DestReg, const CmpInst *CI);
   bool emitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
                 unsigned Alignment = 0);
+  bool emitStore(MVT VT, unsigned SrcReg, Address Addr,
+                 MachineMemOperand *MMO = nullptr);
   bool emitStore(MVT VT, unsigned SrcReg, Address &Addr,
                  unsigned Alignment = 0);
+  unsigned emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt);
   bool emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg,
 
                   bool IsZExt);
@@ -140,9 +146,15 @@ private:
     return 0;
   }
 
+  // Call handling routines.
+private:
+  CCAssignFn *CCAssignFnForCall(CallingConv::ID CC) const;
+  bool processCallArgs(CallLoweringInfo &CLI, SmallVectorImpl<MVT> &ArgVTs,
+                       unsigned &NumBytes);
+  bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes);
+
 public:
   // Backend specific FastISel code.
-
   explicit MipsFastISel(FunctionLoweringInfo &funcInfo,
                         const TargetLibraryInfo *libInfo)
       : FastISel(funcInfo, libInfo),
@@ -166,6 +178,28 @@ public:
 };
 } // end anonymous namespace.
 
+static bool CC_Mips(unsigned ValNo, MVT ValVT, MVT LocVT,
+                    CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
+                    CCState &State) __attribute__((unused));
+
+static bool CC_MipsO32_FP32(unsigned ValNo, MVT ValVT, MVT LocVT,
+                            CCValAssign::LocInfo LocInfo,
+                            ISD::ArgFlagsTy ArgFlags, CCState &State) {
+  llvm_unreachable("should not be called");
+}
+
+bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, MVT LocVT,
+                     CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
+                     CCState &State) {
+  llvm_unreachable("should not be called");
+}
+
+#include "MipsGenCallingConv.inc"
+
+CCAssignFn *MipsFastISel::CCAssignFnForCall(CallingConv::ID CC) const {
+  return CC_MipsO32;
+}
+
 unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) {
   if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1)
     return 0;
@@ -284,6 +318,19 @@ bool MipsFastISel::computeAddress(const
   return Addr.getReg() != 0;
 }
 
+bool MipsFastISel::computeCallAddress(const Value *V, Address &Addr) {
+  const GlobalValue *GV = dyn_cast<GlobalValue>(V);
+  if (GV && isa<Function>(GV) && dyn_cast<Function>(GV)->isIntrinsic())
+    return false;
+  if (!GV)
+    return false;
+  if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
+    Addr.setGlobalValue(GV);
+    return true;
+  }
+  return false;
+}
+
 bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) {
   EVT evt = TLI.getValueType(Ty, true);
   // Only handle simple types.
@@ -694,6 +741,250 @@ bool MipsFastISel::selectFPToInt(const I
   return true;
 }
 //
+bool MipsFastISel::processCallArgs(CallLoweringInfo &CLI,
+                                   SmallVectorImpl<MVT> &OutVTs,
+                                   unsigned &NumBytes) {
+  CallingConv::ID CC = CLI.CallConv;
+  SmallVector<CCValAssign, 16> ArgLocs;
+  CCState CCInfo(CC, false, *FuncInfo.MF, ArgLocs, *Context);
+  CCInfo.AnalyzeCallOperands(OutVTs, CLI.OutFlags, CCAssignFnForCall(CC));
+  // Get a count of how many bytes are to be pushed on the stack.
+  NumBytes = CCInfo.getNextStackOffset();
+  // This is the minimum argument area used for A0-A3.
+  if (NumBytes < 16)
+    NumBytes = 16;
+
+  emitInst(Mips::ADJCALLSTACKDOWN).addImm(16);
+  // Process the args.
+  MVT firstMVT;
+  for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+    CCValAssign &VA = ArgLocs[i];
+    const Value *ArgVal = CLI.OutVals[VA.getValNo()];
+    MVT ArgVT = OutVTs[VA.getValNo()];
+
+    if (i == 0) {
+      firstMVT = ArgVT;
+      if (ArgVT == MVT::f32) {
+        VA.convertToReg(Mips::F12);
+      } else if (ArgVT == MVT::f64) {
+        VA.convertToReg(Mips::D6);
+      }
+    } else if (i == 1) {
+      if ((firstMVT == MVT::f32) || (firstMVT == MVT::f64)) {
+        if (ArgVT == MVT::f32) {
+          VA.convertToReg(Mips::F14);
+        } else if (ArgVT == MVT::f64) {
+          VA.convertToReg(Mips::D7);
+        }
+      }
+    }
+    if (((ArgVT == MVT::i32) || (ArgVT == MVT::f32)) && VA.isMemLoc()) {
+      switch (VA.getLocMemOffset()) {
+      case 0:
+        VA.convertToReg(Mips::A0);
+        break;
+      case 4:
+        VA.convertToReg(Mips::A1);
+        break;
+      case 8:
+        VA.convertToReg(Mips::A2);
+        break;
+      case 12:
+        VA.convertToReg(Mips::A3);
+        break;
+      default:
+        break;
+      }
+    }
+    unsigned ArgReg = getRegForValue(ArgVal);
+    if (!ArgReg)
+      return false;
+
+    // Handle arg promotion: SExt, ZExt, AExt.
+    switch (VA.getLocInfo()) {
+    case CCValAssign::Full:
+      break;
+    case CCValAssign::AExt:
+    case CCValAssign::SExt: {
+      MVT DestVT = VA.getLocVT();
+      MVT SrcVT = ArgVT;
+      ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/false);
+      if (!ArgReg)
+        return false;
+      break;
+    }
+    case CCValAssign::ZExt: {
+      MVT DestVT = VA.getLocVT();
+      MVT SrcVT = ArgVT;
+      ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/true);
+      if (!ArgReg)
+        return false;
+      break;
+    }
+    default:
+      llvm_unreachable("Unknown arg promotion!");
+    }
+
+    // Now copy/store arg to correct locations.
+    if (VA.isRegLoc() && !VA.needsCustom()) {
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+              TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(ArgReg);
+      CLI.OutRegs.push_back(VA.getLocReg());
+    } else if (VA.needsCustom()) {
+      llvm_unreachable("Mips does not use custom args.");
+      return false;
+    } else {
+      //
+      // FIXME: This path will currently return false. It was copied
+      // from the AArch64 port and should be essentially fine for Mips too.
+      // The work to finish up this path will be done in a follow-on patch.
+      //
+      assert(VA.isMemLoc() && "Assuming store on stack.");
+      // Don't emit stores for undef values.
+      if (isa<UndefValue>(ArgVal))
+        continue;
+
+      // Need to store on the stack.
+      // FIXME: This alignment is incorrect but this path is disabled
+      // for now (will return false). We need to determine the right alignment
+      // based on the normal alignment for the underlying machine type.
+      //
+      unsigned ArgSize = RoundUpToAlignment(ArgVT.getSizeInBits(), 4);
+
+      unsigned BEAlign = 0;
+      if (ArgSize < 8 && !Subtarget->isLittle())
+        BEAlign = 8 - ArgSize;
+
+      Address Addr;
+      Addr.setKind(Address::RegBase);
+      Addr.setReg(Mips::SP);
+      Addr.setOffset(VA.getLocMemOffset() + BEAlign);
+
+      unsigned Alignment = DL.getABITypeAlignment(ArgVal->getType());
+      MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand(
+          MachinePointerInfo::getStack(Addr.getOffset()),
+          MachineMemOperand::MOStore, ArgVT.getStoreSize(), Alignment);
+      (void)(MMO);
+      // if (!emitStore(ArgVT, ArgReg, Addr, MMO))
+      return false; // can't store on the stack yet.
+    }
+  }
+
+  return true;
+}
+
+bool MipsFastISel::finishCall(CallLoweringInfo &CLI, MVT RetVT,
+                              unsigned NumBytes) {
+  CallingConv::ID CC = CLI.CallConv;
+  emitInst(Mips::ADJCALLSTACKUP).addImm(16);
+  if (RetVT != MVT::isVoid) {
+    SmallVector<CCValAssign, 16> RVLocs;
+    CCState CCInfo(CC, false, *FuncInfo.MF, RVLocs, *Context);
+    CCInfo.AnalyzeCallResult(RetVT, RetCC_Mips);
+
+    // Only handle a single return value.
+    if (RVLocs.size() != 1)
+      return false;
+    // Copy all of the result registers out of their specified physreg.
+    MVT CopyVT = RVLocs[0].getValVT();
+    // Special handling for extended integers.
+    if (RetVT == MVT::i1 || RetVT == MVT::i8 || RetVT == MVT::i16)
+      CopyVT = MVT::i32;
+
+    unsigned ResultReg = createResultReg(TLI.getRegClassFor(CopyVT));
+    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+            TII.get(TargetOpcode::COPY),
+            ResultReg).addReg(RVLocs[0].getLocReg());
+    CLI.InRegs.push_back(RVLocs[0].getLocReg());
+
+    CLI.ResultReg = ResultReg;
+    CLI.NumResultRegs = 1;
+  }
+  return true;
+}
+
+bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) {
+  CallingConv::ID CC = CLI.CallConv;
+  bool IsTailCall = CLI.IsTailCall;
+  bool IsVarArg = CLI.IsVarArg;
+  const Value *Callee = CLI.Callee;
+  // const char *SymName = CLI.SymName;
+
+  // Allow SelectionDAG isel to handle tail calls.
+  if (IsTailCall)
+    return false;
+
+  // Let SDISel handle vararg functions.
+  if (IsVarArg)
+    return false;
+
+  // FIXME: Only handle *simple* calls for now.
+  MVT RetVT;
+  if (CLI.RetTy->isVoidTy())
+    RetVT = MVT::isVoid;
+  else if (!isTypeLegal(CLI.RetTy, RetVT))
+    return false;
+
+  for (auto Flag : CLI.OutFlags)
+    if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal())
+      return false;
+
+  // Set up the argument vectors.
+  SmallVector<MVT, 16> OutVTs;
+  OutVTs.reserve(CLI.OutVals.size());
+
+  for (auto *Val : CLI.OutVals) {
+    MVT VT;
+    if (!isTypeLegal(Val->getType(), VT) &&
+        !(VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16))
+      return false;
+
+    // We don't handle vector parameters yet.
+    if (VT.isVector() || VT.getSizeInBits() > 64)
+      return false;
+
+    OutVTs.push_back(VT);
+  }
+
+  Address Addr;
+  if (!computeCallAddress(Callee, Addr))
+    return false;
+
+  // Handle the arguments now that we've gotten them.
+  unsigned NumBytes;
+  if (!processCallArgs(CLI, OutVTs, NumBytes))
+    return false;
+
+  // Issue the call.
+  unsigned DestAddress = materializeGV(Addr.getGlobalValue(), MVT::i32);
+  emitInst(TargetOpcode::COPY, Mips::T9).addReg(DestAddress);
+  MachineInstrBuilder MIB =
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::JALR),
+              Mips::RA).addReg(Mips::T9);
+
+  // Add implicit physical register uses to the call.
+  for (auto Reg : CLI.OutRegs)
+    MIB.addReg(Reg, RegState::Implicit);
+
+  // Add a register mask with the call-preserved registers.
+  // Proper defs for return values will be added by setPhysRegsDeadExcept().
+  MIB.addRegMask(TRI.getCallPreservedMask(CC));
+
+  CLI.Call = MIB;
+
+  // Add implicit physical register uses to the call.
+  for (auto Reg : CLI.OutRegs)
+    MIB.addReg(Reg, RegState::Implicit);
+
+  // Add a register mask with the call-preserved registers.  Proper
+  // defs for return values will be added by setPhysRegsDeadExcept().
+  MIB.addRegMask(TRI.getCallPreservedMask(CC));
+
+  CLI.Call = MIB;
+  // Finish off the call including any return values.
+  return finishCall(CLI, RetVT, NumBytes);
+}
+
 bool MipsFastISel::selectRet(const Instruction *I) {
   const ReturnInst *Ret = cast<ReturnInst>(I);
 
@@ -812,6 +1103,7 @@ bool MipsFastISel::emitIntZExt(MVT SrcVT
     break;
   case MVT::i16:
     emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xffff);
+    break;
   }
   return true;
 }
@@ -822,6 +1114,13 @@ bool MipsFastISel::emitIntExt(MVT SrcVT,
     return emitIntZExt(SrcVT, SrcReg, DestVT, DestReg);
   return emitIntSExt(SrcVT, SrcReg, DestVT, DestReg);
 }
+
+unsigned MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
+                                  bool isZExt) {
+  unsigned DestReg = createResultReg(&Mips::GPR32RegClass);
+  return emitIntExt(SrcVT, SrcReg, DestVT, DestReg, isZExt);
+}
+
 bool MipsFastISel::fastSelectInstruction(const Instruction *I) {
   if (!TargetSupported)
     return false;

Modified: llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp?rev=221948&r1=221947&r2=221948&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp Thu Nov 13 17:37:45 2014
@@ -2356,6 +2356,11 @@ static bool CC_MipsO32_FP64(unsigned Val
   return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs);
 }
 
+static bool CC_MipsO32(unsigned ValNo, MVT ValVT,
+                   MVT LocVT, CCValAssign::LocInfo LocInfo,
+                   ISD::ArgFlagsTy ArgFlags, CCState &State)
+__attribute__((unused));
+
 #include "MipsGenCallingConv.inc"
 
 //===----------------------------------------------------------------------===//

Added: llvm/trunk/test/CodeGen/Mips/Fast-ISel/callabi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/Fast-ISel/callabi.ll?rev=221948&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/Fast-ISel/callabi.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/Fast-ISel/callabi.ll Thu Nov 13 17:37:45 2014
@@ -0,0 +1,477 @@
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \
+; RUN:     < %s | FileCheck %s
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \
+; RUN:     < %s | FileCheck %s
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \
+; RUN:     < %s | FileCheck %s -check-prefix=mips32r2
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \
+; RUN:     < %s | FileCheck %s -check-prefix=mips32
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \
+; RUN:     < %s | FileCheck %s -check-prefix=CHECK2
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \
+; RUN:     < %s | FileCheck %s -check-prefix=CHECK2
+
+
+ at c1 = global i8 -45, align 1
+ at uc1 = global i8 27, align 1
+ at s1 = global i16 -1789, align 2
+ at us1 = global i16 1256, align 2
+
+; Function Attrs: nounwind
+define void @cxi() #0 {
+entry:
+; CHECK-LABEL:  cxi
+  call void @xi(i32 10)
+; CHECK-DAG:    addiu   $4, $zero, 10
+; CHECK-DAG:    lw      $25, %got(xi)(${{[0-9]+}})
+; CHECK:        jalr    $25
+
+  ret void
+}
+
+declare void @xi(i32) #1
+
+; Function Attrs: nounwind
+define void @cxii() #0 {
+entry:
+; CHECK-LABEL:  cxii
+  call void @xii(i32 746, i32 892)
+; CHECK-DAG:    addiu   $4, $zero, 746
+; CHECK-DAG:    addiu   $5, $zero, 892
+; CHECK-DAG:    lw      $25, %got(xii)(${{[0-9]+}})
+; CHECK:        jalr    $25
+
+  ret void
+}
+
+declare void @xii(i32, i32) #1
+
+; Function Attrs: nounwind
+define void @cxiii() #0 {
+entry:
+; CHECK-LABEL:  cxiii
+  call void @xiii(i32 88, i32 44, i32 11)
+; CHECK-DAG:    addiu   $4, $zero, 88
+; CHECK-DAG:    addiu   $5, $zero, 44
+; CHECK-DAG:    addiu   $6, $zero, 11
+; CHECK-DAG:    lw      $25, %got(xiii)(${{[0-9]+}})
+; CHECK:        jalr    $25
+  ret void
+}
+
+declare void @xiii(i32, i32, i32) #1
+
+; Function Attrs: nounwind
+define void @cxiiii() #0 {
+entry:
+; CHECK-LABEL:  cxiiii
+  call void @xiiii(i32 167, i32 320, i32 97, i32 14)
+; CHECK-DAG:    addiu   $4, $zero, 167
+; CHECK-DAG:    addiu   $5, $zero, 320
+; CHECK-DAG:    addiu   $6, $zero, 97
+; CHECK-DAG:    addiu   $7, $zero, 14
+; CHECK-DAG:    lw      $25, %got(xiiii)(${{[0-9]+}})
+; CHECK:        jalr    $25
+
+  ret void
+}
+
+declare void @xiiii(i32, i32, i32, i32) #1
+
+; Function Attrs: nounwind
+define void @cxiiiiconv() #0 {
+entry:
+; CHECK-LABEL: cxiiiiconv
+; mips32r2-LABEL:  cxiiiiconv
+; mips32-LABEL:  cxiiiiconv
+  %0 = load i8* @c1, align 1
+  %conv = sext i8 %0 to i32
+  %1 = load i8* @uc1, align 1
+  %conv1 = zext i8 %1 to i32
+  %2 = load i16* @s1, align 2
+  %conv2 = sext i16 %2 to i32
+  %3 = load i16* @us1, align 2
+  %conv3 = zext i16 %3 to i32
+  call void @xiiii(i32 %conv, i32 %conv1, i32 %conv2, i32 %conv3)
+; CHECK:        addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; mips32r2:     addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; mips32:       addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; mips32r2-DAG:         lw      $[[REG_C1_ADDR:[0-9]+]], %got(c1)($[[REG_GP]])
+; mips32r2-DAG: lbu     $[[REG_C1:[0-9]+]], 0($[[REG_C1_ADDR]])
+; mips32r2-DAG  seb     $3, $[[REG_C1]]
+; mips32-DAG:   lw      $[[REG_C1_ADDR:[0-9]+]], %got(c1)($[[REG_GP]])
+; mips32-DAG:   lbu     $[[REG_C1:[0-9]+]], 0($[[REG_C1_ADDR]])
+; mips32-DAG:   sll     $[[REG_C1_1:[0-9]+]], $[[REG_C1]], 24
+; mips32-DAG:   sra     $4, $[[REG_C1_1]], 24
+; CHECK-DAG:    lw      $[[REG_UC1_ADDR:[0-9]+]], %got(uc1)($[[REG_GP]])
+; CHECK-DAG:    lbu     $[[REG_UC1:[0-9]+]], 0($[[REG_UC1_ADDR]])
+; FIXME andi is superfulous
+; CHECK-DAG:    andi    $5, $[[REG_UC1]], 255
+; mips32r2-DAG:         lw      $[[REG_S1_ADDR:[0-9]+]], %got(s1)($[[REG_GP]])
+; mips32r2-DAG: lhu     $[[REG_S1:[0-9]+]], 0($[[REG_S1_ADDR]])
+; mips32r2-DAG: seh     $6, $[[REG_S1]]
+; mips32-DAG:   lw      $[[REG_S1_ADDR:[0-9]+]], %got(s1)($[[REG_GP]])
+; mips32-DAG:   lhu     $[[REG_S1:[0-9]+]], 0($[[REG_S1_ADDR]])
+; mips32-DAG:   sll     $[[REG_S1_1:[0-9]+]], $[[REG_S1]], 16
+; mips32-DAG:   sra     $6, $[[REG_S1_1]], 16
+; CHECK-DAG:    lw      $[[REG_US1_ADDR:[0-9]+]], %got(us1)($[[REG_GP]])
+; CHECK-DAG:    lhu     $[[REG_US1:[0-9]+]], 0($[[REG_US1_ADDR]])
+; FIXME andi is superfulous
+; CHECK-DAG:    andi    $7, $[[REG_US1]], 65535
+; mips32r2:     jalr    $25
+; mips32r2:     jalr    $25
+; CHECK:        jalr    $25
+  ret void
+}
+
+; Function Attrs: nounwind
+define void @cxf() #0 {
+entry:
+; CHECK-LABEL:  cxf
+  call void @xf(float 0x40BBC85560000000)
+; CHECK:        addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK:        lui     $[[REG_FPCONST_1:[0-9]+]], 17886
+; CHECK:        ori     $[[REG_FPCONST:[0-9]+]], $[[REG_FPCONST_1]], 17067
+; CHECK: mtc1   $[[REG_FPCONST]], $f12
+; CHECK:        lw      $25, %got(xf)($[[REG_GP]])
+; CHECK:        jalr    $25
+  ret void
+}
+
+declare void @xf(float) #1
+
+; Function Attrs: nounwind
+define void @cxff() #0 {
+entry:
+; CHECK-LABEL:  cxff
+  call void @xff(float 0x3FF74A6CA0000000, float 0x401A2C0840000000)
+; CHECK:        addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    lui     $[[REG_FPCONST_1:[0-9]+]], 16314
+; CHECK-DAG:    ori     $[[REG_FPCONST:[0-9]+]], $[[REG_FPCONST_1]], 21349
+; CHECK-DAG: mtc1       $[[REG_FPCONST]], $f12
+; CHECK-DAG:    lui     $[[REG_FPCONST_2:[0-9]+]], 16593
+; CHECK-DAG:    ori     $[[REG_FPCONST_3:[0-9]+]], $[[REG_FPCONST_2]], 24642
+; CHECK-DAG: mtc1       $[[REG_FPCONST_3]], $f14
+; CHECK:        lw      $25, %got(xff)($[[REG_GP]])
+; CHECK:        jalr    $25
+  ret void
+}
+
+declare void @xff(float, float) #1
+
+; Function Attrs: nounwind
+define void @cxfi() #0 {
+entry:
+; CHECK-LABEL: cxfi
+  call void @xfi(float 0x4013906240000000, i32 102)
+; CHECK:        addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    lui     $[[REG_FPCONST_1:[0-9]+]], 16540
+; CHECK-DAG:    ori     $[[REG_FPCONST:[0-9]+]], $[[REG_FPCONST_1]], 33554
+; CHECK-DAG: mtc1       $[[REG_FPCONST]], $f12
+; CHECK-DAG:    addiu   $5, $zero, 102
+; CHECK:        lw      $25, %got(xfi)($[[REG_GP]])
+; CHECK:        jalr    $25
+
+  ret void
+}
+
+declare void @xfi(float, i32) #1
+
+; Function Attrs: nounwind
+define void @cxfii() #0 {
+entry:
+; CHECK-LABEL: cxfii
+  call void @xfii(float 0x405EC7EE00000000, i32 9993, i32 10922)
+; CHECK:        addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    lui     $[[REG_FPCONST_1:[0-9]+]], 17142
+; CHECK-DAG:    ori     $[[REG_FPCONST:[0-9]+]], $[[REG_FPCONST_1]], 16240
+; CHECK-DAG: mtc1       $[[REG_FPCONST]], $f12
+; CHECK-DAG:    addiu   $5, $zero, 9993
+; CHECK-DAG:    addiu   $6, $zero, 10922
+; CHECK:        lw      $25, %got(xfii)($[[REG_GP]])
+; CHECK:        jalr    $25
+  ret void
+}
+
+declare void @xfii(float, i32, i32) #1
+
+; Function Attrs: nounwind
+define void @cxfiii() #0 {
+entry:
+; CHECK-LABEL: cxfiii
+  call void @xfiii(float 0x405C072B20000000, i32 3948, i32 89011, i32 111222)
+; CHECK:        addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    lui     $[[REG_FPCONST_1:[0-9]+]], 17120
+; CHECK-DAG:    ori     $[[REG_FPCONST:[0-9]+]], $[[REG_FPCONST_1]], 14681
+; CHECK-DAG: mtc1       $[[REG_FPCONST]], $f12
+; CHECK-DAG:    addiu   $5, $zero, 3948
+; CHECK-DAG:    lui     $[[REG_I_1:[0-9]+]], 1
+; CHECK-DAG:    ori     $6, $[[REG_I_1]], 23475
+; CHECK-DAG:    lui     $[[REG_I_2:[0-9]+]], 1
+; CHECK-DAG:    ori     $7, $[[REG_I_2]], 45686
+; CHECK:        lw      $25, %got(xfiii)($[[REG_GP]])
+; CHECK:        jalr    $25
+  ret void
+}
+
+declare void @xfiii(float, i32, i32, i32) #1
+
+; Function Attrs: nounwind
+define void @cxd() #0 {
+entry:
+; mips32r2-LABEL: cxd:
+; mips32-LABEL: cxd:
+  call void @xd(double 5.994560e+02)
+; mips32:       addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; mips32-DAG:   lui     $[[REG_FPCONST_1:[0-9]+]], 16514
+; mips32-DAG:   ori     $[[REG_FPCONST_2:[0-9]+]], $[[REG_FPCONST_1]], 48037
+; mips32-DAG:   lui     $[[REG_FPCONST_3:[0-9]+]], 58195
+; mips32-DAG:   ori     $[[REG_FPCONST_4:[0-9]+]], $[[REG_FPCONST_3]], 63439
+; mips32-DAG:    mtc1   $[[REG_FPCONST_4]], $f12
+; mips32-DAG:       mtc1        $[[REG_FPCONST_2]], $f13
+; mips32-DAG:   lw      $25, %got(xd)($[[REG_GP]])
+; mips32:       jalr    $25
+; mips32r2:     addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; mips32r2-DAG: lui     $[[REG_FPCONST_1:[0-9]+]], 16514
+; mips32r2-DAG: ori     $[[REG_FPCONST_2:[0-9]+]], $[[REG_FPCONST_1]], 48037
+; mips32r2-DAG: lui     $[[REG_FPCONST_3:[0-9]+]], 58195
+; mips32r2-DAG: ori     $[[REG_FPCONST_4:[0-9]+]], $[[REG_FPCONST_3]], 63439
+; mips32r2-DAG: mtc1    $[[REG_FPCONST_4]], $f12
+; mips32r2-DAG: mthc1   $[[REG_FPCONST_2]], $f12
+; mips32r2-DAG: lw      $25, %got(xd)($[[REG_GP]])
+; mips32r2 :    jalr    $25
+  ret void
+}
+
+declare void @xd(double) #1
+
+; Function Attrs: nounwind
+define void @cxdd() #0 {
+; mips32r2-LABEL: cxdd:
+; mips32-LABEL: cxdd:
+entry:
+  call void @xdd(double 1.234980e+03, double 0x40F5B331F7CED917)
+; mips32:       addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; mips32-DAG:   lui     $[[REG_FPCONST_1:[0-9]+]], 16531
+; mips32-DAG:   ori     $[[REG_FPCONST_2:[0-9]+]], $[[REG_FPCONST_1]], 19435
+; mips32-DAG:   lui     $[[REG_FPCONST_3:[0-9]+]], 34078
+; mips32-DAG:   ori     $[[REG_FPCONST_4:[0-9]+]], $[[REG_FPCONST_3]], 47186
+; mips32-DAG:   mtc1    $[[REG_FPCONST_4]], $f12
+; mips32-DAG:   mtc1    $[[REG_FPCONST_2]], $f13
+; mips32-DAG:   lui     $[[REG_FPCONST_1:[0-9]+]], 16629
+; mips32-DAG:   ori     $[[REG_FPCONST_2:[0-9]+]], $[[REG_FPCONST_1]], 45873
+; mips32-DAG:   lui     $[[REG_FPCONST_3:[0-9]+]], 63438
+; mips32-DAG:   ori     $[[REG_FPCONST_4:[0-9]+]], $[[REG_FPCONST_3]], 55575
+; mips32-DAG:   mtc1    $[[REG_FPCONST_4]], $f14
+; mips32-DAG:   mtc1    $[[REG_FPCONST_2]], $f15
+; mips32-DAG:   lw      $25, %got(xdd)($[[REG_GP]])
+; mips32:       jalr    $25
+; mips32r2:     addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; mips32r2-DAG: lui     $[[REG_FPCONST_1:[0-9]+]], 16531
+; mips32r2-DAG: ori     $[[REG_FPCONST_2:[0-9]+]], $[[REG_FPCONST_1]], 19435
+; mips32r2-DAG: lui     $[[REG_FPCONST_3:[0-9]+]], 34078
+; mips32r2-DAG: ori     $[[REG_FPCONST_4:[0-9]+]], $[[REG_FPCONST_3]], 47186
+; mips32r2-DAG: mtc1    $[[REG_FPCONST_4]], $f12
+; mips32r2-DAG: mthc1   $[[REG_FPCONST_2]], $f12
+; mips32r2-DAG: lui     $[[REG_FPCONST_1:[0-9]+]], 16629
+; mips32r2-DAG: ori     $[[REG_FPCONST_2:[0-9]+]], $[[REG_FPCONST_1]], 45873
+; mips32r2-DAG: lui     $[[REG_FPCONST_3:[0-9]+]], 63438
+; mips32r2-DAG: ori     $[[REG_FPCONST_4:[0-9]+]], $[[REG_FPCONST_3]], 55575
+; mips32r2-DAG: mtc1    $[[REG_FPCONST_4]], $f14
+; mips32r2-DAG: mthc1   $[[REG_FPCONST_2]], $f14
+; mips32r2-DAG: lw      $25, %got(xdd)($[[REG_GP]])
+; mips32r2 :    jalr    $25
+  ret void
+}
+
+declare void @xdd(double, double) #1
+
+; Function Attrs: nounwind
+define void @cxif() #0 {
+entry:
+; CHECK-LABEL: cxif:
+  call void @xif(i32 345, float 0x407BCE5A20000000)
+; CHECK-DAG:    addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    addiu   $4, $zero, 345
+; CHECK-DAG:    lui     $[[REGF_1:[0-9]+]], 17374
+; CHECK-DAG:    ori     $[[REGF_2:[0-9]+]], $[[REGF_1]], 29393
+; CHECK-DAG:    mtc1    $[[REGF_2]], $f[[REGF_3:[0-9]+]]
+; CHECK-DAG:    mfc1    $5, $f[[REGF_3]]
+; CHECK-DAG:    lw      $25, %got(xif)($[[REG_GP]])
+; CHECK:        jalr    $25
+
+  ret void
+}
+
+declare void @xif(i32, float) #1
+
+; Function Attrs: nounwind
+define void @cxiff() #0 {
+entry:
+; CHECK-LABEL: cxiff:
+; CHECK2-LABEL: cxiff:
+  call void @xiff(i32 12239, float 0x408EDB3340000000, float 0x4013FFE5C0000000)
+; We need to do the two floating point parameters in a separate
+; check because we can't control the ordering of parts of the sequence
+;;
+; CHECK:        addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK:        addiu   $4, $zero, 12239
+; CHECK2:       addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK2:       addiu   $4, $zero, 12239
+; CHECK:        lui     $[[REGF_1:[0-9]+]], 17526
+; CHECK:        ori     $[[REGF_2:[0-9]+]], $[[REGF_1]], 55706
+; CHECK:        mtc1    $[[REGF_2]], $f[[REGF_3:[0-9]+]]
+; CHECK:        mfc1    $5, $f[[REGF_3]]
+; CHECK2:       lui     $[[REGF2_1:[0-9]+]], 16543
+; CHECK2:       ori     $[[REGF2_2:[0-9]+]], $[[REGF2_1]], 65326
+; CHECK2:       mtc1    $[[REGF2_2]], $f[[REGF2_3:[0-9]+]]
+; CHECK2:       mfc1    $6, $f[[REGF2_3]]
+; CHECK:        lw      $25, %got(xiff)($[[REG_GP]])
+; CHECK2:       lw      $25, %got(xiff)($[[REG_GP]])
+; CHECK:        jalr    $25
+; CHECK2:       jalr    $25
+  ret void
+}
+
+declare void @xiff(i32, float, float) #1
+
+; Function Attrs: nounwind
+define void @cxifi() #0 {
+entry:
+; CHECK: cxifi:
+  call void @xifi(i32 887, float 0x402277CEE0000000, i32 888)
+; CHECK-DAG:    addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    addiu   $4, $zero, 887
+; CHECK-DAG:    lui     $[[REGF_1:[0-9]+]], 16659
+; CHECK-DAG:    ori     $[[REGF_2:[0-9]+]], $[[REGF_1]], 48759
+; CHECK-DAG:    mtc1    $[[REGF_2]], $f[[REGF_3:[0-9]+]]
+; CHECK-DAG:    mfc1    $5, $f[[REGF_3]]
+; CHECk-DAG:    addiu   $6, $zero, 888
+; CHECK-DAG:    lw      $25, %got(xifi)($[[REG_GP]])
+; CHECK:        jalr    $25
+
+  ret void
+}
+
+declare void @xifi(i32, float, i32) #1
+
+; Function Attrs: nounwind
+define void @cxifif() #0 {
+entry:
+; CHECK: cxifif:
+; CHECK2: cxifif:
+  call void @xifif(i32 67774, float 0x408EE0FBE0000000, i32 9991, float 0x40B15C8CC0000000)
+; CHECK-DAG:    addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    lui     $[[REGI:[0-9]+]], 1
+; CHECK-DAG:    ori     $4, $[[REGI]], 2238
+; CHECK-DAG:    lui     $[[REGF_1:[0-9]+]], 17527
+; CHECK-DAG:    ori     $[[REGF_2:[0-9]+]], $[[REGF_1]], 2015
+; CHECK-DAG:    mtc1    $[[REGF_2]], $f[[REGF_3:[0-9]+]]
+; CHECK-DAG:    mfc1    $5, $f[[REGF_3]]
+; CHECk-DAG:    addiu   $6, $zero, 888
+; CHECK2:       lui     $[[REGF2_1:[0-9]+]], 17802
+; CHECK2:       ori     $[[REGF2_2:[0-9]+]], $[[REGF2_1]], 58470
+; CHECK2:       mtc1    $[[REGF2_2]], $f[[REGF2_3:[0-9]+]]
+; CHECK2:       mfc1    $7, $f[[REGF2_3]]
+; CHECK:        lw      $25, %got(xifif)($[[REG_GP]])
+; CHECK2:       lw      $25, %got(xifif)($[[REG_GP]])
+; CHECK2:       jalr    $25
+; CHECK:        jalr    $25
+
+  ret void
+}
+
+declare void @xifif(i32, float, i32, float) #1
+
+; Function Attrs: nounwind
+define void @cxiffi() #0 {
+entry:
+; CHECK-label: cxiffi:
+; CHECK2-label: cxiffi:
+  call void @xiffi(i32 45, float 0x3FF6666660000000, float 0x408F333340000000, i32 234)
+; CHECK-DAG:    addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    addiu   $4, $zero, 45
+; CHECK2-DAG:   addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK2-DAG:   addiu   $4, $zero, 45
+; CHECK-DAG:    lui     $[[REGF_1:[0-9]+]], 16307
+; CHECK-DAG:    ori     $[[REGF_2:[0-9]+]], $[[REGF_1]], 13107
+; CHECK-DAG:    mtc1    $[[REGF_2]], $f[[REGF_3:[0-9]+]]
+; CHECK-DAG:    mfc1    $5, $f[[REGF_3]]
+; CHECK2:       lui     $[[REGF2_1:[0-9]+]], 17529
+; CHECK2:       ori     $[[REGF2_2:[0-9]+]], $[[REGF2_1]], 39322
+; CHECK2:       mtc1    $[[REGF2_2]], $f[[REGF2_3:[0-9]+]]
+; CHECK2:       mfc1    $6, $f[[REGF2_3]]
+; CHECK-DAG:    lw      $25, %got(xiffi)($[[REG_GP]])
+; CHECK-DAG:    addiu   $7, $zero, 234
+; CHECK2-DAG:   lw      $25, %got(xiffi)($[[REG_GP]])
+; CHECK:        jalr    $25
+; CHECK2:       jalr    $25
+
+  ret void
+}
+
+declare void @xiffi(i32, float, float, i32) #1
+
+; Function Attrs: nounwind
+define void @cxifii() #0 {
+entry:
+; CHECK-DAG:    cxifii:
+  call void @xifii(i32 12239, float 0x408EDB3340000000, i32 998877, i32 1234)
+; CHECK-DAG:    addu    $[[REG_GP:[0-9]+]], ${{[0-9]+}}, ${{[0-9+]}}
+; CHECK-DAG:    addiu   $4, $zero, 12239
+; CHECK-DAG:    lui     $[[REGF_1:[0-9]+]], 17526
+; CHECK-DAG:    ori     $[[REGF_2:[0-9]+]], $[[REGF_1]], 55706
+; CHECK-DAG:    mtc1    $[[REGF_2]], $f[[REGF_3:[0-9]+]]
+; CHECK-DAG:    mfc1    $5, $f[[REGF_3]]
+; CHECK-DAG:    lui     $[[REGI2:[0-9]+]], 15
+; CHECK-DAG:    ori     $6, $[[REGI2]], 15837
+; CHECk-DAG:    addiu   $7, $zero, 1234
+; CHECK-DAG:    lw      $25, %got(xifii)($[[REG_GP]])
+; CHECK:        jalr    $25
+  ret void
+}
+
+declare void @xifii(i32, float, i32, i32) #1
+
+; FIXME: this function will not pass yet. 
+; Function Attrs: nounwind
+; define void @cxfid() #0 {
+;entry:
+;  call void @xfid(float 0x4013B851E0000000, i32 811123, double 0x40934BFF487FCB92)
+;  ret void
+;}
+
+declare void @xfid(float, i32, double) #1
+
+; Function Attrs: nounwind
+define void @g() #0 {
+entry:
+  call void @cxi()
+  call void @cxii()
+  call void @cxiii()
+  call void @cxiiii()
+  call void @cxiiiiconv()
+  call void @cxf()
+  call void @cxff()
+  call void @cxd()
+  call void @cxfi()
+  call void @cxfii()
+  call void @cxfiii()
+  call void @cxdd()
+  call void @cxif()
+  call void @cxiff()
+  call void @cxifi()
+  call void @cxifii()
+  call void @cxifif()
+  call void @cxiffi()
+  ret void
+}
+
+
+attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = metadata !{metadata !"clang version 3.6.0 (gitosis at dmz-portal.mips.com:clang 43992fe7b17de5553ac06d323cb80cc6723a9ae3) (gitosis at dmz-portal.mips.com:llvm.git 0834e6839eb170197c81bb02e916258d1527e312)"}





More information about the llvm-commits mailing list