[MIPS GlobalISel] Add lowerCall
authorPetar Jovanovic <petar.jovanovic@mips.com>
Wed, 6 Jun 2018 07:24:52 +0000 (07:24 +0000)
committerPetar Jovanovic <petar.jovanovic@mips.com>
Wed, 6 Jun 2018 07:24:52 +0000 (07:24 +0000)
Add minimal support to lower function calls.
Support only functions with arguments/return that go through registers
and have type i32.

Patch by Petar Avramovic.

Differential Revision: https://reviews.llvm.org/D45627

llvm-svn: 334071

llvm/lib/Target/Mips/MipsCallLowering.cpp
llvm/lib/Target/Mips/MipsCallLowering.h
llvm/test/CodeGen/Mips/GlobalISel/irtranslator/call.ll [new file with mode: 0644]
llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/call.ll [new file with mode: 0644]

index 561b15b..cd751e5 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "MipsCallLowering.h"
 #include "MipsCCState.h"
+#include "MipsTargetMachine.h"
 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
 
 using namespace llvm;
@@ -44,10 +45,25 @@ public:
 private:
   virtual void assignValueToReg(unsigned ValVReg, unsigned PhysReg) override;
 
-  void markPhysRegUsed(unsigned PhysReg) {
+  virtual void markPhysRegUsed(unsigned PhysReg) {
     MIRBuilder.getMBB().addLiveIn(PhysReg);
   }
 };
+
+class CallReturnHandler : public IncomingValueHandler {
+public:
+  CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+                    MachineInstrBuilder &MIB)
+      : IncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
+
+private:
+  virtual void markPhysRegUsed(unsigned PhysReg) override {
+    MIB.addDef(PhysReg, RegState::Implicit);
+  }
+
+  MachineInstrBuilder &MIB;
+};
+
 } // end anonymous namespace
 
 void IncomingValueHandler::assignValueToReg(unsigned ValVReg,
@@ -198,6 +214,118 @@ bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
   return true;
 }
 
+bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
+                                 CallingConv::ID CallConv,
+                                 const MachineOperand &Callee,
+                                 const ArgInfo &OrigRet,
+                                 ArrayRef<ArgInfo> OrigArgs) const {
+
+  if (CallConv != CallingConv::C)
+    return false;
+
+  for (auto &Arg : OrigArgs) {
+    if (!isSupportedType(Arg.Ty))
+      return false;
+    if (Arg.Flags.isByVal() || Arg.Flags.isSRet())
+      return false;
+  }
+  if (OrigRet.Reg && !isSupportedType(OrigRet.Ty))
+    return false;
+
+  MachineFunction &MF = MIRBuilder.getMF();
+  const Function &F = MF.getFunction();
+  const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
+  const MipsTargetMachine &TM =
+      static_cast<const MipsTargetMachine &>(MF.getTarget());
+  const MipsABIInfo &ABI = TM.getABI();
+
+  MachineInstrBuilder CallSeqStart =
+      MIRBuilder.buildInstr(Mips::ADJCALLSTACKDOWN);
+
+  // FIXME: Add support for pic calling sequences, long call sequences for O32,
+  //       N32 and N64. First handle the case when Callee.isReg().
+  if (Callee.isReg())
+    return false;
+
+  MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(Mips::JAL);
+  MIB.addDef(Mips::SP, RegState::Implicit);
+  MIB.add(Callee);
+  const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+  MIB.addRegMask(TRI->getCallPreservedMask(MF, F.getCallingConv()));
+
+  TargetLowering::ArgListTy FuncOrigArgs;
+  FuncOrigArgs.reserve(OrigArgs.size());
+
+  SmallVector<ArgInfo, 8> ArgInfos;
+  SmallVector<unsigned, 8> OrigArgIndices;
+  unsigned i = 0;
+  for (auto &Arg : OrigArgs) {
+
+    TargetLowering::ArgListEntry Entry;
+    Entry.Ty = Arg.Ty;
+    FuncOrigArgs.push_back(Entry);
+
+    splitToValueTypes(Arg, i, ArgInfos, OrigArgIndices);
+    ++i;
+  }
+
+  SmallVector<ISD::OutputArg, 8> Outs;
+  subTargetRegTypeForCallingConv(
+      MIRBuilder, ArgInfos, OrigArgIndices,
+      [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx,
+          unsigned partOffs) {
+        Outs.emplace_back(flags, vt, argvt, used, origIdx, partOffs);
+      });
+
+  SmallVector<CCValAssign, 8> ArgLocs;
+  MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
+                     F.getContext());
+
+  const char *Call = Callee.isSymbol() ? Callee.getSymbolName() : nullptr;
+  CCInfo.AnalyzeCallOperands(Outs, TLI.CCAssignFnForCall(), FuncOrigArgs, Call);
+
+  OutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), MIB);
+  if (!RetHandler.handle(ArgLocs, ArgInfos)) {
+    return false;
+  }
+
+  // TODO: Calculate stack offset.
+  CallSeqStart.addImm(ABI.GetCalleeAllocdArgSizeInBytes(CallConv)).addImm(0);
+  MIRBuilder.insertInstr(MIB);
+
+  if (OrigRet.Reg) {
+
+    ArgInfos.clear();
+    SmallVector<unsigned, 8> OrigRetIndices;
+
+    splitToValueTypes(OrigRet, 0, ArgInfos, OrigRetIndices);
+
+    SmallVector<ISD::InputArg, 8> Ins;
+    subTargetRegTypeForCallingConv(
+        MIRBuilder, ArgInfos, OrigRetIndices,
+        [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used,
+            unsigned origIdx, unsigned partOffs) {
+          Ins.emplace_back(flags, vt, argvt, used, origIdx, partOffs);
+        });
+
+    SmallVector<CCValAssign, 8> ArgLocs;
+    MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
+                       F.getContext());
+
+    CCInfo.AnalyzeCallResult(Ins, TLI.CCAssignFnForReturn(), OrigRet.Ty, Call);
+
+    CallReturnHandler Handler(MIRBuilder, MF.getRegInfo(), MIB);
+    if (!Handler.handle(ArgLocs, ArgInfos))
+      return false;
+  }
+
+  MIRBuilder.buildInstr(Mips::ADJCALLSTACKUP)
+      .addImm(ABI.GetCalleeAllocdArgSizeInBytes(CallConv))
+      .addImm(0);
+
+  return true;
+}
+
 void MipsCallLowering::subTargetRegTypeForCallingConv(
     MachineIRBuilder &MIRBuilder, ArrayRef<ArgInfo> Args,
     ArrayRef<unsigned> OrigArgIndices, const FunTy &PushBack) const {
index fe072c7..cdff19a 100644 (file)
@@ -48,6 +48,10 @@ public:
   bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
                             ArrayRef<unsigned> VRegs) const override;
 
