[MIPS GlobalISel] Lower i8 and i16 arguments
authorPetar Jovanovic <petar.jovanovic@mips.com>
Thu, 23 Aug 2018 20:41:09 +0000 (20:41 +0000)
committerPetar Jovanovic <petar.jovanovic@mips.com>
Thu, 23 Aug 2018 20:41:09 +0000 (20:41 +0000)
Lower integer arguments smaller than i32.
Support both register and stack arguments.
Define setLocInfo function for setting LocInfo field in ArgLocs vector.

Patch by Petar Avramovic.

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

llvm-svn: 340572

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

index 47b9617..648dec5 100644 (file)
@@ -24,16 +24,12 @@ using namespace llvm;
 MipsCallLowering::MipsCallLowering(const MipsTargetLowering &TLI)
     : CallLowering(&TLI) {}
 
-bool MipsCallLowering::MipsHandler::assign(const CCValAssign &VA,
-                                           unsigned vreg) {
+bool MipsCallLowering::MipsHandler::assign(unsigned VReg,
+                                           const CCValAssign &VA) {
   if (VA.isRegLoc()) {
-    assignValueToReg(vreg, VA.getLocReg());
+    assignValueToReg(VReg, VA);
   } else if (VA.isMemLoc()) {
-    unsigned Size = alignTo(VA.getValVT().getSizeInBits(), 8) / 8;
-    unsigned Offset = VA.getLocMemOffset();
-    MachinePointerInfo MPO;
-    unsigned StackAddr = getStackAddress(Size, Offset, MPO);
-    assignValueToAddress(vreg, StackAddr, Size, MPO);
+    assignValueToAddress(VReg, VA);
   } else {
     return false;
   }
@@ -50,22 +46,20 @@ public:
               ArrayRef<CallLowering::ArgInfo> Args);
 
 private:
-  void assignValueToReg(unsigned ValVReg, unsigned PhysReg) override;
+  void assignValueToReg(unsigned ValVReg, const CCValAssign &VA) override;
 
-  unsigned getStackAddress(uint64_t Size, int64_t Offset,
-                           MachinePointerInfo &MPO) override;
+  unsigned getStackAddress(const CCValAssign &VA,
+                           MachineMemOperand *&MMO) override;
 
-  void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
-                            MachinePointerInfo &MPO) override;
+  void assignValueToAddress(unsigned ValVReg, const CCValAssign &VA) override;
 
   virtual void markPhysRegUsed(unsigned PhysReg) {
     MIRBuilder.getMBB().addLiveIn(PhysReg);
   }
 
-  void buildLoad(unsigned Val, unsigned Addr, uint64_t Size, unsigned Alignment,
-                 MachinePointerInfo &MPO) {
-    MachineMemOperand *MMO = MIRBuilder.getMF().getMachineMemOperand(
-        MPO, MachineMemOperand::MOLoad, Size, Alignment);
+  void buildLoad(unsigned Val, const CCValAssign &VA) {
+    MachineMemOperand *MMO;
+    unsigned Addr = getStackAddress(VA, MMO);
     MIRBuilder.buildLoad(Val, Addr, *MMO);
   }
 };
@@ -87,17 +81,34 @@ private:
 } // end anonymous namespace
 
 void IncomingValueHandler::assignValueToReg(unsigned ValVReg,
-                                            unsigned PhysReg) {
-  MIRBuilder.buildCopy(ValVReg, PhysReg);
+                                            const CCValAssign &VA) {
+  unsigned PhysReg = VA.getLocReg();
+  switch (VA.getLocInfo()) {
+  case CCValAssign::LocInfo::SExt:
+  case CCValAssign::LocInfo::ZExt:
+  case CCValAssign::LocInfo::AExt: {
+    auto Copy = MIRBuilder.buildCopy(LLT{VA.getLocVT()}, PhysReg);
+    MIRBuilder.buildTrunc(ValVReg, Copy);
+    break;
+  }
+  default:
+    MIRBuilder.buildCopy(ValVReg, PhysReg);
+    break;
+  }
   markPhysRegUsed(PhysReg);
 }
 
