[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