[llvm] [X86][GlobalISel] Implement basic varargs for x86_64 Linux (PR #217113)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 12:58:48 PDT 2026


https://github.com/iDontHaveTime created https://github.com/llvm/llvm-project/pull/217113

Implement the va_start intrinsic for x86-64 SysV calling convention in GlobalISel.

Fixes #73106

>From 5ca074e217a736a938bc3706d64331a1ad498747 Mon Sep 17 00:00:00 2001
From: iDontHaveTime <timevanah at gmail.com>
Date: Tue, 18 Aug 2026 22:52:18 +0300
Subject: [PATCH] [X86][GlobalISel] Implement basic varargs for x86_64 Linux

---
 llvm/lib/Target/X86/GISel/X86CallLowering.cpp |  77 +++++-
 llvm/lib/Target/X86/GISel/X86CallLowering.h   |   4 +
 .../X86/GISel/X86InstructionSelector.cpp      | 225 +++++++++++++-----
 .../lib/Target/X86/GISel/X86LegalizerInfo.cpp |   2 +
 .../X86/GlobalISel/callingconv-varargs.ll     | 185 ++++++++++++++
 5 files changed, 420 insertions(+), 73 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/GlobalISel/callingconv-varargs.ll

diff --git a/llvm/lib/Target/X86/GISel/X86CallLowering.cpp b/llvm/lib/Target/X86/GISel/X86CallLowering.cpp
index 28764b535ba08..9f42310a72cd4 100644
--- a/llvm/lib/Target/X86/GISel/X86CallLowering.cpp
+++ b/llvm/lib/Target/X86/GISel/X86CallLowering.cpp
@@ -15,6 +15,7 @@
 #include "X86CallLowering.h"
 #include "X86CallingConv.h"
 #include "X86ISelLowering.h"
+#include "X86InstrBuilder.h"
 #include "X86InstrInfo.h"
 #include "X86MachineFunctionInfo.h"
 #include "X86RegisterInfo.h"
@@ -133,6 +134,11 @@ struct X86OutgoingValueHandler : public CallLowering::OutgoingValueHandler {
   const X86Subtarget &STI;
 };
 
+struct X86IncomingValueAssigner : public CallLowering::IncomingValueAssigner {
+  X86IncomingValueAssigner(CCAssignFn *AssignFn_, CCAssignFn *AssignFnVarArg_)
+      : IncomingValueAssigner(AssignFn_, AssignFnVarArg_) {}
+};
+
 } // end anonymous namespace
 
 bool X86CallLowering::canLowerReturn(
@@ -267,17 +273,23 @@ bool X86CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
                                            FunctionLoweringInfo &FLI) const {
   MachineFunction &MF = MIRBuilder.getMF();
   MachineRegisterInfo &MRI = MF.getRegInfo();
+  const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
   auto DL = MF.getDataLayout();
-  auto FuncInfo = MF.getInfo<X86MachineFunctionInfo>();
+  auto *FuncInfo = MF.getInfo<X86MachineFunctionInfo>();
 
-  SmallVector<ArgInfo, 8> SplitArgs;
+  // Handle only Linux SysV for varargs for now.
+  if (F.isVarArg() && !(STI.isTargetLinux() && STI.is64Bit() &&
+                        F.getCallingConv() == CallingConv::C))
+    return false;
 
+  SmallVector<ArgInfo, 8> SplitArgs;
   if (!FLI.CanLowerReturn)
     insertSRetIncomingArgument(F, SplitArgs, FLI.DemoteRegister, MRI, DL);
 
-  // TODO: handle variadic function
-  if (F.isVarArg())
-    return false;
+  // Offset in bytes from reg_save_area for general purpose args in varags.
+  unsigned GPOffset = 0;
+  // Offset in bytes from reg_save_area for floating point args in varargs.
+  unsigned FPOffset = 48;
 
   unsigned Idx = 0;
   for (const auto &Arg : F.args()) {
@@ -294,25 +306,54 @@ bool X86CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
       FuncInfo->setSRetReturnReg(VRegs[Idx][0]);
     }
 
+    // Scalars under or equal to 64 are considered INTEGER class.
+    if (GPOffset < 48 && Arg.getType()->isIntegerTy() &&
+        Arg.getType()->getIntegerBitWidth() <= 64) {
+      GPOffset += 8;
+    } else if (const Type *Ty = Arg.getType();
+               (Ty->isFloatTy() || Ty->isDoubleTy()) && FPOffset < 176) {
+      FPOffset += 16;
+    }
+
     ArgInfo OrigArg(VRegs[Idx], Arg.getType(), Idx);
     setArgFlags(OrigArg, Idx + AttributeList::FirstArgIndex, DL, F);
     splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv());
     Idx++;
   }
 