-unsigned IncomingValueHandler::getStackAddress(uint64_t Size, int64_t Offset,
-                                               MachinePointerInfo &MPO) {
+unsigned IncomingValueHandler::getStackAddress(const CCValAssign &VA,
+                                               MachineMemOperand *&MMO) {
+  unsigned Size = alignTo(VA.getValVT().getSizeInBits(), 8) / 8;
+  unsigned Offset = VA.getLocMemOffset();
   MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
 
   int FI = MFI.CreateFixedObject(Size, Offset, true);
-  MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
+  MachinePointerInfo MPO =
+      MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
+  MMO = MIRBuilder.getMF().getMachineMemOperand(MPO, MachineMemOperand::MOLoad,
+                                                Size, /* Alignment */ 0);
 
   unsigned AddrReg = MRI.createGenericVirtualRegister(LLT::pointer(0, 32));
   MIRBuilder.buildFrameIndex(AddrReg, FI);
@@ -105,17 +116,22 @@ unsigned IncomingValueHandler::getStackAddress(uint64_t Size, int64_t Offset,
   return AddrReg;
 }
 
-void IncomingValueHandler::assignValueToAddress(unsigned ValVReg, unsigned Addr,
-                                                uint64_t Size,
-                                                MachinePointerInfo &MPO) {
-  // If the value is not extended, a simple load will suffice.
-  buildLoad(ValVReg, Addr, Size, /* Alignment */ 0, MPO);
+void IncomingValueHandler::assignValueToAddress(unsigned ValVReg,
+                                                const CCValAssign &VA) {
+  if (VA.getLocInfo() == CCValAssign::SExt ||
+      VA.getLocInfo() == CCValAssign::ZExt ||
+      VA.getLocInfo() == CCValAssign::AExt) {
+    unsigned LoadReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
+    buildLoad(LoadReg, VA);
+    MIRBuilder.buildTrunc(ValVReg, LoadReg);
+  } else
+    buildLoad(ValVReg, VA);
 }
 
 bool IncomingValueHandler::handle(ArrayRef<CCValAssign> ArgLocs,
                                   ArrayRef<CallLowering::ArgInfo> Args) {
   for (unsigned i = 0, ArgsSize = Args.size(); i < ArgsSize; ++i) {
-    if (!assign(ArgLocs[i], Args[i].Reg))
+    if (!assign(Args[i].Reg, ArgLocs[i]))
       return false;
   }
   return true;
@@ -132,69 +148,134 @@ public:
               ArrayRef<CallLowering::ArgInfo> Args);
 
 private:
-  void assignValueToReg(unsigned ValVReg, unsigned PhysReg) override;
+  void assignValueToReg(unsigned ValVReg, const CCValAssign &VA) override;
 
-  unsigned getStackAddress(uint64_t Size, int64_t Offset,
-                           MachinePointerInfo &MPO) override;
+  unsigned getStackAddress(const CCValAssign &VA,
+                           MachineMemOperand *&MMO) override;
 
-  void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
-                            MachinePointerInfo &MPO) override;
+  void assignValueToAddress(unsigned ValVReg, const CCValAssign &VA) override;
+
+  unsigned extendRegister(unsigned ValReg, const CCValAssign &VA);
 
   MachineInstrBuilder &MIB;
 };
 } // end anonymous namespace
 
 void OutgoingValueHandler::assignValueToReg(unsigned ValVReg,
-                                            unsigned PhysReg) {
-  MIRBuilder.buildCopy(PhysReg, ValVReg);
+                                            const CCValAssign &VA) {
+  unsigned PhysReg = VA.getLocReg();
+  unsigned ExtReg = extendRegister(ValVReg, VA);
+  MIRBuilder.buildCopy(PhysReg, ExtReg);
   MIB.addUse(PhysReg, RegState::Implicit);
 }
 