+  bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
+                 const MachineOperand &Callee, const ArgInfo &OrigRet,
+                 ArrayRef<ArgInfo> OrigArgs) const override;
+
 private:
   using FunTy =
       std::function<void(ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used,
diff --git a/llvm/test/CodeGen/Mips/GlobalISel/irtranslator/call.ll b/llvm/test/CodeGen/Mips/GlobalISel/irtranslator/call.ll
new file mode 100644 (file)
index 0000000..b1ac258
--- /dev/null
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32
+
+declare i32 @f(i32 %a, i32 %b);
+
+define i32 @g(i32 %a0, i32 %a1, i32 %x, i32 %y) {
+  ; MIPS32-LABEL: name: g
+  ; MIPS32: bb.1.entry:
+  ; MIPS32:   liveins: $a0, $a1, $a2, $a3
+  ; MIPS32:   [[COPY:%[0-9]+]]:_(s32) = COPY $a0
+  ; MIPS32:   [[COPY1:%[0-9]+]]:_(s32) = COPY $a1
+  ; MIPS32:   [[COPY2:%[0-9]+]]:_(s32) = COPY $a2
+  ; MIPS32:   [[COPY3:%[0-9]+]]:_(s32) = COPY $a3
+  ; MIPS32:   ADJCALLSTACKDOWN 16, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   $a0 = COPY [[COPY2]](s32)
+  ; MIPS32:   $a1 = COPY [[COPY3]](s32)
+  ; MIPS32:   JAL @f, csr_o32, implicit-def $ra, implicit-def $sp, implicit $a0, implicit $a1, implicit-def $v0
+  ; MIPS32:   [[COPY4:%[0-9]+]]:_(s32) = COPY $v0
+  ; MIPS32:   ADJCALLSTACKUP 16, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY4]], [[COPY4]]
+  ; MIPS32:   $v0 = COPY [[ADD]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  %z = call i32 @f(i32 %x, i32 %y)
+  %doublez = add i32 %z, %z
+  ret i32 %doublez
+}
diff --git a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/call.ll b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/call.ll
new file mode 100644 (file)
index 0000000..2e388e4
--- /dev/null
@@ -0,0 +1,26 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc  -O0 -mtriple=mipsel-linux-gnu -global-isel  -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32
+
+declare i32 @f(i32 %a, i32 %b);
+
+define i32 @g(i32 %a0, i32 %a1, i32 %x, i32 %y) {
+; MIPS32-LABEL: g:
+; MIPS32:       # %bb.0: # %entry
+; MIPS32-NEXT:    addiu $sp, $sp, -24
+; MIPS32-NEXT:    .cfi_def_cfa_offset 24
+; MIPS32-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill
+; MIPS32-NEXT:    .cfi_offset 31, -4
+; MIPS32-NEXT:    move $4, $6
+; MIPS32-NEXT:    move $5, $7
+; MIPS32-NEXT:    jal f
+; MIPS32-NEXT:    nop
+; MIPS32-NEXT:    addu $2, $2, $2
+; MIPS32-NEXT:    lw $ra, 20($sp) # 4-byte Folded Reload
+; MIPS32-NEXT:    addiu $sp, $sp, 24
+; MIPS32-NEXT:    jr $ra
+; MIPS32-NEXT:    nop
+entry:
+  %z = call i32 @f(i32 %x, i32 %y)
+  %doublez = add i32 %z, %z
+  ret i32 %doublez
+}