-  if (SplitArgs.empty())
-    return true;
-
   MachineBasicBlock &MBB = MIRBuilder.getMBB();
   if (!MBB.empty())
     MIRBuilder.setInstr(*MBB.begin());
 
-  X86OutgoingValueAssigner Assigner(CC_X86);
+  X86IncomingValueAssigner Assigner(CC_X86, CC_X86);
   FormalArgHandler Handler(MIRBuilder, MRI);
+
   if (!determineAndHandleAssignments(Handler, Assigner, SplitArgs, MIRBuilder,
                                      F.getCallingConv(), F.isVarArg()))
     return false;
 
+  if (F.isVarArg()) {
+    // In the x86_64 SystemV ABI the va_list struct requires a regsave area.
+    // FIXME: Test %al instead of allocating for all registers from the get go.
+    MachineFrameInfo &MFI = MF.getFrameInfo();
+    int RegSaveIndex = MFI.CreateStackObject(
+        /* GP Registers */ 6 * 8 + /* XMM Registers */ 8 * 16, Align(8), false);
+
+    // Put the registers into their slots as seen in Figure 3.33.
+    // %rdi - 0
+    // %rsi - 8
+    // %rdx - 16
+    // And so on.
+    saveVarArgRegistersSysV(MIRBuilder, RegSaveIndex);
+
+    // Store the variables into the machine function info.
+    FuncInfo->setVarArgsGPOffset(GPOffset);
+    FuncInfo->setVarArgsFPOffset(FPOffset);
+    FuncInfo->setVarArgsFrameIndex(
+        MFI.CreateFixedObject(1, alignTo(Assigner.StackSize, 8), true));
+    FuncInfo->setRegSaveFrameIndex(RegSaveIndex);
+  }
+
   // Move back to the end of the basic block.
   MIRBuilder.setMBB(MBB);
 
@@ -434,3 +475,21 @@ bool X86CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
 
   return true;
 }