-unsigned OutgoingValueHandler::getStackAddress(uint64_t Size, int64_t Offset,
-                                               MachinePointerInfo &MPO) {
+unsigned OutgoingValueHandler::getStackAddress(const CCValAssign &VA,
+                                               MachineMemOperand *&MMO) {
   LLT p0 = LLT::pointer(0, 32);
   LLT s32 = LLT::scalar(32);
   unsigned SPReg = MRI.createGenericVirtualRegister(p0);
   MIRBuilder.buildCopy(SPReg, Mips::SP);
 
   unsigned OffsetReg = MRI.createGenericVirtualRegister(s32);
+  unsigned Offset = VA.getLocMemOffset();
   MIRBuilder.buildConstant(OffsetReg, Offset);
 
   unsigned AddrReg = MRI.createGenericVirtualRegister(p0);
   MIRBuilder.buildGEP(AddrReg, SPReg, OffsetReg);
 
-  MPO = MachinePointerInfo::getStack(MIRBuilder.getMF(), Offset);
+  MachinePointerInfo MPO =
+      MachinePointerInfo::getStack(MIRBuilder.getMF(), Offset);
+  unsigned Size = alignTo(VA.getValVT().getSizeInBits(), 8) / 8;
+  MMO = MIRBuilder.getMF().getMachineMemOperand(MPO, MachineMemOperand::MOStore,
+                                                Size, /* Alignment */ 0);
+
   return AddrReg;
 }
 
-void OutgoingValueHandler::assignValueToAddress(unsigned ValVReg, unsigned Addr,
-                                                uint64_t Size,
-                                                MachinePointerInfo &MPO) {
-  MachineMemOperand *MMO = MIRBuilder.getMF().getMachineMemOperand(
-      MPO, MachineMemOperand::MOStore, Size, /* Alignment */ 0);
-  MIRBuilder.buildStore(ValVReg, Addr, *MMO);
+void OutgoingValueHandler::assignValueToAddress(unsigned ValVReg,
+                                                const CCValAssign &VA) {
+  MachineMemOperand *MMO;
+  unsigned Addr = getStackAddress(VA, MMO);
+  unsigned ExtReg = extendRegister(ValVReg, VA);
+  MIRBuilder.buildStore(ExtReg, Addr, *MMO);
+}
+
+unsigned OutgoingValueHandler::extendRegister(unsigned ValReg,
+                                              const CCValAssign &VA) {
+  LLT LocTy{VA.getLocVT()};
+  switch (VA.getLocInfo()) {
+  case CCValAssign::SExt: {
+    unsigned ExtReg = MRI.createGenericVirtualRegister(LocTy);
+    MIRBuilder.buildSExt(ExtReg, ValReg);
+    return ExtReg;
+  }
+  case CCValAssign::ZExt: {
+    unsigned ExtReg = MRI.createGenericVirtualRegister(LocTy);
+    MIRBuilder.buildZExt(ExtReg, ValReg);
+    return ExtReg;
+  }
+  case CCValAssign::AExt: {
+    unsigned ExtReg = MRI.createGenericVirtualRegister(LocTy);
+    MIRBuilder.buildAnyExt(ExtReg, ValReg);
+    return ExtReg;
+  }
+  // TODO : handle upper extends
+  case CCValAssign::Full:
+    return ValReg;
+  default:
+    break;
+  }
+  llvm_unreachable("unable to extend register");
 }
 
 bool OutgoingValueHandler::handle(ArrayRef<CCValAssign> ArgLocs,
                                   ArrayRef<CallLowering::ArgInfo> Args) {
   for (unsigned i = 0; i < Args.size(); ++i) {
-    if (!assign(ArgLocs[i], Args[i].Reg))
+    if (!assign(Args[i].Reg, ArgLocs[i]))
       return false;
   }
   return true;
 }
 
 static bool isSupportedType(Type *T) {
-  if (T->isIntegerTy() && T->getScalarSizeInBits() == 32)
+  if (T->isIntegerTy() && T->getScalarSizeInBits() <= 32)
     return true;
   if (T->isPointerTy())
     return true;
   return false;
 }
 
+CCValAssign::LocInfo determineLocInfo(const MVT RegisterVT, const EVT VT,
+                                      const ISD::ArgFlagsTy &Flags) {
+  if (VT.getSizeInBits() == RegisterVT.getSizeInBits())
+    return CCValAssign::LocInfo::Full;
+  if (Flags.isSExt())
+    return CCValAssign::LocInfo::SExt;
+  if (Flags.isZExt())
+    return CCValAssign::LocInfo::ZExt;
+  return CCValAssign::LocInfo::AExt;
+}
+
+template <typename T>
+void setLocInfo(SmallVectorImpl<CCValAssign> &ArgLocs,
+                const SmallVectorImpl<T> &Arguments) {
+  for (unsigned i = 0; i < ArgLocs.size(); ++i) {
+    const CCValAssign &VA = ArgLocs[i];
+    CCValAssign::LocInfo LocInfo = determineLocInfo(
+        Arguments[i].VT, Arguments[i].ArgVT, Arguments[i].Flags);
+    if (VA.isMemLoc())
+      ArgLocs[i] =
+          CCValAssign::getMem(VA.getValNo(), VA.getValVT(),
+                              VA.getLocMemOffset(), VA.getLocVT(), LocInfo);
+    else
+      ArgLocs[i] = CCValAssign::getReg(VA.getValNo(), VA.getValVT(),
+                                       VA.getLocReg(), VA.getLocVT(), LocInfo);
+  }
+}
+
 bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
-                                      const Value *Val,
-                                      ArrayRef<unsigned> VRegs) const {
+                                   const Value *Val,
+                                   ArrayRef<unsigned> VRegs) const {
 
   MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA);
 
@@ -234,6 +315,7 @@ bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
     MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
                        F.getContext());
     CCInfo.AnalyzeReturn(Outs, TLI.CCAssignFnForReturn());
