mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
Small structs for PPC64 SVR4 must be passed right-justified in registers.
lib/Target/PowerPC/PPCISelLowering.{h,cpp} Rename LowerFormalArguments_Darwin to LowerFormalArguments_Darwin_Or_64SVR4. Rename LowerFormalArguments_SVR4 to LowerFormalArguments_32SVR4. Receive small structs right-justified in LowerFormalArguments_Darwin_Or_64SVR4. Rename LowerCall_Darwin to LowerCall_Darwin_Or_64SVR4. Rename LowerCall_SVR4 to LowerCall_32SVR4. Pass small structs right-justified in LowerCall_Darwin_Or_64SVR4. test/CodeGen/PowerPC/structsinregs.ll New test. llvm-svn: 164228
This commit is contained in:
parent
d260d5d0b8
commit
4e7e64ff70
@ -1717,16 +1717,16 @@ PPCTargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
SmallVectorImpl<SDValue> &InVals)
|
||||
const {
|
||||
if (PPCSubTarget.isSVR4ABI() && !PPCSubTarget.isPPC64()) {
|
||||
return LowerFormalArguments_SVR4(Chain, CallConv, isVarArg, Ins,
|
||||
dl, DAG, InVals);
|
||||
} else {
|
||||
return LowerFormalArguments_Darwin(Chain, CallConv, isVarArg, Ins,
|
||||
return LowerFormalArguments_32SVR4(Chain, CallConv, isVarArg, Ins,
|
||||
dl, DAG, InVals);
|
||||
} else {
|
||||
return LowerFormalArguments_Darwin_Or_64SVR4(Chain, CallConv, isVarArg, Ins,
|
||||
dl, DAG, InVals);
|
||||
}
|
||||
}
|
||||
|
||||
SDValue
|
||||
PPCTargetLowering::LowerFormalArguments_SVR4(
|
||||
PPCTargetLowering::LowerFormalArguments_32SVR4(
|
||||
SDValue Chain,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg>
|
||||
@ -1944,7 +1944,7 @@ PPCTargetLowering::LowerFormalArguments_SVR4(
|
||||
}
|
||||
|
||||
SDValue
|
||||
PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
PPCTargetLowering::LowerFormalArguments_Darwin_Or_64SVR4(
|
||||
SDValue Chain,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg>
|
||||
@ -1959,6 +1959,7 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
|
||||
EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
|
||||
bool isPPC64 = PtrVT == MVT::i64;
|
||||
bool isSVR4ABI = PPCSubTarget.isSVR4ABI();
|
||||
// Potential tail calls could cause overwriting of argument stack slots.
|
||||
bool isImmutable = !(getTargetMachine().Options.GuaranteedTailCallOpt &&
|
||||
(CallConv == CallingConv::Fast));
|
||||
@ -2019,10 +2020,12 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
default: llvm_unreachable("Unhandled argument type!");
|
||||
case MVT::i32:
|
||||
case MVT::f32:
|
||||
VecArgOffset += isPPC64 ? 8 : 4;
|
||||
VecArgOffset += 4;
|
||||
break;
|
||||
case MVT::i64: // PPC64
|
||||
case MVT::f64:
|
||||
// FIXME: We are guaranteed to be !isPPC64 at this point.
|
||||
// Does MVT::i64 apply?
|
||||
VecArgOffset += 8;
|
||||
break;
|
||||
case MVT::v4f32:
|
||||
@ -2076,8 +2079,11 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
// ObjSize is the true size, ArgSize rounded up to multiple of registers.
|
||||
ObjSize = Flags.getByValSize();
|
||||
ArgSize = ((ObjSize + PtrByteSize - 1)/PtrByteSize) * PtrByteSize;
|
||||
// Objects of size 1 and 2 are right justified, everything else is
|
||||
// left justified. This means the memory address is adjusted forwards.
|
||||
// FOR DARWIN: Objects of size 1 and 2 are right justified, everything
|
||||
// else is left justified. This means the memory address is adjusted
|
||||
// forwards.
|
||||
// FOR 64-BIT SVR4: All aggregates smaller than 8 bytes must be passed
|
||||
// right-justified.
|
||||
if (ObjSize==1 || ObjSize==2) {
|
||||
CurArgOffset = CurArgOffset + (4 - ObjSize);
|
||||
}
|
||||
@ -2085,7 +2091,8 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
int FI = MFI->CreateFixedObject(ObjSize, CurArgOffset, true);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
|
||||
InVals.push_back(FIN);
|
||||
if (ObjSize==1 || ObjSize==2) {
|
||||
if (ObjSize==1 || ObjSize==2 ||
|
||||
(ObjSize==4 && isSVR4ABI)) {
|
||||
if (GPR_idx != Num_GPR_Regs) {
|
||||
unsigned VReg;
|
||||
if (isPPC64)
|
||||
@ -2093,10 +2100,11 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
else
|
||||
VReg = MF.addLiveIn(GPR[GPR_idx], &PPC::GPRCRegClass);
|
||||
SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT);
|
||||
EVT ObjType = (ObjSize == 1 ? MVT::i8 :
|
||||
(ObjSize == 2 ? MVT::i16 : MVT::i32));
|
||||
SDValue Store = DAG.getTruncStore(Val.getValue(1), dl, Val, FIN,
|
||||
MachinePointerInfo(),
|
||||
ObjSize==1 ? MVT::i8 : MVT::i16,
|
||||
false, false, 0);
|
||||
ObjType, false, false, 0);
|
||||
MemOps.push_back(Store);
|
||||
++GPR_idx;
|
||||
}
|
||||
@ -2107,8 +2115,8 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
}
|
||||
for (unsigned j = 0; j < ArgSize; j += PtrByteSize) {
|
||||
// Store whatever pieces of the object are in registers
|
||||
// to memory. ArgVal will be address of the beginning of
|
||||
// the object.
|
||||
// to memory. ArgOffset will be the address of the beginning
|
||||
// of the object.
|
||||
if (GPR_idx != Num_GPR_Regs) {
|
||||
unsigned VReg;
|
||||
if (isPPC64)
|
||||
@ -2118,7 +2126,16 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
int FI = MFI->CreateFixedObject(PtrByteSize, ArgOffset, true);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
|
||||
SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT);
|
||||
SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, FIN,
|
||||
SDValue Shifted = Val;
|
||||
|
||||
// For 64-bit SVR4, small structs come in right-adjusted.
|
||||
// Shift them left so the following logic works as expected.
|
||||
if (ObjSize < 8 && isSVR4ABI) {
|
||||
SDValue ShiftAmt = DAG.getConstant(64 - 8 * ObjSize, PtrVT);
|
||||
Shifted = DAG.getNode(ISD::SHL, dl, PtrVT, Val, ShiftAmt);
|
||||
}
|
||||
|
||||
SDValue Store = DAG.getStore(Val.getValue(1), dl, Shifted, FIN,
|
||||
MachinePointerInfo(),
|
||||
false, false, 0);
|
||||
MemOps.push_back(Store);
|
||||
@ -2308,8 +2325,8 @@ PPCTargetLowering::LowerFormalArguments_Darwin(
|
||||
return Chain;
|
||||
}
|
||||
|
||||
/// CalculateParameterAndLinkageAreaSize - Get the size of the paramter plus
|
||||
/// linkage area for the Darwin ABI.
|
||||
/// CalculateParameterAndLinkageAreaSize - Get the size of the parameter plus
|
||||
/// linkage area for the Darwin ABI, or the 64-bit SVR4 ABI.
|
||||
static unsigned
|
||||
CalculateParameterAndLinkageAreaSize(SelectionDAG &DAG,
|
||||
bool isPPC64,
|
||||
@ -2718,7 +2735,7 @@ unsigned PrepareCall(SelectionDAG &DAG, SDValue &Callee, SDValue &InFlag,
|
||||
// Thus for a call through a function pointer, the following actions need
|
||||
// to be performed:
|
||||
// 1. Save the TOC of the caller in the TOC save area of its stack
|
||||
// frame (this is done in LowerCall_Darwin()).
|
||||
// frame (this is done in LowerCall_Darwin_Or_64SVR4()).
|
||||
// 2. Load the address of the function entry point from the function
|
||||
// descriptor.
|
||||
// 3. Load the TOC of the callee from the function descriptor into r2.
|
||||
@ -2969,25 +2986,25 @@ PPCTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
Ins, DAG);
|
||||
|
||||
if (PPCSubTarget.isSVR4ABI() && !PPCSubTarget.isPPC64())
|
||||
return LowerCall_SVR4(Chain, Callee, CallConv, isVarArg,
|
||||
isTailCall, Outs, OutVals, Ins,
|
||||
dl, DAG, InVals);
|
||||
return LowerCall_32SVR4(Chain, Callee, CallConv, isVarArg,
|
||||
isTailCall, Outs, OutVals, Ins,
|
||||
dl, DAG, InVals);
|
||||
|
||||
return LowerCall_Darwin(Chain, Callee, CallConv, isVarArg,
|
||||
isTailCall, Outs, OutVals, Ins,
|
||||
dl, DAG, InVals);
|
||||
return LowerCall_Darwin_Or_64SVR4(Chain, Callee, CallConv, isVarArg,
|
||||
isTailCall, Outs, OutVals, Ins,
|
||||
dl, DAG, InVals);
|
||||
}
|
||||
|
||||
SDValue
|
||||
PPCTargetLowering::LowerCall_SVR4(SDValue Chain, SDValue Callee,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
bool isTailCall,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const {
|
||||
// See PPCTargetLowering::LowerFormalArguments_SVR4() for a description
|
||||
PPCTargetLowering::LowerCall_32SVR4(SDValue Chain, SDValue Callee,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
bool isTailCall,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const {
|
||||
// See PPCTargetLowering::LowerFormalArguments_32SVR4() for a description
|
||||
// of the 32-bit SVR4 ABI stack frame layout.
|
||||
|
||||
assert((CallConv == CallingConv::C ||
|
||||
@ -3192,7 +3209,7 @@ PPCTargetLowering::LowerCall_SVR4(SDValue Chain, SDValue Callee,
|
||||
}
|
||||
|
||||
SDValue
|
||||
PPCTargetLowering::LowerCall_Darwin(SDValue Chain, SDValue Callee,
|
||||
PPCTargetLowering::LowerCall_Darwin_Or_64SVR4(SDValue Chain, SDValue Callee,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
bool isTailCall,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
@ -3201,6 +3218,8 @@ PPCTargetLowering::LowerCall_Darwin(SDValue Chain, SDValue Callee,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const {
|
||||
|
||||
bool isSVR4ABI = PPCSubTarget.isSVR4ABI();
|
||||
|
||||
unsigned NumOps = Outs.size();
|
||||
|
||||
EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
|
||||
@ -3308,12 +3327,22 @@ PPCTargetLowering::LowerCall_Darwin(SDValue Chain, SDValue Callee,
|
||||
}
|
||||
|
||||
// FIXME memcpy is used way more than necessary. Correctness first.
|
||||
// Note: "by value" is code for passing a structure by value, not
|
||||
// basic types.
|
||||
if (Flags.isByVal()) {
|
||||
// Note: Size includes alignment padding, so
|
||||
// struct x { short a; char b; }
|
||||
// will have Size = 4. With #pragma pack(1), it will have Size = 3.
|
||||
// These are the proper values we need for right-justifying the
|
||||
// aggregate in a parameter register for 64-bit SVR4.
|
||||
unsigned Size = Flags.getByValSize();
|
||||
if (Size==1 || Size==2) {
|
||||
// Very small objects are passed right-justified.
|
||||
// Everything else is passed left-justified.
|
||||
EVT VT = (Size==1) ? MVT::i8 : MVT::i16;
|
||||
// FOR DARWIN ONLY: Very small objects are passed right-justified.
|
||||
// Everything else is passed left-justified.
|
||||
// FOR 64-BIT SVR4: All aggregates smaller than 8 bytes must
|
||||
// be passed right-justified.
|
||||
if (Size==1 || Size==2 ||
|
||||
(Size==4 && isSVR4ABI)) {
|
||||
EVT VT = (Size==1) ? MVT::i8 : ((Size==2) ? MVT::i16 : MVT::i32);
|
||||
if (GPR_idx != NumGPRs) {
|
||||
SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, dl, PtrVT, Chain, Arg,
|
||||
MachinePointerInfo(), VT,
|
||||
@ -3341,15 +3370,67 @@ PPCTargetLowering::LowerCall_Darwin(SDValue Chain, SDValue Callee,
|
||||
// Copy entire object into memory. There are cases where gcc-generated
|
||||
// code assumes it is there, even if it could be put entirely into
|
||||
// registers. (This is not what the doc says.)
|
||||
SDValue MemcpyCall = CreateCopyOfByValArgument(Arg, PtrOff,
|
||||
CallSeqStart.getNode()->getOperand(0),
|
||||
Flags, DAG, dl);
|
||||
// This must go outside the CALLSEQ_START..END.
|
||||
SDValue NewCallSeqStart = DAG.getCALLSEQ_START(MemcpyCall,
|
||||
CallSeqStart.getNode()->getOperand(1));
|
||||
DAG.ReplaceAllUsesWith(CallSeqStart.getNode(), NewCallSeqStart.getNode());
|
||||
Chain = CallSeqStart = NewCallSeqStart;
|
||||
// And copy the pieces of it that fit into registers.
|
||||
|
||||
// FIXME: The above statement is likely due to a misunderstanding of the
|
||||
// documents. At least for 64-bit SVR4, all arguments must be copied
|
||||
// into the parameter area BY THE CALLEE in the event that the callee
|
||||
// takes the address of any formal argument. That has not yet been
|
||||
// implemented. However, it is reasonable to use the stack area as a
|
||||
// staging area for the register load.
|
||||
|
||||
// Skip this for small aggregates under 64-bit SVR4, as we will use
|
||||
// the same slot for a right-justified copy, below.
|
||||
if (Size >= 8 || !isSVR4ABI) {
|
||||
SDValue MemcpyCall = CreateCopyOfByValArgument(Arg, PtrOff,
|
||||
CallSeqStart.getNode()->getOperand(0),
|
||||
Flags, DAG, dl);
|
||||
// This must go outside the CALLSEQ_START..END.
|
||||
SDValue NewCallSeqStart = DAG.getCALLSEQ_START(MemcpyCall,
|
||||
CallSeqStart.getNode()->getOperand(1));
|
||||
DAG.ReplaceAllUsesWith(CallSeqStart.getNode(),
|
||||
NewCallSeqStart.getNode());
|
||||
Chain = CallSeqStart = NewCallSeqStart;
|
||||
}
|
||||
|
||||
// FOR 64-BIT SVR4: When a register is available, pass the
|
||||
// aggregate right-justified.
|
||||
if (isSVR4ABI && Size < 8 && GPR_idx != NumGPRs) {
|
||||
// The easiest way to get this right-justified in a register
|
||||
// is to copy the structure into the rightmost portion of a
|
||||
// local variable slot, then load the whole slot into the
|
||||
// register.
|
||||
// FIXME: The memcpy seems to produce pretty awful code for
|
||||
// small aggregates, particularly for packed ones.
|
||||
// FIXME: It would be preferable to use the slot in the
|
||||
// parameter save area instead of a new local variable.
|
||||
SDValue Const = DAG.getConstant(8 - Size, PtrOff.getValueType());
|
||||
SDValue AddPtr = DAG.getNode(ISD::ADD, dl, PtrVT, PtrOff, Const);
|
||||
SDValue MemcpyCall = CreateCopyOfByValArgument(Arg, AddPtr,
|
||||
CallSeqStart.getNode()->getOperand(0),
|
||||
Flags, DAG, dl);
|
||||
|
||||
// Place the memcpy outside the CALLSEQ_START..END.
|
||||
SDValue NewCallSeqStart = DAG.getCALLSEQ_START(MemcpyCall,
|
||||
CallSeqStart.getNode()->getOperand(1));
|
||||
DAG.ReplaceAllUsesWith(CallSeqStart.getNode(),
|
||||
NewCallSeqStart.getNode());
|
||||
Chain = CallSeqStart = NewCallSeqStart;
|
||||
|
||||
// Load the slot into the register.
|
||||
SDValue Load = DAG.getLoad(PtrVT, dl, Chain, PtrOff,
|
||||
MachinePointerInfo(),
|
||||
false, false, false, 0);
|
||||
MemOpChains.push_back(Load.getValue(1));
|
||||
RegsToPass.push_back(std::make_pair(GPR[GPR_idx++], Load));
|
||||
|
||||
// Done with this argument.
|
||||
ArgOffset += PtrByteSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
// For small aggregates (Darwin only) and aggregates >= PtrByteSize,
|
||||
// copy the pieces of the object that fit into registers from the
|
||||
// parameter save area.
|
||||
for (unsigned j=0; j<Size; j+=PtrByteSize) {
|
||||
SDValue Const = DAG.getConstant(j, PtrOff.getValueType());
|
||||
SDValue AddArg = DAG.getNode(ISD::ADD, dl, PtrVT, Arg, Const);
|
||||
|
@ -467,20 +467,21 @@ namespace llvm {
|
||||
DebugLoc dl, SelectionDAG &DAG) const;
|
||||
|
||||
SDValue
|
||||
LowerFormalArguments_Darwin(SDValue Chain,
|
||||
LowerFormalArguments_Darwin_Or_64SVR4(SDValue Chain,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
SDValue
|
||||
LowerFormalArguments_SVR4(SDValue Chain,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
LowerFormalArguments_32SVR4(SDValue Chain,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
|
||||
SDValue
|
||||
LowerCall_Darwin(SDValue Chain, SDValue Callee, CallingConv::ID CallConv,
|
||||
LowerCall_Darwin_Or_64SVR4(SDValue Chain, SDValue Callee,
|
||||
CallingConv::ID CallConv,
|
||||
bool isVarArg, bool isTailCall,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals,
|
||||
@ -488,13 +489,13 @@ namespace llvm {
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
SDValue
|
||||
LowerCall_SVR4(SDValue Chain, SDValue Callee, CallingConv::ID CallConv,
|
||||
bool isVarArg, bool isTailCall,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
LowerCall_32SVR4(SDValue Chain, SDValue Callee, CallingConv::ID CallConv,
|
||||
bool isVarArg, bool isTailCall,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
204
test/CodeGen/PowerPC/structsinregs.ll
Normal file
204
test/CodeGen/PowerPC/structsinregs.ll
Normal file
@ -0,0 +1,204 @@
|
||||
; RUN: llc -O0 -disable-fp-elim < %s | FileCheck %s
|
||||
target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64"
|
||||
target triple = "powerpc64-unknown-linux-gnu"
|
||||
|
||||
%struct.s1 = type { i8 }
|
||||
%struct.s2 = type { i16 }
|
||||
%struct.s4 = type { i32 }
|
||||
%struct.t1 = type { i8 }
|
||||
%struct.t3 = type <{ i16, i8 }>
|
||||
%struct.t5 = type <{ i32, i8 }>
|
||||
%struct.t6 = type <{ i32, i16 }>
|
||||
%struct.t7 = type <{ i32, i16, i8 }>
|
||||
%struct.s3 = type { i16, i8 }
|
||||
%struct.s5 = type { i32, i8 }
|
||||
%struct.s6 = type { i32, i16 }
|
||||
%struct.s7 = type { i32, i16, i8 }
|
||||
%struct.t2 = type <{ i16 }>
|
||||
%struct.t4 = type <{ i32 }>
|
||||
|
||||
@caller1.p1 = private unnamed_addr constant %struct.s1 { i8 1 }, align 1
|
||||
@caller1.p2 = private unnamed_addr constant %struct.s2 { i16 2 }, align 2
|
||||
@caller1.p3 = private unnamed_addr constant { i16, i8, i8 } { i16 4, i8 8, i8 undef }, align 2
|
||||
@caller1.p4 = private unnamed_addr constant %struct.s4 { i32 16 }, align 4
|
||||
@caller1.p5 = private unnamed_addr constant { i32, i8, [3 x i8] } { i32 32, i8 64, [3 x i8] undef }, align 4
|
||||
@caller1.p6 = private unnamed_addr constant { i32, i16, [2 x i8] } { i32 128, i16 256, [2 x i8] undef }, align 4
|
||||
@caller1.p7 = private unnamed_addr constant { i32, i16, i8, i8 } { i32 512, i16 1024, i8 -3, i8 undef }, align 4
|
||||
@caller2.p1 = private unnamed_addr constant %struct.t1 { i8 1 }, align 1
|
||||
@caller2.p2 = private unnamed_addr constant { i16 } { i16 2 }, align 1
|
||||
@caller2.p3 = private unnamed_addr constant %struct.t3 <{ i16 4, i8 8 }>, align 1
|
||||
@caller2.p4 = private unnamed_addr constant { i32 } { i32 16 }, align 1
|
||||
@caller2.p5 = private unnamed_addr constant %struct.t5 <{ i32 32, i8 64 }>, align 1
|
||||
@caller2.p6 = private unnamed_addr constant %struct.t6 <{ i32 128, i16 256 }>, align 1
|
||||
@caller2.p7 = private unnamed_addr constant %struct.t7 <{ i32 512, i16 1024, i8 -3 }>, align 1
|
||||
|
||||
define i32 @caller1() nounwind {
|
||||
entry:
|
||||
%p1 = alloca %struct.s1, align 1
|
||||
%p2 = alloca %struct.s2, align 2
|
||||
%p3 = alloca %struct.s3, align 2
|
||||
%p4 = alloca %struct.s4, align 4
|
||||
%p5 = alloca %struct.s5, align 4
|
||||
%p6 = alloca %struct.s6, align 4
|
||||
%p7 = alloca %struct.s7, align 4
|
||||
%0 = bitcast %struct.s1* %p1 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* getelementptr inbounds (%struct.s1* @caller1.p1, i32 0, i32 0), i64 1, i32 1, i1 false)
|
||||
%1 = bitcast %struct.s2* %p2 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast (%struct.s2* @caller1.p2 to i8*), i64 2, i32 2, i1 false)
|
||||
%2 = bitcast %struct.s3* %p3 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* bitcast ({ i16, i8, i8 }* @caller1.p3 to i8*), i64 4, i32 2, i1 false)
|
||||
%3 = bitcast %struct.s4* %p4 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* bitcast (%struct.s4* @caller1.p4 to i8*), i64 4, i32 4, i1 false)
|
||||
%4 = bitcast %struct.s5* %p5 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* bitcast ({ i32, i8, [3 x i8] }* @caller1.p5 to i8*), i64 8, i32 4, i1 false)
|
||||
%5 = bitcast %struct.s6* %p6 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* bitcast ({ i32, i16, [2 x i8] }* @caller1.p6 to i8*), i64 8, i32 4, i1 false)
|
||||
%6 = bitcast %struct.s7* %p7 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %6, i8* bitcast ({ i32, i16, i8, i8 }* @caller1.p7 to i8*), i64 8, i32 4, i1 false)
|
||||
%call = call i32 @callee1(%struct.s1* byval %p1, %struct.s2* byval %p2, %struct.s3* byval %p3, %struct.s4* byval %p4, %struct.s5* byval %p5, %struct.s6* byval %p6, %struct.s7* byval %p7)
|
||||
ret i32 %call
|
||||
|
||||
; CHECK: ld 9, 128(31)
|
||||
; CHECK: ld 8, 136(31)
|
||||
; CHECK: ld 7, 144(31)
|
||||
; CHECK: lwz 6, 152(31)
|
||||
; CHECK: lwz 5, 160(31)
|
||||
; CHECK: lhz 4, 168(31)
|
||||
; CHECK: lbz 3, 176(31)
|
||||
}
|
||||
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
|
||||
|
||||
define internal i32 @callee1(%struct.s1* byval %v1, %struct.s2* byval %v2, %struct.s3* byval %v3, %struct.s4* byval %v4, %struct.s5* byval %v5, %struct.s6* byval %v6, %struct.s7* byval %v7) nounwind {
|
||||
entry:
|
||||
%a = getelementptr inbounds %struct.s1* %v1, i32 0, i32 0
|
||||
%0 = load i8* %a, align 1
|
||||
%conv = zext i8 %0 to i32
|
||||
%a1 = getelementptr inbounds %struct.s2* %v2, i32 0, i32 0
|
||||
%1 = load i16* %a1, align 2
|
||||
%conv2 = sext i16 %1 to i32
|
||||
%add = add nsw i32 %conv, %conv2
|
||||
%a3 = getelementptr inbounds %struct.s3* %v3, i32 0, i32 0
|
||||
%2 = load i16* %a3, align 2
|
||||
%conv4 = sext i16 %2 to i32
|
||||
%add5 = add nsw i32 %add, %conv4
|
||||
%a6 = getelementptr inbounds %struct.s4* %v4, i32 0, i32 0
|
||||
%3 = load i32* %a6, align 4
|
||||
%add7 = add nsw i32 %add5, %3
|
||||
%a8 = getelementptr inbounds %struct.s5* %v5, i32 0, i32 0
|
||||
%4 = load i32* %a8, align 4
|
||||
%add9 = add nsw i32 %add7, %4
|
||||
%a10 = getelementptr inbounds %struct.s6* %v6, i32 0, i32 0
|
||||
%5 = load i32* %a10, align 4
|
||||
%add11 = add nsw i32 %add9, %5
|
||||
%a12 = getelementptr inbounds %struct.s7* %v7, i32 0, i32 0
|
||||
%6 = load i32* %a12, align 4
|
||||
%add13 = add nsw i32 %add11, %6
|
||||
ret i32 %add13
|
||||
|
||||
; CHECK: std 9, 96(1)
|
||||
; CHECK: std 8, 88(1)
|
||||
; CHECK: std 7, 80(1)
|
||||
; CHECK: stw 6, 72(1)
|
||||
; CHECK: stw 5, 64(1)
|
||||
; CHECK: sth 4, 58(1)
|
||||
; CHECK: stb 3, 51(1)
|
||||
; CHECK: lha {{[0-9]+}}, 58(1)
|
||||
; CHECK: lbz {{[0-9]+}}, 51(1)
|
||||
; CHECK: lha {{[0-9]+}}, 64(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 72(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 80(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 88(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 96(1)
|
||||
}
|
||||
|
||||
define i32 @caller2() nounwind {
|
||||
entry:
|
||||
%p1 = alloca %struct.t1, align 1
|
||||
%p2 = alloca %struct.t2, align 1
|
||||
%p3 = alloca %struct.t3, align 1
|
||||
%p4 = alloca %struct.t4, align 1
|
||||
%p5 = alloca %struct.t5, align 1
|
||||
%p6 = alloca %struct.t6, align 1
|
||||
%p7 = alloca %struct.t7, align 1
|
||||
%0 = bitcast %struct.t1* %p1 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* getelementptr inbounds (%struct.t1* @caller2.p1, i32 0, i32 0), i64 1, i32 1, i1 false)
|
||||
%1 = bitcast %struct.t2* %p2 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast ({ i16 }* @caller2.p2 to i8*), i64 2, i32 1, i1 false)
|
||||
%2 = bitcast %struct.t3* %p3 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* bitcast (%struct.t3* @caller2.p3 to i8*), i64 3, i32 1, i1 false)
|
||||
%3 = bitcast %struct.t4* %p4 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* bitcast ({ i32 }* @caller2.p4 to i8*), i64 4, i32 1, i1 false)
|
||||
%4 = bitcast %struct.t5* %p5 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* bitcast (%struct.t5* @caller2.p5 to i8*), i64 5, i32 1, i1 false)
|
||||
%5 = bitcast %struct.t6* %p6 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* bitcast (%struct.t6* @caller2.p6 to i8*), i64 6, i32 1, i1 false)
|
||||
%6 = bitcast %struct.t7* %p7 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %6, i8* bitcast (%struct.t7* @caller2.p7 to i8*), i64 7, i32 1, i1 false)
|
||||
%call = call i32 @callee2(%struct.t1* byval %p1, %struct.t2* byval %p2, %struct.t3* byval %p3, %struct.t4* byval %p4, %struct.t5* byval %p5, %struct.t6* byval %p6, %struct.t7* byval %p7)
|
||||
ret i32 %call
|
||||
|
||||
; CHECK: stb {{[0-9]+}}, 71(1)
|
||||
; CHECK: sth {{[0-9]+}}, 69(1)
|
||||
; CHECK: stb {{[0-9]+}}, 87(1)
|
||||
; CHECK: stw {{[0-9]+}}, 83(1)
|
||||
; CHECK: sth {{[0-9]+}}, 94(1)
|
||||
; CHECK: stw {{[0-9]+}}, 90(1)
|
||||
; CHECK: stb {{[0-9]+}}, 103(1)
|
||||
; CHECK: sth {{[0-9]+}}, 101(1)
|
||||
; CHECK: stw {{[0-9]+}}, 97(1)
|
||||
; CHECK: ld 9, 96(1)
|
||||
; CHECK: ld 8, 88(1)
|
||||
; CHECK: ld 7, 80(1)
|
||||
; CHECK: lwz 6, 152(31)
|
||||
; CHECK: ld 5, 64(1)
|
||||
; CHECK: lhz 4, 168(31)
|
||||
; CHECK: lbz 3, 176(31)
|
||||
}
|
||||
|
||||
define internal i32 @callee2(%struct.t1* byval %v1, %struct.t2* byval %v2, %struct.t3* byval %v3, %struct.t4* byval %v4, %struct.t5* byval %v5, %struct.t6* byval %v6, %struct.t7* byval %v7) nounwind {
|
||||
entry:
|
||||
%a = getelementptr inbounds %struct.t1* %v1, i32 0, i32 0
|
||||
%0 = load i8* %a, align 1
|
||||
%conv = zext i8 %0 to i32
|
||||
%a1 = getelementptr inbounds %struct.t2* %v2, i32 0, i32 0
|
||||
%1 = load i16* %a1, align 1
|
||||
%conv2 = sext i16 %1 to i32
|
||||
%add = add nsw i32 %conv, %conv2
|
||||
%a3 = getelementptr inbounds %struct.t3* %v3, i32 0, i32 0
|
||||
%2 = load i16* %a3, align 1
|
||||
%conv4 = sext i16 %2 to i32
|
||||
%add5 = add nsw i32 %add, %conv4
|
||||
%a6 = getelementptr inbounds %struct.t4* %v4, i32 0, i32 0
|
||||
%3 = load i32* %a6, align 1
|
||||
%add7 = add nsw i32 %add5, %3
|
||||
%a8 = getelementptr inbounds %struct.t5* %v5, i32 0, i32 0
|
||||
%4 = load i32* %a8, align 1
|
||||
%add9 = add nsw i32 %add7, %4
|
||||
%a10 = getelementptr inbounds %struct.t6* %v6, i32 0, i32 0
|
||||
%5 = load i32* %a10, align 1
|
||||
%add11 = add nsw i32 %add9, %5
|
||||
%a12 = getelementptr inbounds %struct.t7* %v7, i32 0, i32 0
|
||||
%6 = load i32* %a12, align 1
|
||||
%add13 = add nsw i32 %add11, %6
|
||||
ret i32 %add13
|
||||
|
||||
; CHECK: sldi 9, 9, 8
|
||||
; CHECK: sldi 8, 8, 16
|
||||
; CHECK: sldi 7, 7, 24
|
||||
; CHECK: sldi 5, 5, 40
|
||||
; CHECK: stw 6, 72(1)
|
||||
; CHECK: sth 4, 58(1)
|
||||
; CHECK: stb 3, 51(1)
|
||||
; CHECK: std 9, 96(1)
|
||||
; CHECK: std 8, 88(1)
|
||||
; CHECK: std 7, 80(1)
|
||||
; CHECK: std 5, 64(1)
|
||||
; CHECK: lha {{[0-9]+}}, 58(1)
|
||||
; CHECK: lbz {{[0-9]+}}, 51(1)
|
||||
; CHECK: lha {{[0-9]+}}, 64(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 72(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 80(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 88(1)
|
||||
; CHECK: lwz {{[0-9]+}}, 96(1)
|
||||
}
|
Loading…
Reference in New Issue
Block a user