+
+void X86CallLowering::saveVarArgRegistersSysV(MachineIRBuilder &MIRBuilder,
+                                              int FrameIdx) const {
+  int Offset = 0;
+  for (Register GPReg :
+       {X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9}) {
+    addFrameReference(MIRBuilder.buildInstr(X86::MOV64mr), FrameIdx, Offset)
+        .addReg(GPReg);
+    Offset += 8;
+  }
+
+  for (Register FPReg : {X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3, X86::XMM4,
+                         X86::XMM5, X86::XMM6, X86::XMM7}) {
+    addFrameReference(MIRBuilder.buildInstr(X86::MOVAPSmr), FrameIdx, Offset)
+        .addReg(FPReg);
+    Offset += 16;
+  }
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/X86/GISel/X86CallLowering.h b/llvm/lib/Target/X86/GISel/X86CallLowering.h
index 9067abf060bd9..47b3658768235 100644
--- a/llvm/lib/Target/X86/GISel/X86CallLowering.h
+++ b/llvm/lib/Target/X86/GISel/X86CallLowering.h
@@ -40,6 +40,10 @@ class X86CallLowering : public CallLowering {
   bool canLowerReturn(MachineFunction &MF, CallingConv::ID CallConv,
                       SmallVectorImpl<BaseArgInfo> &Outs,
                       bool IsVarArg) const override;
+
+private:
+  void saveVarArgRegistersSysV(MachineIRBuilder &MIRBuilder,
+                               int FrameIdx) const;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
index 113fd8867f2cd..9a33de417fd78 100644
--- a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
+++ b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
@@ -12,9 +12,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "MCTargetDesc/X86BaseInfo.h"
+#include "MCTargetDesc/X86MCTargetDesc.h"
 #include "X86.h"
 #include "X86InstrBuilder.h"
 #include "X86InstrInfo.h"
+#include "X86MachineFunctionInfo.h"
 #include "X86RegisterBankInfo.h"
 #include "X86RegisterInfo.h"
 #include "X86Subtarget.h"
@@ -122,6 +124,9 @@ class X86InstructionSelector : public InstructionSelector {
   bool selectSelect(MachineInstr &I, MachineRegisterInfo &MRI,
                     MachineFunction &MF) const;
 
+  bool selectVaStartSysVList(MachineInstr &I, MachineRegisterInfo &MRI,
+                             MachineFunction &MF) const;
+
   ComplexRendererFns selectAddr(MachineOperand &Root) const;
 
   // emit insert subreg instruction and insert it before MachineInstr &I
@@ -491,6 +496,13 @@ bool X86InstructionSelector::select(MachineInstr &I) {
     return selectMulDivRem(I, MRI, MF);
   case TargetOpcode::G_SELECT:
     return selectSelect(I, MRI, MF);
+  case TargetOpcode::G_VASTART:
+    // As mentioned in X86CallLowering.cpp only 64bit Linux with C calling
+    // convention for now.
+    return (MF.getFunction().getCallingConv() == CallingConv::C &&
+            STI.isTargetLinux() && STI.is64Bit())
+               ? selectVaStartSysVList(I, MRI, MF)
+               : false;
   }
 
   return false;
@@ -534,62 +546,62 @@ unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
     if (X86::GPRRegBankID == RB.getID())
       return Isload ? X86::MOV32rm : X86::MOV32mr;
     if (X86::VECRRegBankID == RB.getID())
-      return Isload ? (HasAVX512 ? X86::VMOVSSZrm_alt :
-                       HasAVX    ? X86::VMOVSSrm_alt :
-                                   X86::MOVSSrm_alt)
-                    : (HasAVX512 ? X86::VMOVSSZmr :
-                       HasAVX    ? X86::VMOVSSmr :
-                                   X86::MOVSSmr);
+      return Isload ? (HasAVX512 ? X86::VMOVSSZrm_alt
+                       : HasAVX  ? X86::VMOVSSrm_alt
+                                 : X86::MOVSSrm_alt)
+                    : (HasAVX512 ? X86::VMOVSSZmr
+                       : HasAVX  ? X86::VMOVSSmr
+                                 : X86::MOVSSmr);
     if (X86::PSRRegBankID == RB.getID())
       return Isload ? X86::LD_Fp32m : X86::ST_Fp32m;
   } else if (Ty == LLT::scalar(64)) {
     if (X86::GPRRegBankID == RB.getID())
       return Isload ? X86::MOV64rm : X86::MOV64mr;
     if (X86::VECRRegBankID == RB.getID())
-      return Isload ? (HasAVX512 ? X86::VMOVSDZrm_alt :
-                       HasAVX    ? X86::VMOVSDrm_alt :
-                                   X86::MOVSDrm_alt)
-                    : (HasAVX512 ? X86::VMOVSDZmr :
-                       HasAVX    ? X86::VMOVSDmr :
-                                   X86::MOVSDmr);
+      return Isload ? (HasAVX512 ? X86::VMOVSDZrm_alt
+                       : HasAVX  ? X86::VMOVSDrm_alt
+                                 : X86::MOVSDrm_alt)
+                    : (HasAVX512 ? X86::VMOVSDZmr
+                       : HasAVX  ? X86::VMOVSDmr
+                                 : X86::MOVSDmr);
     if (X86::PSRRegBankID == RB.getID())
       return Isload ? X86::LD_Fp64m : X86::ST_Fp64m;
   } else if (Ty == LLT::scalar(80)) {
     return Isload ? X86::LD_Fp80m : X86::ST_FpP80m;
   } else if (Ty.isVector() && Ty.getSizeInBits() == 128) {
     if (Alignment >= Align(16))
-      return Isload ? (HasVLX ? X86::VMOVAPSZ128rm
-                              : HasAVX512
-                                    ? X86::VMOVAPSZ128rm_NOVLX
-                                    : HasAVX ? X86::VMOVAPSrm : X86::MOVAPSrm)
-                    : (HasVLX ? X86::VMOVAPSZ128mr
-                              : HasAVX512
-                                    ? X86::VMOVAPSZ128mr_NOVLX
-                                    : HasAVX ? X86::VMOVAPSmr : X86::MOVAPSmr);
+      return Isload ? (HasVLX      ? X86::VMOVAPSZ128rm
+                       : HasAVX512 ? X86::VMOVAPSZ128rm_NOVLX
+                       : HasAVX    ? X86::VMOVAPSrm
+                                   : X86::MOVAPSrm)
+                    : (HasVLX      ? X86::VMOVAPSZ128mr
+                       : HasAVX512 ? X86::VMOVAPSZ128mr_NOVLX
+                       : HasAVX    ? X86::VMOVAPSmr
+                                   : X86::MOVAPSmr);
     else
-      return Isload ? (HasVLX ? X86::VMOVUPSZ128rm
-                              : HasAVX512
-                                    ? X86::VMOVUPSZ128rm_NOVLX
-                                    : HasAVX ? X86::VMOVUPSrm : X86::MOVUPSrm)
-                    : (HasVLX ? X86::VMOVUPSZ128mr
-                              : HasAVX512
-                                    ? X86::VMOVUPSZ128mr_NOVLX
-                                    : HasAVX ? X86::VMOVUPSmr : X86::MOVUPSmr);
+      return Isload ? (HasVLX      ? X86::VMOVUPSZ128rm
+                       : HasAVX512 ? X86::VMOVUPSZ128rm_NOVLX
+                       : HasAVX    ? X86::VMOVUPSrm
+                                   : X86::MOVUPSrm)
+                    : (HasVLX      ? X86::VMOVUPSZ128mr
+                       : HasAVX512 ? X86::VMOVUPSZ128mr_NOVLX
+                       : HasAVX    ? X86::VMOVUPSmr
+                                   : X86::MOVUPSmr);
   } else if (Ty.isVector() && Ty.getSizeInBits() == 256) {
     if (Alignment >= Align(32))
-      return Isload ? (HasVLX ? X86::VMOVAPSZ256rm
-                              : HasAVX512 ? X86::VMOVAPSZ256rm_NOVLX
-                                          : X86::VMOVAPSYrm)
-                    : (HasVLX ? X86::VMOVAPSZ256mr
-                              : HasAVX512 ? X86::VMOVAPSZ256mr_NOVLX
-                                          : X86::VMOVAPSYmr);
+      return Isload ? (HasVLX      ? X86::VMOVAPSZ256rm
+                       : HasAVX512 ? X86::VMOVAPSZ256rm_NOVLX
+                                   : X86::VMOVAPSYrm)
+                    : (HasVLX      ? X86::VMOVAPSZ256mr
+                       : HasAVX512 ? X86::VMOVAPSZ256mr_NOVLX
+                                   : X86::VMOVAPSYmr);
     else
-      return Isload ? (HasVLX ? X86::VMOVUPSZ256rm
-                              : HasAVX512 ? X86::VMOVUPSZ256rm_NOVLX
-                                          : X86::VMOVUPSYrm)
-                    : (HasVLX ? X86::VMOVUPSZ256mr
-                              : HasAVX512 ? X86::VMOVUPSZ256mr_NOVLX
-                                          : X86::VMOVUPSYmr);
+      return Isload ? (HasVLX      ? X86::VMOVUPSZ256rm
+                       : HasAVX512 ? X86::VMOVUPSZ256rm_NOVLX
+                                   : X86::VMOVUPSYrm)
+                    : (HasVLX      ? X86::VMOVUPSZ256mr
+                       : HasAVX512 ? X86::VMOVUPSZ256mr_NOVLX
+                                   : X86::VMOVUPSYmr);
   } else if (Ty.isVector() && Ty.getSizeInBits() == 512) {
     if (Alignment >= Align(64))
       return Isload ? X86::VMOVAPSZrm : X86::VMOVAPSZmr;
@@ -740,8 +752,9 @@ bool X86InstructionSelector::selectFrameIndexOrGep(MachineInstr &I,
                                                    MachineFunction &MF) const {
   unsigned Opc = I.getOpcode();
 
-  assert((Opc == TargetOpcode::G_FRAME_INDEX || Opc == TargetOpcode::G_PTR_ADD) &&
-         "unexpected instruction");
+  assert(
+      (Opc == TargetOpcode::G_FRAME_INDEX || Opc == TargetOpcode::G_PTR_ADD) &&
+      "unexpected instruction");
 
   const Register DefReg = I.getOperand(0).getReg();
   LLT Ty = MRI.getType(DefReg);
@@ -1083,8 +1096,10 @@ bool X86InstructionSelector::selectCmp(MachineInstr &I,
            .addReg(LHS)
            .addReg(RHS);
 
-  MachineInstr &SetInst = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
-                                   TII.get(X86::SETCCr), I.getOperand(0).getReg()).addImm(CC);
+  MachineInstr &SetInst =
+      *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::SETCCr),
+               I.getOperand(0).getReg())
+           .addImm(CC);
 
   constrainSelectedInstRegOperands(CmpInst, TII, TRI, RBI);
   constrainSelectedInstRegOperands(SetInst, TII, TRI, RBI);
@@ -1158,9 +1173,11 @@ bool X86InstructionSelector::selectFCmp(MachineInstr &I,
     Register FlagReg1 = MRI.createVirtualRegister(&X86::GR8RegClass);
     Register FlagReg2 = MRI.createVirtualRegister(&X86::GR8RegClass);
     MachineInstr &Set1 = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
-                                  TII.get(X86::SETCCr), FlagReg1).addImm(SETFOpc[0]);
+                                  TII.get(X86::SETCCr), FlagReg1)
+                              .addImm(SETFOpc[0]);
     MachineInstr &Set2 = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
-                                  TII.get(X86::SETCCr), FlagReg2).addImm(SETFOpc[1]);
+                                  TII.get(X86::SETCCr), FlagReg2)
+                              .addImm(SETFOpc[1]);
     MachineInstr &Set3 = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
                                   TII.get(SETFOpc[2]), ResultReg)
                               .addReg(FlagReg1)
