Merged from r214493:

[mips][PR19612] Fix va_arg for big-endian mode.

Summary:
Big-endian mode was not correctly adjusting the offset for types smaller
than an ABI slot.

Fixes PR19612

Reviewers: dsanders

Reviewed By: dsanders

Subscribers: sstankovic, llvm-commits

Differential Revision: http://reviews.llvm.org/D4556



git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_35@223007 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Sanders 2014-12-01 11:22:34 +00:00
parent 9290cd66a8
commit ae5e83adbd
4 changed files with 1185 additions and 11 deletions

View File

@ -251,7 +251,6 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM,
setOperationAction(ISD::SETCC, MVT::f32, Custom); setOperationAction(ISD::SETCC, MVT::f32, Custom);
setOperationAction(ISD::SETCC, MVT::f64, Custom); setOperationAction(ISD::SETCC, MVT::f64, Custom);
setOperationAction(ISD::BRCOND, MVT::Other, Custom); setOperationAction(ISD::BRCOND, MVT::Other, Custom);
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom);
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom);
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
@ -343,7 +342,8 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM,
setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); setOperationAction(ISD::EH_RETURN, MVT::Other, Custom);
setOperationAction(ISD::VAARG, MVT::Other, Expand); setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAARG, MVT::Other, Custom);
setOperationAction(ISD::VACOPY, MVT::Other, Expand); setOperationAction(ISD::VACOPY, MVT::Other, Expand);
setOperationAction(ISD::VAEND, MVT::Other, Expand); setOperationAction(ISD::VAEND, MVT::Other, Expand);
@ -392,6 +392,11 @@ MipsTargetLowering::MipsTargetLowering(MipsTargetMachine &TM,
setMinFunctionAlignment(Subtarget.isGP64bit() ? 3 : 2); setMinFunctionAlignment(Subtarget.isGP64bit() ? 3 : 2);
// The arguments on the stack are defined in terms of 4-byte slots on O32
// and 8-byte slots on N32/N64.
setMinStackArgumentAlignment(
(Subtarget.isABI_N32() || Subtarget.isABI_N64()) ? 8 : 4);
setStackPointerRegisterToSaveRestore(Subtarget.isABI_N64() ? Mips::SP_64 setStackPointerRegisterToSaveRestore(Subtarget.isABI_N64() ? Mips::SP_64
: Mips::SP); : Mips::SP);
@ -792,6 +797,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
case ISD::SELECT_CC: return lowerSELECT_CC(Op, DAG); case ISD::SELECT_CC: return lowerSELECT_CC(Op, DAG);
case ISD::SETCC: return lowerSETCC(Op, DAG); case ISD::SETCC: return lowerSETCC(Op, DAG);
case ISD::VASTART: return lowerVASTART(Op, DAG); case ISD::VASTART: return lowerVASTART(Op, DAG);
case ISD::VAARG: return lowerVAARG(Op, DAG);
case ISD::FCOPYSIGN: return lowerFCOPYSIGN(Op, DAG); case ISD::FCOPYSIGN: return lowerFCOPYSIGN(Op, DAG);
case ISD::FRAMEADDR: return lowerFRAMEADDR(Op, DAG); case ISD::FRAMEADDR: return lowerFRAMEADDR(Op, DAG);
case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG); case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG);
@ -1755,6 +1761,65 @@ SDValue MipsTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const {
MachinePointerInfo(SV), false, false, 0); MachinePointerInfo(SV), false, false, 0);
} }
SDValue MipsTargetLowering::lowerVAARG(SDValue Op, SelectionDAG &DAG) const {
SDNode *Node = Op.getNode();
EVT VT = Node->getValueType(0);
SDValue Chain = Node->getOperand(0);
SDValue VAListPtr = Node->getOperand(1);
unsigned Align = Node->getConstantOperandVal(3);
const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
SDLoc DL(Node);
unsigned ArgSlotSizeInBytes =
(Subtarget.isABI_N32() || Subtarget.isABI_N64()) ? 8 : 4;
SDValue VAListLoad = DAG.getLoad(getPointerTy(), DL, Chain, VAListPtr,
MachinePointerInfo(SV), false, false, false,
0);
SDValue VAList = VAListLoad;
// Re-align the pointer if necessary.
// It should only ever be necessary for 64-bit types on O32 since the minimum
// argument alignment is the same as the maximum type alignment for N32/N64.
//
// FIXME: We currently align too often. The code generator doesn't notice
// when the pointer is still aligned from the last va_arg (or pair of
// va_args for the i64 on O32 case).
if (Align > getMinStackArgumentAlignment()) {
assert(((Align & (Align-1)) == 0) && "Expected Align to be a power of 2");
VAList = DAG.getNode(ISD::ADD, DL, VAList.getValueType(), VAList,
DAG.getConstant(Align - 1,
VAList.getValueType()));
VAList = DAG.getNode(ISD::AND, DL, VAList.getValueType(), VAList,
DAG.getConstant(-(int64_t)Align,
VAList.getValueType()));
}
// Increment the pointer, VAList, to the next vaarg.
unsigned ArgSizeInBytes = getDataLayout()->getTypeAllocSize(VT.getTypeForEVT(*DAG.getContext()));
SDValue Tmp3 = DAG.getNode(ISD::ADD, DL, VAList.getValueType(), VAList,
DAG.getConstant(RoundUpToAlignment(ArgSizeInBytes, ArgSlotSizeInBytes),
VAList.getValueType()));
// Store the incremented VAList to the legalized pointer
Chain = DAG.getStore(VAListLoad.getValue(1), DL, Tmp3, VAListPtr,
MachinePointerInfo(SV), false, false, 0);
// In big-endian mode we must adjust the pointer when the load size is smaller
// than the argument slot size. We must also reduce the known alignment to
// match. For example in the N64 ABI, we must add 4 bytes to the offset to get
// the correct half of the slot, and reduce the alignment from 8 (slot
// alignment) down to 4 (type alignment).
if (!Subtarget.isLittle() && ArgSizeInBytes < ArgSlotSizeInBytes) {
unsigned Adjustment = ArgSlotSizeInBytes - ArgSizeInBytes;
VAList = DAG.getNode(ISD::ADD, DL, VAListPtr.getValueType(), VAList,
DAG.getIntPtrConstant(Adjustment));
}
// Load the actual argument out of the pointer VAList
return DAG.getLoad(VT, DL, Chain, VAList, MachinePointerInfo(), false, false,
false, 0);
}
static SDValue lowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG, static SDValue lowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG,
bool HasExtractInsert) { bool HasExtractInsert) {
EVT TyX = Op.getOperand(0).getValueType(); EVT TyX = Op.getOperand(0).getValueType();

View File

@ -482,6 +482,7 @@ namespace llvm {
SDValue lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerSETCC(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSETCC(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerVAARG(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFABS(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFABS(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;

View File

@ -4,11 +4,11 @@
; RUN-TODO: llc -march=mips64 -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s ; RUN-TODO: llc -march=mips64 -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
; RUN-TODO: llc -march=mips64el -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s ; RUN-TODO: llc -march=mips64el -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=N32 --check-prefix=NEW %s ; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=N32 --check-prefix=NEW --check-prefix=NEWBE %s
; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=N32 --check-prefix=NEW %s ; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=N32 --check-prefix=NEW --check-prefix=NEWLE %s
; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=N64 --check-prefix=NEW %s ; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=N64 --check-prefix=NEW --check-prefix=NEWBE %s
; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=N64 --check-prefix=NEW %s ; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=N64 --check-prefix=NEW --check-prefix=NEWLE %s
; Test the effect of varargs on floating point types in the non-variable part ; Test the effect of varargs on floating point types in the non-variable part
; of the argument list as specified by section 2 of the MIPSpro N32 Handbook. ; of the argument list as specified by section 2 of the MIPSpro N32 Handbook.
@ -34,6 +34,7 @@ entry:
%b = va_arg i8** %ap, double %b = va_arg i8** %ap, double
%1 = getelementptr [11 x double]* @doubles, i32 0, i32 2 %1 = getelementptr [11 x double]* @doubles, i32 0, i32 2
store volatile double %b, double* %1 store volatile double %b, double* %1
call void @llvm.va_end(i8* %ap2)
ret void ret void
} }
@ -98,6 +99,7 @@ entry:
%b = va_arg i8** %ap, float %b = va_arg i8** %ap, float
%1 = getelementptr [11 x float]* @floats, i32 0, i32 2 %1 = getelementptr [11 x float]* @floats, i32 0, i32 2
store volatile float %b, float* %1 store volatile float %b, float* %1
call void @llvm.va_end(i8* %ap2)
ret void ret void
} }
@ -140,16 +142,18 @@ entry:
; Increment the pointer then get the varargs arg ; Increment the pointer then get the varargs arg
; LLVM will rebind the load to the stack pointer instead of the varargs pointer ; LLVM will rebind the load to the stack pointer instead of the varargs pointer
; during lowering. This is fine and doesn't change the behaviour. ; during lowering. This is fine and doesn't change the behaviour.
; N32/N64 is using ori instead of addiu/daddiu but (although odd) this is fine ; Also, in big-endian mode the offset must be increased by 4 to retrieve the
; since the stack is always aligned. ; correct half of the argument slot.
;
; O32-DAG: addiu [[VAPTR]], [[VAPTR]], 4 ; O32-DAG: addiu [[VAPTR]], [[VAPTR]], 4
; O32-DAG: sw [[VAPTR]], 4($sp) ; O32-DAG: sw [[VAPTR]], 4($sp)
; N32-DAG: ori [[VAPTR]], [[VAPTR]], 4 ; N32-DAG: addiu [[VAPTR]], [[VAPTR]], 8
; N32-DAG: sw [[VAPTR]], 4($sp) ; N32-DAG: sw [[VAPTR]], 4($sp)
; N64-DAG: ori [[VAPTR]], [[VAPTR]], 4 ; N64-DAG: daddiu [[VAPTR]], [[VAPTR]], 8
; N64-DAG: sd [[VAPTR]], 0($sp) ; N64-DAG: sd [[VAPTR]], 0($sp)
; O32-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 12($sp) ; O32-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 12($sp)
; NEW-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 8($sp) ; NEWLE-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 8($sp)
; NEWBE-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 12($sp)
; ALL-DAG: swc1 [[FTMP1]], 8([[R2]]) ; ALL-DAG: swc1 [[FTMP1]], 8([[R2]])
declare void @llvm.va_start(i8*) declare void @llvm.va_start(i8*)

File diff suppressed because it is too large Load Diff