mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[VE] vaarg functions callers and callees
Summary: Isel patterns and tests for vaarg functions as callers and callees. Reviewers: arsenm, rengolin, k-ishizaka Subscribers: merge_guards_bot, wdng, hiraditya, llvm-commits Tags: #ve, #llvm Differential Revision: https://reviews.llvm.org/D73710
This commit is contained in:
parent
8301fd0d00
commit
b2d7ee731b
@ -49,6 +49,19 @@ def CC_VE : CallingConv<[
|
||||
CCDelegateTo<CC_VE_C_Stack>
|
||||
]>;
|
||||
|
||||
// All arguments get passed in stack for varargs function or non-prototyped
|
||||
// function.
|
||||
def CC_VE2 : CallingConv<[
|
||||
// float --> need special handling like below.
|
||||
// 0 4
|
||||
// +------+------+
|
||||
// | empty| float|
|
||||
// +------+------+
|
||||
CCIfType<[f32], CCCustom<"allocateFloat">>,
|
||||
|
||||
CCAssignToStack<0, 8>
|
||||
]>;
|
||||
|
||||
def RetCC_VE : CallingConv<[
|
||||
// Promote i1/i8/i16 arguments to i32.
|
||||
CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "VEISelLowering.h"
|
||||
#include "MCTargetDesc/VEMCExpr.h"
|
||||
#include "VEMachineFunctionInfo.h"
|
||||
#include "VERegisterInfo.h"
|
||||
#include "VETargetMachine.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
@ -203,7 +204,20 @@ SDValue VETargetLowering::LowerFormalArguments(
|
||||
MachinePointerInfo::getFixedStack(MF, FI)));
|
||||
}
|
||||
|
||||
assert(!IsVarArg && "TODO implement var args");
|
||||
if (!IsVarArg)
|
||||
return Chain;
|
||||
|
||||
// This function takes variable arguments, some of which may have been passed
|
||||
// in registers %s0-%s8.
|
||||
//
|
||||
// The va_start intrinsic needs to know the offset to the first variable
|
||||
// argument.
|
||||
// TODO: need to calculate offset correctly once we support f128.
|
||||
unsigned ArgOffset = ArgLocs.size() * 8;
|
||||
VEMachineFunctionInfo *FuncInfo = MF.getInfo<VEMachineFunctionInfo>();
|
||||
// Skip the 176 bytes of register save area.
|
||||
FuncInfo->setVarArgsFrameOffset(ArgOffset + ArgsBaseOffset);
|
||||
|
||||
return Chain;
|
||||
}
|
||||
|
||||
@ -258,7 +272,16 @@ SDValue VETargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
// by CC_VE would be correct now.
|
||||
CCInfo.AnalyzeCallOperands(CLI.Outs, CC_VE);
|
||||
|
||||
assert(!CLI.IsVarArg);
|
||||
// VE requires to use both register and stack for varargs or no-prototyped
|
||||
// functions.
|
||||
bool UseBoth = CLI.IsVarArg;
|
||||
|
||||
// Analyze operands again if it is required to store BOTH.
|
||||
SmallVector<CCValAssign, 16> ArgLocs2;
|
||||
CCState CCInfo2(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(),
|
||||
ArgLocs2, *DAG.getContext());
|
||||
if (UseBoth)
|
||||
CCInfo2.AnalyzeCallOperands(CLI.Outs, CC_VE2);
|
||||
|
||||
// Get the size of the outgoing arguments stack space requirement.
|
||||
unsigned ArgsSize = CCInfo.getNextStackOffset();
|
||||
@ -326,7 +349,9 @@ SDValue VETargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
|
||||
if (VA.isRegLoc()) {
|
||||
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
|
||||
continue;
|
||||
if (!UseBoth)
|
||||
continue;
|
||||
VA = ArgLocs2[i];
|
||||
}
|
||||
|
||||
assert(VA.isMemLoc());
|
||||
@ -502,6 +527,15 @@ VETargetLowering::VETargetLowering(const TargetMachine &TM,
|
||||
setOperationAction(ISD::BlockAddress, PtrVT, Custom);
|
||||
setOperationAction(ISD::GlobalAddress, PtrVT, Custom);
|
||||
|
||||
/// VAARG handling {
|
||||
setOperationAction(ISD::VASTART, MVT::Other, Custom);
|
||||
// VAARG needs to be lowered to access with 8 bytes alignment.
|
||||
setOperationAction(ISD::VAARG, MVT::Other, Custom);
|
||||
// Use the default implementation.
|
||||
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
||||
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
||||
/// } VAARG handling
|
||||
|
||||
// VE has no REM or DIVREM operations.
|
||||
for (MVT IntVT : MVT::integer_valuetypes()) {
|
||||
setOperationAction(ISD::UREM, IntVT, Expand);
|
||||
@ -604,6 +638,66 @@ SDValue VETargetLowering::LowerBlockAddress(SDValue Op,
|
||||
return makeAddress(Op, DAG);
|
||||
}
|
||||
|
||||
SDValue VETargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
VEMachineFunctionInfo *FuncInfo = MF.getInfo<VEMachineFunctionInfo>();
|
||||
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
||||
|
||||
// Need frame address to find the address of VarArgsFrameIndex.
|
||||
MF.getFrameInfo().setFrameAddressIsTaken(true);
|
||||
|
||||
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
||||
// memory location argument.
|
||||
SDLoc DL(Op);
|
||||
SDValue Offset =
|
||||
DAG.getNode(ISD::ADD, DL, PtrVT, DAG.getRegister(VE::SX9, PtrVT),
|
||||
DAG.getIntPtrConstant(FuncInfo->getVarArgsFrameOffset(), DL));
|
||||
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
||||
return DAG.getStore(Op.getOperand(0), DL, Offset, Op.getOperand(1),
|
||||
MachinePointerInfo(SV));
|
||||
}
|
||||
|
||||
SDValue VETargetLowering::LowerVAARG(SDValue Op, SelectionDAG &DAG) const {
|
||||
SDNode *Node = Op.getNode();
|
||||
EVT VT = Node->getValueType(0);
|
||||
SDValue InChain = Node->getOperand(0);
|
||||
SDValue VAListPtr = Node->getOperand(1);
|
||||
EVT PtrVT = VAListPtr.getValueType();
|
||||
const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
|
||||
SDLoc DL(Node);
|
||||
SDValue VAList =
|
||||
DAG.getLoad(PtrVT, DL, InChain, VAListPtr, MachinePointerInfo(SV));
|
||||
SDValue Chain = VAList.getValue(1);
|
||||
SDValue NextPtr;
|
||||
|
||||
if (VT == MVT::f32) {
|
||||
// float --> need special handling like below.
|
||||
// 0 4
|
||||
// +------+------+
|
||||
// | empty| float|
|
||||
// +------+------+
|
||||
// Increment the pointer, VAList, by 8 to the next vaarg.
|
||||
NextPtr =
|
||||
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getIntPtrConstant(8, DL));
|
||||
// Then, adjust VAList.
|
||||
unsigned InternalOffset = 4;
|
||||
VAList = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
|
||||
DAG.getConstant(InternalOffset, DL, PtrVT));
|
||||
} else {
|
||||
// Increment the pointer, VAList, by 8 to the next vaarg.
|
||||
NextPtr =
|
||||
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getIntPtrConstant(8, DL));
|
||||
}
|
||||
|
||||
// Store the incremented VAList to the legalized pointer.
|
||||
InChain = DAG.getStore(Chain, DL, NextPtr, VAListPtr, MachinePointerInfo(SV));
|
||||
|
||||
// Load the actual argument out of the pointer VAList.
|
||||
// We can't count on greater alignment than the word size.
|
||||
return DAG.getLoad(VT, DL, InChain, VAList, MachinePointerInfo(),
|
||||
std::min(PtrVT.getSizeInBits(), VT.getSizeInBits()) / 8);
|
||||
}
|
||||
|
||||
SDValue VETargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
switch (Op.getOpcode()) {
|
||||
default:
|
||||
@ -612,6 +706,10 @@ SDValue VETargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
return LowerBlockAddress(Op, DAG);
|
||||
case ISD::GlobalAddress:
|
||||
return LowerGlobalAddress(Op, DAG);
|
||||
case ISD::VASTART:
|
||||
return LowerVASTART(Op, DAG);
|
||||
case ISD::VAARG:
|
||||
return LowerVAARG(Op, DAG);
|
||||
}
|
||||
}
|
||||
/// } Custom Lower
|
||||
|
@ -71,6 +71,8 @@ public:
|
||||
/// Custom Lower {
|
||||
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
|
||||
|
||||
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
/// } Custom Lower
|
||||
|
@ -296,6 +296,114 @@ void VEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
||||
}
|
||||
}
|
||||
|
||||
/// isLoadFromStackSlot - If the specified machine instruction is a direct
|
||||
/// load from a stack slot, return the virtual or physical register number of
|
||||
/// the destination along with the FrameIndex of the loaded stack slot. If
|
||||
/// not, return 0. This predicate must return 0 if the instruction has
|
||||
/// any side effects other than loading from the stack slot.
|
||||
unsigned VEInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
|
||||
int &FrameIndex) const {
|
||||
if (MI.getOpcode() == VE::LDSri || MI.getOpcode() == VE::LDLri ||
|
||||
MI.getOpcode() == VE::LDUri) {
|
||||
if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
|
||||
MI.getOperand(2).getImm() == 0) {
|
||||
FrameIndex = MI.getOperand(1).getIndex();
|
||||
return MI.getOperand(0).getReg();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// isStoreToStackSlot - If the specified machine instruction is a direct
|
||||
/// store to a stack slot, return the virtual or physical register number of
|
||||
/// the source reg along with the FrameIndex of the loaded stack slot. If
|
||||
/// not, return 0. This predicate must return 0 if the instruction has
|
||||
/// any side effects other than storing to the stack slot.
|
||||
unsigned VEInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
|
||||
int &FrameIndex) const {
|
||||
if (MI.getOpcode() == VE::STSri || MI.getOpcode() == VE::STLri ||
|
||||
MI.getOpcode() == VE::STUri) {
|
||||
if (MI.getOperand(0).isFI() && MI.getOperand(1).isImm() &&
|
||||
MI.getOperand(1).getImm() == 0) {
|
||||
FrameIndex = MI.getOperand(0).getIndex();
|
||||
return MI.getOperand(2).getReg();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VEInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
Register SrcReg, bool isKill, int FI,
|
||||
const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const {
|
||||
DebugLoc DL;
|
||||
if (I != MBB.end())
|
||||
DL = I->getDebugLoc();
|
||||
|
||||
MachineFunction *MF = MBB.getParent();
|
||||
const MachineFrameInfo &MFI = MF->getFrameInfo();
|
||||
MachineMemOperand *MMO = MF->getMachineMemOperand(
|
||||
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,
|
||||
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
|
||||
|
||||
// On the order of operands here: think "[FrameIdx + 0] = SrcReg".
|
||||
if (RC == &VE::I64RegClass) {
|
||||
BuildMI(MBB, I, DL, get(VE::STSri))
|
||||
.addFrameIndex(FI)
|
||||
.addImm(0)
|
||||
.addReg(SrcReg, getKillRegState(isKill))
|
||||
.addMemOperand(MMO);
|
||||
} else if (RC == &VE::I32RegClass) {
|
||||
BuildMI(MBB, I, DL, get(VE::STLri))
|
||||
.addFrameIndex(FI)
|
||||
.addImm(0)
|
||||
.addReg(SrcReg, getKillRegState(isKill))
|
||||
.addMemOperand(MMO);
|
||||
} else if (RC == &VE::F32RegClass) {
|
||||
BuildMI(MBB, I, DL, get(VE::STUri))
|
||||
.addFrameIndex(FI)
|
||||
.addImm(0)
|
||||
.addReg(SrcReg, getKillRegState(isKill))
|
||||
.addMemOperand(MMO);
|
||||
} else
|
||||
report_fatal_error("Can't store this register to stack slot");
|
||||
}
|
||||
|
||||
void VEInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
Register DestReg, int FI,
|
||||
const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const {
|
||||
DebugLoc DL;
|
||||
if (I != MBB.end())
|
||||
DL = I->getDebugLoc();
|
||||
|
||||
MachineFunction *MF = MBB.getParent();
|
||||
const MachineFrameInfo &MFI = MF->getFrameInfo();
|
||||
MachineMemOperand *MMO = MF->getMachineMemOperand(
|
||||
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
|
||||
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
|
||||
|
||||
if (RC == &VE::I64RegClass) {
|
||||
BuildMI(MBB, I, DL, get(VE::LDSri), DestReg)
|
||||
.addFrameIndex(FI)
|
||||
.addImm(0)
|
||||
.addMemOperand(MMO);
|
||||
} else if (RC == &VE::I32RegClass) {
|
||||
BuildMI(MBB, I, DL, get(VE::LDLri), DestReg)
|
||||
.addFrameIndex(FI)
|
||||
.addImm(0)
|
||||
.addMemOperand(MMO);
|
||||
} else if (RC == &VE::F32RegClass) {
|
||||
BuildMI(MBB, I, DL, get(VE::LDUri), DestReg)
|
||||
.addFrameIndex(FI)
|
||||
.addImm(0)
|
||||
.addMemOperand(MMO);
|
||||
} else
|
||||
report_fatal_error("Can't load this register from stack slot");
|
||||
}
|
||||
|
||||
bool VEInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
||||
switch (MI.getOpcode()) {
|
||||
case VE::EXTEND_STACK: {
|
||||
|
@ -59,6 +59,23 @@ public:
|
||||
const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
|
||||
bool KillSrc) const override;
|
||||
|
||||
/// Stack Spill & Reload {
|
||||
unsigned isLoadFromStackSlot(const MachineInstr &MI,
|
||||
int &FrameIndex) const override;
|
||||
unsigned isStoreToStackSlot(const MachineInstr &MI,
|
||||
int &FrameIndex) const override;
|
||||
void storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI, Register SrcReg,
|
||||
bool isKill, int FrameIndex,
|
||||
const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
|
||||
void loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI, Register DestReg,
|
||||
int FrameIndex, const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
/// } Stack Spill & Reload
|
||||
|
||||
// Lower pseudo instructions after register allocation.
|
||||
bool expandPostRAPseudo(MachineInstr &MI) const override;
|
||||
|
||||
|
@ -20,12 +20,19 @@ class VEMachineFunctionInfo : public MachineFunctionInfo {
|
||||
virtual void anchor();
|
||||
|
||||
private:
|
||||
/// VarArgsFrameOffset - Frame offset to start of varargs area.
|
||||
int VarArgsFrameOffset;
|
||||
|
||||
/// IsLeafProc - True if the function is a leaf procedure.
|
||||
bool IsLeafProc;
|
||||
|
||||
public:
|
||||
VEMachineFunctionInfo() : IsLeafProc(false) {}
|
||||
explicit VEMachineFunctionInfo(MachineFunction &MF) : IsLeafProc(false) {}
|
||||
VEMachineFunctionInfo() : VarArgsFrameOffset(0), IsLeafProc(false) {}
|
||||
explicit VEMachineFunctionInfo(MachineFunction &MF)
|
||||
: VarArgsFrameOffset(0), IsLeafProc(false) {}
|
||||
|
||||
int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
|
||||
void setVarArgsFrameOffset(int Offset) { VarArgsFrameOffset = Offset; }
|
||||
|
||||
void setLeafProc(bool rhs) { IsLeafProc = rhs; }
|
||||
bool isLeafProc() const { return IsLeafProc; }
|
||||
|
63
test/CodeGen/VE/va_arg.ll
Normal file
63
test/CodeGen/VE/va_arg.ll
Normal file
@ -0,0 +1,63 @@
|
||||
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
|
||||
|
||||
@.str = private unnamed_addr constant [6 x i8] c"a=%d\0A\00", align 1
|
||||
@.str.1 = private unnamed_addr constant [6 x i8] c"b=%d\0A\00", align 1
|
||||
@.str.2 = private unnamed_addr constant [6 x i8] c"c=%d\0A\00", align 1
|
||||
@.str.3 = private unnamed_addr constant [6 x i8] c"d=%u\0A\00", align 1
|
||||
@.str.4 = private unnamed_addr constant [6 x i8] c"e=%u\0A\00", align 1
|
||||
@.str.5 = private unnamed_addr constant [6 x i8] c"f=%u\0A\00", align 1
|
||||
@.str.6 = private unnamed_addr constant [6 x i8] c"g=%f\0A\00", align 1
|
||||
@.str.7 = private unnamed_addr constant [6 x i8] c"h=%p\0A\00", align 1
|
||||
@.str.8 = private unnamed_addr constant [7 x i8] c"i=%ld\0A\00", align 1
|
||||
@.str.9 = private unnamed_addr constant [7 x i8] c"j=%lf\0A\00", align 1
|
||||
|
||||
define i32 @func_vainout(i32, ...) {
|
||||
; CHECK-LABEL: func_vainout:
|
||||
; CHECK: ldl.sx %s1, 184(,%s9)
|
||||
; CHECK: ld2b.sx %s18, 192(,%s9)
|
||||
; CHECK: ld1b.sx %s19, 200(,%s9)
|
||||
; CHECK: ldl.sx %s20, 208(,%s9)
|
||||
; CHECK: ld2b.zx %s21, 216(,%s9)
|
||||
; CHECK: ld1b.zx %s22, 224(,%s9)
|
||||
; CHECK: ldu %s23, 236(,%s9)
|
||||
; CHECK: ld %s24, 240(,%s9)
|
||||
; CHECK: ld %s25, 248(,%s9)
|
||||
; CHECK: ld %s26, 256(,%s9)
|
||||
|
||||
%a = alloca i8*, align 8
|
||||
%a8 = bitcast i8** %a to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %a8)
|
||||
call void @llvm.va_start(i8* nonnull %a8)
|
||||
%p0 = va_arg i8** %a, i32
|
||||
%p1 = va_arg i8** %a, i16
|
||||
%p2 = va_arg i8** %a, i8
|
||||
%p3 = va_arg i8** %a, i32
|
||||
%p4 = va_arg i8** %a, i16
|
||||
%p5 = va_arg i8** %a, i8
|
||||
%p6 = va_arg i8** %a, float
|
||||
%p7 = va_arg i8** %a, i8*
|
||||
%p8 = va_arg i8** %a, i64
|
||||
%p9 = va_arg i8** %a, double
|
||||
call void @llvm.va_end(i8* nonnull %a8)
|
||||
call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %a8)
|
||||
%pf0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0), i32 %p0)
|
||||
%p1.s32 = sext i16 %p1 to i32
|
||||
%pf1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i64 0, i64 0), i32 %p1.s32)
|
||||
%p2.s32 = sext i8 %p2 to i32
|
||||
%pf2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i64 0, i64 0), i32 %p2.s32)
|
||||
%pf3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.3, i64 0, i64 0), i32 %p3)
|
||||
%p4.z32 = zext i16 %p4 to i32
|
||||
%pf4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.4, i64 0, i64 0), i32 %p4.z32)
|
||||
%p5.z32 = zext i8 %p5 to i32
|
||||
%pf5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.5, i64 0, i64 0), i32 %p5.z32)
|
||||
%pf6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.6, i64 0, i64 0), float %p6)
|
||||
%pf7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.7, i64 0, i64 0), i8* %p7)
|
||||
%pf8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.8, i64 0, i64 0), i64 %p8)
|
||||
%pf9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.9, i64 0, i64 0), double %p9)
|
||||
ret i32 0
|
||||
}
|
||||
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
|
||||
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
|
||||
declare void @llvm.va_start(i8*)
|
||||
declare void @llvm.va_end(i8*)
|
||||
declare i32 @printf(i8* nocapture readonly, ...)
|
152
test/CodeGen/VE/va_callee.ll
Normal file
152
test/CodeGen/VE/va_callee.ll
Normal file
@ -0,0 +1,152 @@
|
||||
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
|
||||
|
||||
define i32 @va_func(i32, ...) {
|
||||
; CHECK-LABEL: va_func:
|
||||
; CHECK: ldl.sx %s0, 184(,%s9)
|
||||
; CHECK: ld2b.sx %s18, 192(,%s9)
|
||||
; CHECK: ld1b.sx %s19, 200(,%s9)
|
||||
; CHECK: ldl.sx %s20, 208(,%s9)
|
||||
; CHECK: ld2b.zx %s21, 216(,%s9)
|
||||
; CHECK: ld1b.zx %s22, 224(,%s9)
|
||||
; CHECK: ldu %s23, 236(,%s9)
|
||||
; CHECK: ld %s24, 240(,%s9)
|
||||
; CHECK: ld %s25, 248(,%s9)
|
||||
|
||||
%va = alloca i8*, align 8
|
||||
%va.i8 = bitcast i8** %va to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
call void @llvm.va_start(i8* nonnull %va.i8)
|
||||
%p1 = va_arg i8** %va, i32
|
||||
%p2 = va_arg i8** %va, i16
|
||||
%p3 = va_arg i8** %va, i8
|
||||
%p4 = va_arg i8** %va, i32
|
||||
%p5 = va_arg i8** %va, i16
|
||||
%p6 = va_arg i8** %va, i8
|
||||
%p7 = va_arg i8** %va, float
|
||||
%p8 = va_arg i8** %va, i8*
|
||||
%p9 = va_arg i8** %va, i64
|
||||
%p10 = va_arg i8** %va, double
|
||||
call void @llvm.va_end(i8* nonnull %va.i8)
|
||||
call void @use_i32(i32 %p1)
|
||||
call void @use_s16(i16 %p2)
|
||||
call void @use_s8(i8 %p3)
|
||||
call void @use_i32(i32 %p4)
|
||||
call void @use_u16(i16 %p5)
|
||||
call void @use_u8(i8 %p6)
|
||||
call void @use_float(float %p7)
|
||||
call void @use_i8p(i8* %p8)
|
||||
call void @use_i64(i64 %p9)
|
||||
call void @use_double(double %p10)
|
||||
call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @va_copy0(i32, ...) {
|
||||
; CHECK-LABEL: va_copy0:
|
||||
; CHECK: ldl.sx %s0,
|
||||
; CHECK: ld2b.sx %s18,
|
||||
; CHECK: ld1b.sx %s19,
|
||||
; CHECK: ldl.sx %s20,
|
||||
; CHECK: ld2b.zx %s21,
|
||||
; CHECK: ld1b.zx %s22,
|
||||
; CHECK: ldu %s23,
|
||||
; CHECK: ld %s24,
|
||||
; CHECK: ld %s25,
|
||||
|
||||
%va = alloca i8*, align 8
|
||||
%va.i8 = bitcast i8** %va to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
call void @llvm.va_start(i8* nonnull %va.i8)
|
||||
%vb = alloca i8*, align 8
|
||||
%vb.i8 = bitcast i8** %vb to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
call void @llvm.va_copy(i8* nonnull %vb.i8, i8* nonnull %va.i8)
|
||||
call void @llvm.va_end(i8* nonnull %va.i8)
|
||||
call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
%p1 = va_arg i8** %vb, i32
|
||||
%p2 = va_arg i8** %vb, i16
|
||||
%p3 = va_arg i8** %vb, i8
|
||||
%p4 = va_arg i8** %vb, i32
|
||||
%p5 = va_arg i8** %vb, i16
|
||||
%p6 = va_arg i8** %vb, i8
|
||||
%p7 = va_arg i8** %vb, float
|
||||
%p8 = va_arg i8** %vb, i8*
|
||||
%p9 = va_arg i8** %vb, i64
|
||||
%p10 = va_arg i8** %vb, double
|
||||
call void @llvm.va_end(i8* nonnull %vb.i8)
|
||||
call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %vb.i8)
|
||||
call void @use_i32(i32 %p1)
|
||||
call void @use_s16(i16 %p2)
|
||||
call void @use_s8(i8 %p3)
|
||||
call void @use_i32(i32 %p4)
|
||||
call void @use_u16(i16 %p5)
|
||||
call void @use_u8(i8 %p6)
|
||||
call void @use_float(float %p7)
|
||||
call void @use_i8p(i8* %p8)
|
||||
call void @use_i64(i64 %p9)
|
||||
call void @use_double(double %p10)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @va_copy8(i32, ...) {
|
||||
; CHECK-LABEL: va_copy8:
|
||||
; CHECK: ldl.sx %s0,
|
||||
; CHECK: ld2b.sx %s18,
|
||||
; CHECK: ld1b.sx %s19,
|
||||
; CHECK: ldl.sx %s20,
|
||||
; CHECK: ld2b.zx %s21,
|
||||
; CHECK: ld1b.zx %s22,
|
||||
; CHECK: ldu %s23,
|
||||
; CHECK: ld %s24,
|
||||
; CHECK: ld %s25,
|
||||
|
||||
%va = alloca i8*, align 8
|
||||
%va.i8 = bitcast i8** %va to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
call void @llvm.va_start(i8* nonnull %va.i8)
|
||||
%p1 = va_arg i8** %va, i32
|
||||
%p2 = va_arg i8** %va, i16
|
||||
%p3 = va_arg i8** %va, i8
|
||||
%p4 = va_arg i8** %va, i32
|
||||
%p5 = va_arg i8** %va, i16
|
||||
%p6 = va_arg i8** %va, i8
|
||||
%p7 = va_arg i8** %va, float
|
||||
|
||||
%vc = alloca i8*, align 8
|
||||
%vc.i8 = bitcast i8** %vc to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
call void @llvm.va_copy(i8* nonnull %vc.i8, i8* nonnull %va.i8)
|
||||
call void @llvm.va_end(i8* nonnull %va.i8)
|
||||
%p8 = va_arg i8** %vc, i8*
|
||||
%p9 = va_arg i8** %vc, i64
|
||||
%p10 = va_arg i8** %vc, double
|
||||
call void @llvm.va_end(i8* nonnull %vc.i8)
|
||||
call void @use_i32(i32 %p1)
|
||||
call void @use_s16(i16 %p2)
|
||||
call void @use_s8(i8 %p3)
|
||||
call void @use_i32(i32 %p4)
|
||||
call void @use_u16(i16 %p5)
|
||||
call void @use_u8(i8 %p6)
|
||||
call void @use_float(float %p7)
|
||||
call void @use_i8p(i8* %p8)
|
||||
call void @use_i64(i64 %p9)
|
||||
call void @use_double(double %p10)
|
||||
call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %va.i8)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare void @use_i64(i64)
|
||||
declare void @use_i32(i32)
|
||||
declare void @use_u16(i16 zeroext)
|
||||
declare void @use_u8(i8 zeroext)
|
||||
declare void @use_s16(i16 signext)
|
||||
declare void @use_s8(i8 signext)
|
||||
declare void @use_i8p(i8*)
|
||||
declare void @use_float(float)
|
||||
declare void @use_double(double)
|
||||
|
||||
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
|
||||
declare void @llvm.va_start(i8*)
|
||||
declare void @llvm.va_copy(i8*, i8*)
|
||||
declare void @llvm.va_end(i8*)
|
||||
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
|
47
test/CodeGen/VE/va_caller.ll
Normal file
47
test/CodeGen/VE/va_caller.ll
Normal file
@ -0,0 +1,47 @@
|
||||
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
|
||||
|
||||
declare i32 @func(i32, ...)
|
||||
|
||||
define i32 @caller() {
|
||||
; CHECK-LABEL: caller:
|
||||
; CHECK: .LBB{{[0-9]+}}_2:
|
||||
; CHECK-NEXT: st %s18, 48(,%s9) # 8-byte Folded Spill
|
||||
; CHECK-NEXT: or %s7, 0, (0)1
|
||||
; CHECK-NEXT: st %s7, 280(,%s11)
|
||||
; CHECK-NEXT: or %s0, 11, (0)1
|
||||
; CHECK-NEXT: st %s0, 272(,%s11)
|
||||
; CHECK-NEXT: st %s7, 264(,%s11)
|
||||
; CHECK-NEXT: or %s0, 10, (0)1
|
||||
; CHECK-NEXT: st %s0, 256(,%s11)
|
||||
; CHECK-NEXT: lea.sl %s0, 1075970048
|
||||
; CHECK-NEXT: st %s0, 248(,%s11)
|
||||
; CHECK-NEXT: or %s0, 8, (0)1
|
||||
; CHECK-NEXT: st %s0, 240(,%s11)
|
||||
; CHECK-NEXT: st %s7, 232(,%s11)
|
||||
; CHECK-NEXT: lea %s0, 1086324736
|
||||
; CHECK-NEXT: stl %s0, 228(,%s11)
|
||||
; CHECK-NEXT: or %s5, 5, (0)1
|
||||
; CHECK-NEXT: stl %s5, 216(,%s11)
|
||||
; CHECK-NEXT: or %s4, 4, (0)1
|
||||
; CHECK-NEXT: stl %s4, 208(,%s11)
|
||||
; CHECK-NEXT: or %s3, 3, (0)1
|
||||
; CHECK-NEXT: stl %s3, 200(,%s11)
|
||||
; CHECK-NEXT: or %s2, 2, (0)1
|
||||
; CHECK-NEXT: stl %s2, 192(,%s11)
|
||||
; CHECK-NEXT: or %s1, 1, (0)1
|
||||
; CHECK-NEXT: stl %s1, 184(,%s11)
|
||||
; CHECK-NEXT: or %s18, 0, (0)1
|
||||
; CHECK-NEXT: lea %s0, func@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, func@hi(%s0)
|
||||
; CHECK-NEXT: lea.sl %s0, 1086324736
|
||||
; CHECK-NEXT: stl %s18, 176(,%s11)
|
||||
; CHECK-NEXT: or %s6, 0, %s0
|
||||
; CHECK-NEXT: or %s0, 0, %s18
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: or %s0, 0, %s18
|
||||
; CHECK-NEXT: ld %s18, 48(,%s9) # 8-byte Folded Reload
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
call i32 (i32, ...) @func(i32 0, i16 1, i8 2, i32 3, i16 4, i8 5, float 6.0, i8* null, i64 8, double 9.0, i128 10, i128 11)
|
||||
ret i32 0
|
||||
}
|
Loading…
Reference in New Issue
Block a user