@@ -1188,8 +1205,9 @@ bool X86InstructionSelector::selectFCmp(MachineInstr &I,
            .addReg(LhsReg)
            .addReg(RhsReg);
 
-  MachineInstr &Set =
-      *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::SETCCr), ResultReg).addImm(CC);
+  MachineInstr &Set = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
+                               TII.get(X86::SETCCr), ResultReg)
+                           .addImm(CC);
   constrainSelectedInstRegOperands(CmpInst, TII, TRI, RBI);
   constrainSelectedInstRegOperands(Set, TII, TRI, RBI);
   I.eraseFromParent();
@@ -1503,8 +1521,9 @@ bool X86InstructionSelector::selectInsert(MachineInstr &I,
   return true;
 }
 
-bool X86InstructionSelector::selectUnmergeValues(
-    MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) {
+bool X86InstructionSelector::selectUnmergeValues(MachineInstr &I,
+                                                 MachineRegisterInfo &MRI,
+                                                 MachineFunction &MF) {
   assert((I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES) &&
          "unexpected instruction");
 
@@ -1528,8 +1547,9 @@ bool X86InstructionSelector::selectUnmergeValues(
   return true;
 }
 
-bool X86InstructionSelector::selectMergeValues(
-    MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) {
+bool X86InstructionSelector::selectMergeValues(MachineInstr &I,
+                                               MachineRegisterInfo &MRI,
+                                               MachineFunction &MF) {
   assert((I.getOpcode() == TargetOpcode::G_MERGE_VALUES ||
           I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS) &&
          "unexpected instruction");
@@ -1577,6 +1597,82 @@ bool X86InstructionSelector::selectMergeValues(
   return true;
 }
 
+bool X86InstructionSelector::selectVaStartSysVList(MachineInstr &I,
+                                                   MachineRegisterInfo &MRI,
+                                                   MachineFunction &MF) const {
+  X86MachineFunctionInfo *FuncInfo = MF.getInfo<X86MachineFunctionInfo>();
+  // x86_64 SystemV va_list structure (Figure 3.34):
+  // typedef struct {
+  //   unsigned gp_offset;
+  //   unsigned fp_offset;
+  //   void *overflow_arg_area;
+  //   void *reg_save_area;
+  // }
+
+  // Offset of general purpose args in bytes, the value should range from 0
+  // to 48.
+  unsigned GPOffset = FuncInfo->getVarArgsGPOffset();
+  assert(GPOffset <= 48 && "GPOffset out of range");
+
+  // Offset of fp args in bytes, this should range 48 to 176.
+  unsigned FPOffset = FuncInfo->getVarArgsFPOffset();
+  assert(FPOffset >= 48 && FPOffset <= 176 && "FPOffset out of range");
+
+  // Frame index for the overflow arg area.
+  int OverflowIndex = FuncInfo->getVarArgsFrameIndex();
+  // Frame index for the register save area.
+  int RegSaveFrameIndex = FuncInfo->getRegSaveFrameIndex();
+
+  // Move the GP offset to the first 4 bytes.
+  addDirectMem(
+      BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::MOV32mi)),
+      I.getOperand(0).getReg())
+      .addImm(GPOffset);
+
+  // Move the FP offset after the GP.
+  addRegOffset(
+      BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::MOV32mi)),
+      I.getOperand(0).getReg(), false, 4)
+      .addImm(FPOffset);
+
+  // Move the overflow area to offset of 8.
+  Register OverflowPtr = MRI.createGenericVirtualRegister(LLT::pointer(0, 64));
+  MachineInstr &OverflowLeaInst =
+      *addFrameReference(BuildMI(*I.getParent(), I, I.getDebugLoc(),
+                                 TII.get(X86::LEA64r), OverflowPtr),
+                         OverflowIndex);
+
+  constrainSelectedInstRegOperands(OverflowLeaInst, TII, TRI, RBI);
+
+  MachineInstr &OverflowMovInst =
+      *addRegOffset(
+           BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::MOV64mr)),
+           I.getOperand(0).getReg(), false, 8)
+           .addReg(OverflowPtr);
+
+  constrainSelectedInstRegOperands(OverflowMovInst, TII, TRI, RBI);
+
+  // Move the register save area to the last 8 bytes.
+  Register RegSavePtr = MRI.createGenericVirtualRegister(LLT::pointer(0, 64));
+  MachineInstr &RegSaveLeaInst =
+      *addFrameReference(BuildMI(*I.getParent(), I, I.getDebugLoc(),
+                                 TII.get(X86::LEA64r), RegSavePtr),
+                         RegSaveFrameIndex);
+
+  constrainSelectedInstRegOperands(RegSaveLeaInst, TII, TRI, RBI);
+
+  MachineInstr &RegSaveMovInst =
+      *addRegOffset(
+           BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::MOV64mr)),
+           I.getOperand(0).getReg(), false, 16)
+           .addReg(RegSavePtr);
+
+  constrainSelectedInstRegOperands(RegSaveMovInst, TII, TRI, RBI);
+
+  I.eraseFromParent();
+  return true;
+}
+
 bool X86InstructionSelector::selectCondBranch(MachineInstr &I,
                                               MachineRegisterInfo &MRI,
                                               MachineFunction &MF) const {
@@ -1590,7 +1686,8 @@ bool X86InstructionSelector::selectCondBranch(MachineInstr &I,
            .addReg(CondReg)
            .addImm(1);
   BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::JCC_1))