+    setLocInfo(ArgLocs, Outs);
 
     OutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);
     if (!RetHandler.handle(ArgLocs, RetInfos)) {
@@ -293,6 +375,7 @@ bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
   CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(F.getCallingConv()),
                        1);
   CCInfo.AnalyzeFormalArguments(Ins, TLI.CCAssignFnForCall());
+  setLocInfo(ArgLocs, Ins);
 
   IncomingValueHandler Handler(MIRBuilder, MF.getRegInfo());
   if (!Handler.handle(ArgLocs, ArgInfos))
@@ -371,6 +454,7 @@ bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
   CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(CallConv), 1);
   const char *Call = Callee.isSymbol() ? Callee.getSymbolName() : nullptr;
   CCInfo.AnalyzeCallOperands(Outs, TLI.CCAssignFnForCall(), FuncOrigArgs, Call);
+  setLocInfo(ArgLocs, Outs);
 
   OutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), MIB);
   if (!RetHandler.handle(ArgLocs, ArgInfos)) {
@@ -405,6 +489,7 @@ bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
                        F.getContext());
 
     CCInfo.AnalyzeCallResult(Ins, TLI.CCAssignFnForReturn(), OrigRet.Ty, Call);
+    setLocInfo(ArgLocs, Ins);
 
     CallReturnHandler Handler(MIRBuilder, MF.getRegInfo(), MIB);
     if (!Handler.handle(ArgLocs, ArgInfos))
index 63fea65..6481e42 100644 (file)
@@ -32,20 +32,19 @@ public:
     virtual ~MipsHandler() = default;
 
   protected:
-    bool assign(const CCValAssign &VA, unsigned vreg);
+    bool assign(unsigned VReg, const CCValAssign &VA);
 
     MachineIRBuilder &MIRBuilder;
     MachineRegisterInfo &MRI;
 
   private:
-    virtual unsigned getStackAddress(uint64_t Size, int64_t Offset,
-                                     MachinePointerInfo &MPO) = 0;
+    virtual unsigned getStackAddress(const CCValAssign &VA,
+                                     MachineMemOperand *&MMO) = 0;
 
-    virtual void assignValueToReg(unsigned ValVReg, unsigned PhysReg) = 0;
+    virtual void assignValueToReg(unsigned ValVReg, const CCValAssign &VA) = 0;
 
-    virtual void assignValueToAddress(unsigned ValVReg, unsigned Addr,
-                                      uint64_t Size,
-                                      MachinePointerInfo &MPO) = 0;
+    virtual void assignValueToAddress(unsigned ValVReg,
+                                      const CCValAssign &VA) = 0;
   };
 
   MipsCallLowering(const MipsTargetLowering &TLI);
