forked from OSchip/llvm-project
Improve varags handling, with testcases. Patch by Sasa Stankovic
llvm-svn: 127349
This commit is contained in:
parent
0f6d098bd1
commit
048ffabe78
|
@ -149,6 +149,10 @@ MipsTargetLowering(MipsTargetMachine &TM)
|
|||
|
||||
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
|
||||
|
||||
setOperationAction(ISD::VAARG, MVT::Other, Expand);
|
||||
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
||||
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
||||
|
||||
// Use the default for now
|
||||
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
||||
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
||||
|
@ -1283,7 +1287,6 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
|
||||
unsigned StackReg = MF.getTarget().getRegisterInfo()->getFrameRegister(MF);
|
||||
MipsFI->setVarArgsFrameIndex(0);
|
||||
|
||||
// Used with vargs to acumulate store chains.
|
||||
|
@ -1303,9 +1306,9 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||
else
|
||||
CCInfo.AnalyzeFormalArguments(Ins, CC_Mips);
|
||||
|
||||
SDValue StackPtr;
|
||||
|
||||
unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16);
|
||||
unsigned LastStackArgEndOffset;
|
||||
EVT LastRegArgValVT;
|
||||
|
||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||
CCValAssign &VA = ArgLocs[i];
|
||||
|
@ -1314,6 +1317,7 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||
if (VA.isRegLoc()) {
|
||||
EVT RegVT = VA.getLocVT();
|
||||
ArgRegEnd = VA.getLocReg();
|
||||
LastRegArgValVT = VA.getValVT();
|
||||
TargetRegisterClass *RC = 0;
|
||||
|
||||
if (RegVT == MVT::i32)
|
||||
|
@ -1354,7 +1358,8 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||
unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(),
|
||||
VA.getLocReg()+1, RC);
|
||||
SDValue ArgValue2 = DAG.getCopyFromReg(Chain, dl, Reg2, RegVT);
|
||||
SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, ArgValue2, ArgValue);
|
||||
SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, ArgValue,
|
||||
ArgValue2);
|
||||
ArgValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, Pair);
|
||||
}
|
||||
}
|
||||
|
@ -1375,10 +1380,10 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||
// used instead of a direct negative address (which is recorded to
|
||||
// be used on emitPrologue) to avoid mis-calc of the first stack
|
||||
// offset on PEI::calculateFrameObjectOffsets.
|
||||
// Arguments are always 32-bit.
|
||||
unsigned ArgSize = VA.getLocVT().getSizeInBits()/8;
|
||||
unsigned ArgSize = VA.getValVT().getSizeInBits()/8;
|
||||
LastStackArgEndOffset = FirstStackArgLoc + VA.getLocMemOffset() + ArgSize;
|
||||
int FI = MFI->CreateFixedObject(ArgSize, 0, true);
|
||||
MipsFI->recordLoadArgsFI(FI, -(ArgSize+
|
||||
MipsFI->recordLoadArgsFI(FI, -(4 +
|
||||
(FirstStackArgLoc + VA.getLocMemOffset())));
|
||||
|
||||
// Create load nodes to retrieve arguments from the stack
|
||||
|
@ -1405,29 +1410,52 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain,
|
|||
// To meet ABI, when VARARGS are passed on registers, the registers
|
||||
// must have their values written to the caller stack frame. If the last
|
||||
// argument was placed in the stack, there's no need to save any register.
|
||||
if ((isVarArg) && (Subtarget->isABI_O32() && ArgRegEnd)) {
|
||||
if (StackPtr.getNode() == 0)
|
||||
StackPtr = DAG.getRegister(StackReg, getPointerTy());
|
||||
if (isVarArg && Subtarget->isABI_O32()) {
|
||||
if (ArgRegEnd) {
|
||||
// Last named formal argument is passed in register.
|
||||
|
||||
// The last register argument that must be saved is Mips::A3
|
||||
TargetRegisterClass *RC = Mips::CPURegsRegisterClass;
|
||||
unsigned StackLoc = ArgLocs.size()-1;
|
||||
// The last register argument that must be saved is Mips::A3
|
||||
TargetRegisterClass *RC = Mips::CPURegsRegisterClass;
|
||||
if (LastRegArgValVT == MVT::f64)
|
||||
ArgRegEnd++;
|
||||
|
||||
for (++ArgRegEnd; ArgRegEnd <= Mips::A3; ++ArgRegEnd, ++StackLoc) {
|
||||
unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegEnd, RC);
|
||||
SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, MVT::i32);
|
||||
if (ArgRegEnd < Mips::A3) {
|
||||
// Both the last named formal argument and the first variable
|
||||
// argument are passed in registers.
|
||||
for (++ArgRegEnd; ArgRegEnd <= Mips::A3; ++ArgRegEnd) {
|
||||
unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegEnd, RC);
|
||||
SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, MVT::i32);
|
||||
|
||||
int FI = MFI->CreateFixedObject(4, 0, true);
|
||||
MipsFI->recordStoreVarArgsFI(FI, -(4+(StackLoc*4)));
|
||||
SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy());
|
||||
OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff,
|
||||
MachinePointerInfo(),
|
||||
false, false, 0));
|
||||
int FI = MFI->CreateFixedObject(4, 0, true);
|
||||
MipsFI->recordStoreVarArgsFI(FI, -(4+(ArgRegEnd-Mips::A0)*4));
|
||||
SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy());
|
||||
OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff,
|
||||
MachinePointerInfo(),
|
||||
false, false, 0));
|
||||
|
||||
// Record the frame index of the first variable argument
|
||||
// which is a value necessary to VASTART.
|
||||
if (!MipsFI->getVarArgsFrameIndex())
|
||||
// Record the frame index of the first variable argument
|
||||
// which is a value necessary to VASTART.
|
||||
if (!MipsFI->getVarArgsFrameIndex()) {
|
||||
MFI->setObjectAlignment(FI, 4);
|
||||
MipsFI->setVarArgsFrameIndex(FI);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Last named formal argument is in register Mips::A3, and the first
|
||||
// variable argument is on stack. Record the frame index of the first
|
||||
// variable argument.
|
||||
int FI = MFI->CreateFixedObject(4, 0, true);
|
||||
MFI->setObjectAlignment(FI, 4);
|
||||
MipsFI->recordStoreVarArgsFI(FI, -20);
|
||||
MipsFI->setVarArgsFrameIndex(FI);
|
||||
}
|
||||
} else {
|
||||
// Last named formal argument and all the variable arguments are passed
|
||||
// on stack. Record the frame index of the first variable argument.
|
||||
int FI = MFI->CreateFixedObject(4, 0, true);
|
||||
MFI->setObjectAlignment(FI, 4);
|
||||
MipsFI->recordStoreVarArgsFI(FI, -(4+LastStackArgEndOffset));
|
||||
MipsFI->setVarArgsFrameIndex(FI);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
; RUN: llc -march=mipsel -mcpu=mips2 < %s | FileCheck %s
|
||||
|
||||
|
||||
; All test functions do the same thing - they return the first variable
|
||||
; argument.
|
||||
|
||||
; All CHECK's do the same thing - they check whether variable arguments from
|
||||
; registers are placed on correct stack locations, and whether the first
|
||||
; variable argument is returned from the correct stack location.
|
||||
|
||||
|
||||
declare void @llvm.va_start(i8*) nounwind
|
||||
declare void @llvm.va_end(i8*) nounwind
|
||||
|
||||
; return int
|
||||
define i32 @va1(i32 %a, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%ap = alloca i8*, align 4
|
||||
%b = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, i32
|
||||
store i32 %0, i32* %b, align 4
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load i32* %b, align 4
|
||||
ret i32 %tmp
|
||||
|
||||
; CHECK: va1:
|
||||
; CHECK: addiu $sp, $sp, -32
|
||||
; CHECK: sw $5, 36($sp)
|
||||
; CHECK: sw $6, 40($sp)
|
||||
; CHECK: sw $7, 44($sp)
|
||||
; CHECK: lw $2, 36($sp)
|
||||
}
|
||||
|
||||
; check whether the variable double argument will be accessed from the 8-byte
|
||||
; aligned location (i.e. whether the address is computed by adding 7 and
|
||||
; clearing lower 3 bits)
|
||||
define double @va2(i32 %a, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%ap = alloca i8*, align 4
|
||||
%b = alloca double, align 8
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, double
|
||||
store double %0, double* %b, align 8
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load double* %b, align 8
|
||||
ret double %tmp
|
||||
|
||||
; CHECK: va2:
|
||||
; CHECK: addiu $sp, $sp, -40
|
||||
; CHECK: addiu $2, $sp, 44
|
||||
; CHECK: sw $5, 44($sp)
|
||||
; CHECK: sw $6, 48($sp)
|
||||
; CHECK: sw $7, 52($sp)
|
||||
; CHECK: addiu $3, $2, 7
|
||||
; CHECK: addiu $5, $zero, -8
|
||||
; CHECK: and $3, $3, $5
|
||||
; CHECK: ldc1 $f0, 0($3)
|
||||
}
|
||||
|
||||
; int
|
||||
define i32 @va3(double %a, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca double, align 8
|
||||
%ap = alloca i8*, align 4
|
||||
%b = alloca i32, align 4
|
||||
store double %a, double* %a.addr, align 8
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, i32
|
||||
store i32 %0, i32* %b, align 4
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load i32* %b, align 4
|
||||
ret i32 %tmp
|
||||
|
||||
; CHECK: va3:
|
||||
; CHECK: addiu $sp, $sp, -40
|
||||
; CHECK: sw $6, 48($sp)
|
||||
; CHECK: sw $7, 52($sp)
|
||||
; CHECK: lw $2, 48($sp)
|
||||
}
|
||||
|
||||
; double
|
||||
define double @va4(double %a, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca double, align 8
|
||||
%ap = alloca i8*, align 4
|
||||
%b = alloca double, align 8
|
||||
store double %a, double* %a.addr, align 8
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, double
|
||||
store double %0, double* %b, align 8
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load double* %b, align 8
|
||||
ret double %tmp
|
||||
|
||||
; CHECK: va4:
|
||||
; CHECK: addiu $sp, $sp, -48
|
||||
; CHECK: sw $6, 56($sp)
|
||||
; CHECK: sw $7, 60($sp)
|
||||
; CHECK: addiu $3, $sp, 56
|
||||
; CHECK: addiu $6, $3, 7
|
||||
; CHECK: addiu $7, $zero, -8
|
||||
; CHECK: and $2, $6, $7
|
||||
; CHECK: ldc1 $f0, 0($2)
|
||||
}
|
||||
|
||||
; int
|
||||
define i32 @va5(i32 %a, i32 %b, i32 %c, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca i32, align 4
|
||||
%c.addr = alloca i32, align 4
|
||||
%ap = alloca i8*, align 4
|
||||
%d = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store i32 %b, i32* %b.addr, align 4
|
||||
store i32 %c, i32* %c.addr, align 4
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, i32
|
||||
store i32 %0, i32* %d, align 4
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load i32* %d, align 4
|
||||
ret i32 %tmp
|
||||
|
||||
; CHECK: va5:
|
||||
; CHECK: addiu $sp, $sp, -40
|
||||
; CHECK: sw $7, 52($sp)
|
||||
; CHECK: lw $2, 52($sp)
|
||||
}
|
||||
|
||||
; double
|
||||
define double @va6(i32 %a, i32 %b, i32 %c, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca i32, align 4
|
||||
%c.addr = alloca i32, align 4
|
||||
%ap = alloca i8*, align 4
|
||||
%d = alloca double, align 8
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store i32 %b, i32* %b.addr, align 4
|
||||
store i32 %c, i32* %c.addr, align 4
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, double
|
||||
store double %0, double* %d, align 8
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load double* %d, align 8
|
||||
ret double %tmp
|
||||
|
||||
; CHECK: va6:
|
||||
; CHECK: addiu $sp, $sp, -48
|
||||
; CHECK: sw $7, 60($sp)
|
||||
; CHECK: addiu $2, $sp, 60
|
||||
; CHECK: addiu $3, $2, 7
|
||||
; CHECK: addiu $4, $zero, -8
|
||||
; CHECK: and $3, $3, $4
|
||||
; CHECK: ldc1 $f0, 0($3)
|
||||
}
|
||||
|
||||
; int
|
||||
define i32 @va7(i32 %a, double %b, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca double, align 8
|
||||
%ap = alloca i8*, align 4
|
||||
%c = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store double %b, double* %b.addr, align 8
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, i32
|
||||
store i32 %0, i32* %c, align 4
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load i32* %c, align 4
|
||||
ret i32 %tmp
|
||||
|
||||
; CHECK: va7:
|
||||
; CHECK: addiu $sp, $sp, -40
|
||||
; CHECK: lw $2, 56($sp)
|
||||
}
|
||||
|
||||
; double
|
||||
define double @va8(i32 %a, double %b, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca double, align 8
|
||||
%ap = alloca i8*, align 4
|
||||
%c = alloca double, align 8
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store double %b, double* %b.addr, align 8
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, double
|
||||
store double %0, double* %c, align 8
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load double* %c, align 8
|
||||
ret double %tmp
|
||||
|
||||
; CHECK: va8:
|
||||
; CHECK: addiu $sp, $sp, -48
|
||||
; CHECK: addiu $3, $sp, 64
|
||||
; CHECK: addiu $4, $3, 7
|
||||
; CHECK: addiu $5, $zero, -8
|
||||
; CHECK: and $2, $4, $5
|
||||
; CHECK: ldc1 $f0, 0($2)
|
||||
}
|
||||
|
||||
; int
|
||||
define i32 @va9(double %a, double %b, i32 %c, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca double, align 8
|
||||
%b.addr = alloca double, align 8
|
||||
%c.addr = alloca i32, align 4
|
||||
%ap = alloca i8*, align 4
|
||||
%d = alloca i32, align 4
|
||||
store double %a, double* %a.addr, align 8
|
||||
store double %b, double* %b.addr, align 8
|
||||
store i32 %c, i32* %c.addr, align 4
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, i32
|
||||
store i32 %0, i32* %d, align 4
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load i32* %d, align 4
|
||||
ret i32 %tmp
|
||||
|
||||
; CHECK: va9:
|
||||
; CHECK: addiu $sp, $sp, -56
|
||||
; CHECK: lw $2, 76($sp)
|
||||
}
|
||||
|
||||
; double
|
||||
define double @va10(double %a, double %b, i32 %c, ...) nounwind {
|
||||
entry:
|
||||
%a.addr = alloca double, align 8
|
||||
%b.addr = alloca double, align 8
|
||||
%c.addr = alloca i32, align 4
|
||||
%ap = alloca i8*, align 4
|
||||
%d = alloca double, align 8
|
||||
store double %a, double* %a.addr, align 8
|
||||
store double %b, double* %b.addr, align 8
|
||||
store i32 %c, i32* %c.addr, align 4
|
||||
%ap1 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_start(i8* %ap1)
|
||||
%0 = va_arg i8** %ap, double
|
||||
store double %0, double* %d, align 8
|
||||
%ap2 = bitcast i8** %ap to i8*
|
||||
call void @llvm.va_end(i8* %ap2)
|
||||
%tmp = load double* %d, align 8
|
||||
ret double %tmp
|
||||
|
||||
; CHECK: va10:
|
||||
; CHECK: addiu $sp, $sp, -56
|
||||
; CHECK: addiu $3, $sp, 76
|
||||
; CHECK: addiu $2, $3, 7
|
||||
; CHECK: addiu $4, $zero, -8
|
||||
; CHECK: and $2, $2, $4
|
||||
; CHECK: ldc1 $f0, 0($2)
|
||||
}
|
Loading…
Reference in New Issue