-      .addMBB(DestMBB).addImm(X86::COND_NE);
+      .addMBB(DestMBB)
+      .addImm(X86::COND_NE);
 
   constrainSelectedInstRegOperands(TestInst, TII, TRI, RBI);
 
@@ -1739,13 +1836,13 @@ bool X86InstructionSelector::selectMulDivRem(MachineInstr &I,
     unsigned HighInReg; // high part of the register pair
     // The following portion depends on both the data type and the operation.
     struct MulDivRemResult {
-      unsigned OpMulDivRem;     // The specific MUL/DIV opcode to use.
-      unsigned OpSignExtend;    // Opcode for sign-extending lowreg into
-                                // highreg, or copying a zero into highreg.
-      unsigned OpCopy;          // Opcode for copying dividend into lowreg, or
-                                // zero/sign-extending into lowreg for i8.
-      unsigned ResultReg;       // Register containing the desired result.
-      bool IsOpSigned;          // Whether to use signed or unsigned form.
+      unsigned OpMulDivRem;  // The specific MUL/DIV opcode to use.
+      unsigned OpSignExtend; // Opcode for sign-extending lowreg into
+                             // highreg, or copying a zero into highreg.
+      unsigned OpCopy;       // Opcode for copying dividend into lowreg, or
+                             // zero/sign-extending into lowreg for i8.
+      unsigned ResultReg;    // Register containing the desired result.
+      bool IsOpSigned;       // Whether to use signed or unsigned form.
     } ResultTable[NumOps];
   } OpTable[NumTypes] = {
       {8,
@@ -1788,10 +1885,10 @@ bool X86InstructionSelector::selectMulDivRem(MachineInstr &I,
        X86::RAX,
        X86::RDX,
        {
-           {X86::IDIV64r, X86::CQO, Copy, X86::RAX, S},    // SDiv
-           {X86::IDIV64r, X86::CQO, Copy, X86::RDX, S},    // SRem
-           {X86::DIV64r, X86::MOV32r0, Copy, X86::RAX, U}, // UDiv
-           {X86::DIV64r, X86::MOV32r0, Copy, X86::RDX, U}, // URem
+           {X86::IDIV64r, X86::CQO, Copy, X86::RAX, S},     // SDiv
+           {X86::IDIV64r, X86::CQO, Copy, X86::RDX, S},     // SRem
+           {X86::DIV64r, X86::MOV32r0, Copy, X86::RAX, U},  // UDiv
+           {X86::DIV64r, X86::MOV32r0, Copy, X86::RDX, U},  // URem
            {X86::IMUL64r, X86::MOV32r0, Copy, X86::RAX, S}, // Mul
            {X86::IMUL64r, X86::MOV32r0, Copy, X86::RDX, S}, // SMulH
            {X86::MUL64r, X86::MOV32r0, Copy, X86::RDX, U},  // UMulH
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index cffba4d43abad..3c6343171302c 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -625,6 +625,8 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
   getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
   getActionDefinitionsBuilder(G_INVOKE_REGION_START).alwaysLegal();
 
+  getActionDefinitionsBuilder(G_VASTART).legalFor({p0});
+
   verify(*STI.getInstrInfo());
 }
 
diff --git a/llvm/test/CodeGen/X86/GlobalISel/callingconv-varargs.ll b/llvm/test/CodeGen/X86/GlobalISel/callingconv-varargs.ll
new file mode 100644
index 0000000000000..ba975f1a3315f
--- /dev/null
+++ b/llvm/test/CodeGen/X86/GlobalISel/callingconv-varargs.ll
@@ -0,0 +1,185 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=x86_64-linux-gnu -global-isel < %s | FileCheck %s
+
+%struct.__va_list_tag = type { i32, i32, ptr, ptr }
+
+define void @empty_varargs(i32 %c, ...) {
+; CHECK-LABEL: empty_varargs:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    subq $48, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 56
+; CHECK-NEXT:    movq %rdi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rsi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rdx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rcx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r8, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r9, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm1, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm2, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm3, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm4, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm5, (%rsp)
+; CHECK-NEXT:    movaps %xmm6, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm7, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    addq $48, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+entry:
+    ret void
+}
+
+define void @start_varargs(i32 %c, ...) {
+; CHECK-LABEL: start_varargs:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    subq $72, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 80
+; CHECK-NEXT:    movq %rdi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rsi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rdx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rcx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r8, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r9, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm1, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm2, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm3, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm4, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm5, (%rsp)
+; CHECK-NEXT:    movaps %xmm6, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm7, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rax
+; CHECK-NEXT:    movl $8, (%rax)
+; CHECK-NEXT:    movl $48, 4(%rax)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; CHECK-NEXT:    movq %rcx, 8(%rax)
+; CHECK-NEXT:    leaq -{{[0-9]+}}(%rsp), %rcx
+; CHECK-NEXT:    movq %rcx, 16(%rax)
+; CHECK-NEXT:    addq $72, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+    %1 = alloca [1 x %struct.__va_list_tag], align 16
+    %2 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_start.p0(ptr %2)
+
+    %3 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_end.p0(ptr %3)
+    ret void
+}
+
+define void @call_varargs(i32 %a, i32 %b, i32 %c, ...) {
+; CHECK-LABEL: call_varargs:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    subq $200, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 208
+; CHECK-NEXT:    movq %rdi, (%rsp)
+; CHECK-NEXT:    movq %rsi, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r8, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r9, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm0, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm1, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm2, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm3, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm4, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm5, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm6, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm7, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rax
+; CHECK-NEXT:    movl $24, (%rax)
+; CHECK-NEXT:    movl $48, 4(%rax)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; CHECK-NEXT:    movq %rcx, 8(%rax)
+; CHECK-NEXT:    movq %rsp, %rcx
+; CHECK-NEXT:    movq %rcx, 16(%rax)
+; CHECK-NEXT:    callq start_varargs
+; CHECK-NEXT:    addq $200, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+    %1 = alloca [1 x %struct.__va_list_tag], align 16
+    %2 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_start.p0(ptr %2)
+
+    call void @start_varargs(i32 %a, i32 %b, i32 %c)
+
+    %3 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_end.p0(ptr %3)
+    ret void
+}
+
+define void @fp_varargs(float %a, double %b, float %c, ...) {
+; CHECK-LABEL: fp_varargs:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    subq $72, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 80
+; CHECK-NEXT:    movq %rdi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rsi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rdx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rcx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r8, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r9, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm1, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm2, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm3, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm4, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm5, (%rsp)
+; CHECK-NEXT:    movaps %xmm6, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm7, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rax
+; CHECK-NEXT:    movl $0, (%rax)
+; CHECK-NEXT:    movl $96, 4(%rax)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; CHECK-NEXT:    movq %rcx, 8(%rax)
+; CHECK-NEXT:    leaq -{{[0-9]+}}(%rsp), %rcx
+; CHECK-NEXT:    movq %rcx, 16(%rax)
+; CHECK-NEXT:    addq $72, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+    %1 = alloca [1 x %struct.__va_list_tag], align 16
+    %2 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_start.p0(ptr %2)
+
+    %3 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_end.p0(ptr %3)
+    ret void
+}
+
+define void @mixed_varargs(i32 %a, i64 %b, float %c, double %d, i32 %e, ...) {
+; CHECK-LABEL: mixed_varargs:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    subq $72, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 80
+; CHECK-NEXT:    movq %rdi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rsi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rdx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rcx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r8, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %r9, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm1, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm2, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm3, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm4, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm5, (%rsp)
+; CHECK-NEXT:    movaps %xmm6, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm7, {{[0-9]+}}(%rsp)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rax
+; CHECK-NEXT:    movl $24, (%rax)
+; CHECK-NEXT:    movl $80, 4(%rax)
+; CHECK-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; CHECK-NEXT:    movq %rcx, 8(%rax)
+; CHECK-NEXT:    leaq -{{[0-9]+}}(%rsp), %rcx
+; CHECK-NEXT:    movq %rcx, 16(%rax)
+; CHECK-NEXT:    addq $72, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+    %1 = alloca [1 x %struct.__va_list_tag], align 16
+    %2 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_start.p0(ptr %2)
+
+    %3 = getelementptr [1 x %struct.__va_list_tag], ptr %1, i64 0, i64 0
+    call void @llvm.va_end.p0(ptr %3)
+    ret void
+}



More information about the llvm-commits mailing list