diff --git a/llvm/test/CodeGen/Mips/GlobalISel/irtranslator/extend_args.ll b/llvm/test/CodeGen/Mips/GlobalISel/irtranslator/extend_args.ll
new file mode 100644 (file)
index 0000000..f8cf2c2
--- /dev/null
@@ -0,0 +1,288 @@
+; 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
+
+
+define  signext i8 @sext_arg_i8(i8 signext %a) {
+  ; MIPS32-LABEL: name: sext_arg_i8
+  ; MIPS32: bb.1.entry:
+  ; MIPS32:   liveins: $a0
+  ; MIPS32:   [[COPY:%[0-9]+]]:_(s32) = COPY $a0
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32)
+  ; MIPS32:   [[SEXT:%[0-9]+]]:_(s32) = G_SEXT [[TRUNC]](s8)
+  ; MIPS32:   $v0 = COPY [[SEXT]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  ret i8 %a
+}
+
+define zeroext i8 @zext_arg_i8(i8 zeroext %a) {
+  ; MIPS32-LABEL: name: zext_arg_i8
+  ; MIPS32: bb.1.entry:
+  ; MIPS32:   liveins: $a0
+  ; MIPS32:   [[COPY:%[0-9]+]]:_(s32) = COPY $a0
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32)
+  ; MIPS32:   [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC]](s8)
+  ; MIPS32:   $v0 = COPY [[ZEXT]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  ret i8 %a
+}
+
+define i8 @aext_arg_i8(i8 %a) {
+  ; MIPS32-LABEL: name: aext_arg_i8
+  ; MIPS32: bb.1.entry:
+  ; MIPS32:   liveins: $a0
+  ; MIPS32:   [[COPY:%[0-9]+]]:_(s32) = COPY $a0
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32)
+  ; MIPS32:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC]](s8)
+  ; MIPS32:   $v0 = COPY [[ANYEXT]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  ret i8 %a
+}
+
+declare signext i8 @sext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 %a)
+declare zeroext i8 @zext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 %a)
+declare i8 @aext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 %a)
+
+define signext i8 @call_sext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 signext %a) {
+  ; MIPS32-LABEL: name: call_sext_stack_arg_i8
+  ; 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:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; MIPS32:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.0, align 0)
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[LOAD]](s32)
+  ; MIPS32:   ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   $a0 = COPY [[COPY]](s32)
+  ; MIPS32:   $a1 = COPY [[COPY1]](s32)
+  ; MIPS32:   $a2 = COPY [[COPY2]](s32)
+  ; MIPS32:   $a3 = COPY [[COPY3]](s32)
+  ; MIPS32:   [[COPY4:%[0-9]+]]:_(p0) = COPY $sp
+  ; MIPS32:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+  ; MIPS32:   [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY4]], [[C]](s32)
+  ; MIPS32:   [[SEXT:%[0-9]+]]:_(s32) = G_SEXT [[TRUNC]](s8)
+  ; MIPS32:   G_STORE [[SEXT]](s32), [[GEP]](p0) :: (store 4 into stack + 16, align 0)
+  ; MIPS32:   JAL @sext_stack_arg_i8, csr_o32, implicit-def $ra, implicit-def $sp, implicit $a0, implicit $a1, implicit $a2, implicit $a3, implicit-def $v0
+  ; MIPS32:   [[COPY5:%[0-9]+]]:_(s32) = COPY $v0
+  ; MIPS32:   [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY5]](s32)
+  ; MIPS32:   ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   [[SEXT1:%[0-9]+]]:_(s32) = G_SEXT [[TRUNC1]](s8)
+  ; MIPS32:   $v0 = COPY [[SEXT1]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  %call = call signext i8 @sext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 signext %a)
+  ret i8 %call
+}
+
+define zeroext i8 @call_zext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 zeroext %a) {
+  ; MIPS32-LABEL: name: call_zext_stack_arg_i8
+  ; 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:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; MIPS32:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.0, align 0)
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[LOAD]](s32)
+  ; MIPS32:   ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   $a0 = COPY [[COPY]](s32)
+  ; MIPS32:   $a1 = COPY [[COPY1]](s32)
+  ; MIPS32:   $a2 = COPY [[COPY2]](s32)
+  ; MIPS32:   $a3 = COPY [[COPY3]](s32)
+  ; MIPS32:   [[COPY4:%[0-9]+]]:_(p0) = COPY $sp
+  ; MIPS32:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+  ; MIPS32:   [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY4]], [[C]](s32)
+  ; MIPS32:   [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC]](s8)
+  ; MIPS32:   G_STORE [[ZEXT]](s32), [[GEP]](p0) :: (store 4 into stack + 16, align 0)
+  ; MIPS32:   JAL @zext_stack_arg_i8, csr_o32, implicit-def $ra, implicit-def $sp, implicit $a0, implicit $a1, implicit $a2, implicit $a3, implicit-def $v0
+  ; MIPS32:   [[COPY5:%[0-9]+]]:_(s32) = COPY $v0
+  ; MIPS32:   [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY5]](s32)
+  ; MIPS32:   ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   [[ZEXT1:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC1]](s8)
+  ; MIPS32:   $v0 = COPY [[ZEXT1]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  %call = call zeroext i8 @zext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 zeroext %a)
+  ret i8 %call
+}
+
+define i8 @call_aext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 %a) {
+  ; MIPS32-LABEL: name: call_aext_stack_arg_i8
+  ; 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:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; MIPS32:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.0, align 0)
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[LOAD]](s32)
+  ; MIPS32:   ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   $a0 = COPY [[COPY]](s32)
+  ; MIPS32:   $a1 = COPY [[COPY1]](s32)
+  ; MIPS32:   $a2 = COPY [[COPY2]](s32)
+  ; MIPS32:   $a3 = COPY [[COPY3]](s32)
+  ; MIPS32:   [[COPY4:%[0-9]+]]:_(p0) = COPY $sp
+  ; MIPS32:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+  ; MIPS32:   [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY4]], [[C]](s32)
+  ; MIPS32:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC]](s8)
+  ; MIPS32:   G_STORE [[ANYEXT]](s32), [[GEP]](p0) :: (store 4 into stack + 16, align 0)
+  ; MIPS32:   JAL @aext_stack_arg_i8, csr_o32, implicit-def $ra, implicit-def $sp, implicit $a0, implicit $a1, implicit $a2, implicit $a3, implicit-def $v0
+  ; MIPS32:   [[COPY5:%[0-9]+]]:_(s32) = COPY $v0
+  ; MIPS32:   [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY5]](s32)
+  ; MIPS32:   ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC1]](s8)
+  ; MIPS32:   $v0 = COPY [[ANYEXT1]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  %call = call i8 @aext_stack_arg_i8(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i8 %a)
+  ret i8 %call
+}
+
+
+define  signext i16 @sext_arg_i16(i16 signext %a) {
+  ; MIPS32-LABEL: name: sext_arg_i16
+  ; MIPS32: bb.1.entry:
+  ; MIPS32:   liveins: $a0
+  ; MIPS32:   [[COPY:%[0-9]+]]:_(s32) = COPY $a0
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
+  ; MIPS32:   [[SEXT:%[0-9]+]]:_(s32) = G_SEXT [[TRUNC]](s16)
+  ; MIPS32:   $v0 = COPY [[SEXT]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  ret i16 %a
+}
+
+define zeroext i16 @zext_arg_i16(i16 zeroext %a) {
+  ; MIPS32-LABEL: name: zext_arg_i16
+  ; MIPS32: bb.1.entry:
+  ; MIPS32:   liveins: $a0
+  ; MIPS32:   [[COPY:%[0-9]+]]:_(s32) = COPY $a0
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
+  ; MIPS32:   [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC]](s16)
+  ; MIPS32:   $v0 = COPY [[ZEXT]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  ret i16 %a
+}
+
+define i16 @aext_arg_i16(i16 %a) {
+  ; MIPS32-LABEL: name: aext_arg_i16
+  ; MIPS32: bb.1.entry:
+  ; MIPS32:   liveins: $a0
+  ; MIPS32:   [[COPY:%[0-9]+]]:_(s32) = COPY $a0
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
+  ; MIPS32:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC]](s16)
+  ; MIPS32:   $v0 = COPY [[ANYEXT]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  ret i16 %a
+}
+
+declare signext i16 @sext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 %a)
+declare zeroext i16 @zext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 %a)
+declare i16 @aext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 %a)
+
+define signext i16 @call_sext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 signext %a) {
+  ; MIPS32-LABEL: name: call_sext_stack_arg_i16
+  ; 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:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; MIPS32:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.0, align 0)
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[LOAD]](s32)
+  ; MIPS32:   ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   $a0 = COPY [[COPY]](s32)
+  ; MIPS32:   $a1 = COPY [[COPY1]](s32)
+  ; MIPS32:   $a2 = COPY [[COPY2]](s32)
+  ; MIPS32:   $a3 = COPY [[COPY3]](s32)
+  ; MIPS32:   [[COPY4:%[0-9]+]]:_(p0) = COPY $sp
+  ; MIPS32:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+  ; MIPS32:   [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY4]], [[C]](s32)
+  ; MIPS32:   [[SEXT:%[0-9]+]]:_(s32) = G_SEXT [[TRUNC]](s16)
+  ; MIPS32:   G_STORE [[SEXT]](s32), [[GEP]](p0) :: (store 4 into stack + 16, align 0)
+  ; MIPS32:   JAL @sext_stack_arg_i16, csr_o32, implicit-def $ra, implicit-def $sp, implicit $a0, implicit $a1, implicit $a2, implicit $a3, implicit-def $v0
+  ; MIPS32:   [[COPY5:%[0-9]+]]:_(s32) = COPY $v0
+  ; MIPS32:   [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY5]](s32)
+  ; MIPS32:   ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   [[SEXT1:%[0-9]+]]:_(s32) = G_SEXT [[TRUNC1]](s16)
+  ; MIPS32:   $v0 = COPY [[SEXT1]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  %call = call signext i16 @sext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 signext %a)
+  ret i16 %call
+}
+
+define zeroext i16 @call_zext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 zeroext %a) {
+  ; MIPS32-LABEL: name: call_zext_stack_arg_i16
+  ; 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:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; MIPS32:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.0, align 0)
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[LOAD]](s32)
+  ; MIPS32:   ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   $a0 = COPY [[COPY]](s32)
+  ; MIPS32:   $a1 = COPY [[COPY1]](s32)
+  ; MIPS32:   $a2 = COPY [[COPY2]](s32)
+  ; MIPS32:   $a3 = COPY [[COPY3]](s32)
+  ; MIPS32:   [[COPY4:%[0-9]+]]:_(p0) = COPY $sp
+  ; MIPS32:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+  ; MIPS32:   [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY4]], [[C]](s32)
+  ; MIPS32:   [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC]](s16)
+  ; MIPS32:   G_STORE [[ZEXT]](s32), [[GEP]](p0) :: (store 4 into stack + 16, align 0)
+  ; MIPS32:   JAL @zext_stack_arg_i16, csr_o32, implicit-def $ra, implicit-def $sp, implicit $a0, implicit $a1, implicit $a2, implicit $a3, implicit-def $v0
+  ; MIPS32:   [[COPY5:%[0-9]+]]:_(s32) = COPY $v0
+  ; MIPS32:   [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY5]](s32)
+  ; MIPS32:   ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   [[ZEXT1:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC1]](s16)
+  ; MIPS32:   $v0 = COPY [[ZEXT1]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  %call = call zeroext i16 @zext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 zeroext %a)
+  ret i16 %call
+}
+
+define i16 @call_aext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 %a) {
+  ; MIPS32-LABEL: name: call_aext_stack_arg_i16
+  ; 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:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; MIPS32:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load 4 from %fixed-stack.0, align 0)
+  ; MIPS32:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[LOAD]](s32)
+  ; MIPS32:   ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   $a0 = COPY [[COPY]](s32)
+  ; MIPS32:   $a1 = COPY [[COPY1]](s32)
+  ; MIPS32:   $a2 = COPY [[COPY2]](s32)
+  ; MIPS32:   $a3 = COPY [[COPY3]](s32)
+  ; MIPS32:   [[COPY4:%[0-9]+]]:_(p0) = COPY $sp
+  ; MIPS32:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+  ; MIPS32:   [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY4]], [[C]](s32)
+  ; MIPS32:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC]](s16)
+  ; MIPS32:   G_STORE [[ANYEXT]](s32), [[GEP]](p0) :: (store 4 into stack + 16, align 0)
+  ; MIPS32:   JAL @aext_stack_arg_i16, csr_o32, implicit-def $ra, implicit-def $sp, implicit $a0, implicit $a1, implicit $a2, implicit $a3, implicit-def $v0
+  ; MIPS32:   [[COPY5:%[0-9]+]]:_(s32) = COPY $v0
+  ; MIPS32:   [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY5]](s32)
+  ; MIPS32:   ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
+  ; MIPS32:   [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC1]](s16)
+  ; MIPS32:   $v0 = COPY [[ANYEXT1]](s32)
+  ; MIPS32:   RetRA implicit $v0
+entry:
+  %call = call i16 @aext_stack_arg_i16(i32 %x1, i32 %x2, i32 %x3, i32 %x4, i16 %a)
+  ret i16 %call
+}