forked from OSchip/llvm-project
[PowerPC][AIX] ByVal formal arguments in a single register.
Adds support for passing ByVal formal arguments as long as they fit in a single register. Differential Revision: https://reviews.llvm.org/D76401
This commit is contained in:
parent
86e0a6c606
commit
3282d875d6
|
@ -6861,9 +6861,14 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
|
|||
|
||||
const unsigned ByValSize = ArgFlags.getByValSize();
|
||||
|
||||
// An empty aggregate parameter takes up no storage and no registers.
|
||||
if (ByValSize == 0)
|
||||
// An empty aggregate parameter takes up no storage and no registers,
|
||||
// but needs a MemLoc for a stack slot for the formal arguments side.
|
||||
if (ByValSize == 0) {
|
||||
State.addLoc(CCValAssign::getMem(ValNo, MVT::INVALID_SIMPLE_VALUE_TYPE,
|
||||
State.getNextStackOffset(), RegVT,
|
||||
LocInfo));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ByValSize <= PtrByteSize) {
|
||||
State.AllocateStack(PtrByteSize, PtrByteSize);
|
||||
|
@ -6978,6 +6983,24 @@ static SDValue truncateScalarIntegerArg(ISD::ArgFlagsTy Flags, EVT ValVT,
|
|||
return DAG.getNode(ISD::TRUNCATE, dl, ValVT, ArgValue);
|
||||
}
|
||||
|
||||
static unsigned mapArgRegToOffsetAIX(unsigned Reg, const PPCFrameLowering *FL) {
|
||||
const unsigned LASize = FL->getLinkageSize();
|
||||
|
||||
if (PPC::GPRCRegClass.contains(Reg)) {
|
||||
assert(Reg >= PPC::R3 && Reg <= PPC::R10 &&
|
||||
"Reg must be a valid argument register!");
|
||||
return LASize + 4 * (Reg - PPC::R3);
|
||||
}
|
||||
|
||||
if (PPC::G8RCRegClass.contains(Reg)) {
|
||||
assert(Reg >= PPC::X3 && Reg <= PPC::X10 &&
|
||||
"Reg must be a valid argument register!");
|
||||
return LASize + 8 * (Reg - PPC::X3);
|
||||
}
|
||||
|
||||
llvm_unreachable("Only general purpose registers expected.");
|
||||
}
|
||||
|
||||
SDValue PPCTargetLowering::LowerFormalArguments_AIX(
|
||||
SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
|
||||
|
@ -7015,12 +7038,12 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
|
|||
CCInfo.AllocateStack(LinkageSize, PtrByteSize);
|
||||
CCInfo.AnalyzeFormalArguments(Ins, CC_AIX);
|
||||
|
||||
SmallVector<SDValue, 8> MemOps;
|
||||
|
||||
for (CCValAssign &VA : ArgLocs) {
|
||||
EVT ValVT = VA.getValVT();
|
||||
MVT LocVT = VA.getLocVT();
|
||||
ISD::ArgFlagsTy Flags = Ins[VA.getValNo()].Flags;
|
||||
assert(!Flags.isByVal() &&
|
||||
"Passing structure by value is unimplemented for formal arguments.");
|
||||
assert((VA.isRegLoc() || VA.isMemLoc()) &&
|
||||
"Unexpected location for function call argument.");
|
||||
|
||||
|
@ -7033,6 +7056,59 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
|
|||
if (VA.isMemLoc() && VA.needsCustom())
|
||||
continue;
|
||||
|
||||
if (Flags.isByVal() && VA.isMemLoc()) {
|
||||
if (Flags.getByValSize() != 0)
|
||||
report_fatal_error(
|
||||
"ByVal arguments passed on stack not implemented yet");
|
||||
|
||||
const int FI = MF.getFrameInfo().CreateFixedObject(
|
||||
PtrByteSize, VA.getLocMemOffset(), /* IsImmutable */ false,
|
||||
/* IsAliased */ true);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
|
||||
InVals.push_back(FIN);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Flags.isByVal()) {
|
||||
assert(VA.isRegLoc() && "MemLocs should already be handled.");
|
||||
|
||||
const unsigned ByValSize = Flags.getByValSize();
|
||||
if (ByValSize > PtrByteSize)
|
||||
report_fatal_error("Formal arguments greater then register size not "
|
||||
"implemented yet.");
|
||||
|
||||
const MCPhysReg ArgReg = VA.getLocReg();
|
||||
const PPCFrameLowering *FL = Subtarget.getFrameLowering();
|
||||
const unsigned Offset = mapArgRegToOffsetAIX(ArgReg, FL);
|
||||
|
||||
const unsigned StackSize = alignTo(ByValSize, PtrByteSize);
|
||||
const int FI = MF.getFrameInfo().CreateFixedObject(
|
||||
StackSize, Offset, /* IsImmutable */ false, /* IsAliased */ true);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
|
||||
|
||||
InVals.push_back(FIN);
|
||||
|
||||
const unsigned VReg = MF.addLiveIn(ArgReg, IsPPC64 ? &PPC::G8RCRegClass
|
||||
: &PPC::GPRCRegClass);
|
||||
|
||||
// Since the callers side has left justified the aggregate in the
|
||||
// register, we can simply store the entire register into the stack
|
||||
// slot.
|
||||
// The store to the fixedstack object is needed becuase accessing a
|
||||
// field of the ByVal will use a gep and load. Ideally we will optimize
|
||||
// to extracting the value from the register directly, and elide the
|
||||
// stores when the arguments address is not taken, but that will need to
|
||||
// be future work.
|
||||
SDValue CopyFrom = DAG.getCopyFromReg(Chain, dl, VReg, LocVT);
|
||||
SDValue Store =
|
||||
DAG.getStore(CopyFrom.getValue(1), dl, CopyFrom, FIN,
|
||||
MachinePointerInfo::getFixedStack(MF, FI, 0));
|
||||
|
||||
MemOps.push_back(Store);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VA.isRegLoc()) {
|
||||
MVT::SimpleValueType SVT = ValVT.getSimpleVT().SimpleTy;
|
||||
unsigned VReg =
|
||||
|
@ -7080,6 +7156,9 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
|
|||
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
|
||||
FuncInfo->setMinReservedArea(CallerReservedArea);
|
||||
|
||||
if (!MemOps.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
|
||||
|
||||
return Chain;
|
||||
}
|
||||
|
||||
|
@ -7156,8 +7235,13 @@ SDValue PPCTargetLowering::LowerCall_AIX(
|
|||
|
||||
if (Flags.isByVal()) {
|
||||
const unsigned ByValSize = Flags.getByValSize();
|
||||
|
||||
// Nothing to do for zero-sized ByVals on the caller side.
|
||||
if (!ByValSize)
|
||||
continue;
|
||||
|
||||
assert(
|
||||
VA.isRegLoc() && ByValSize > 0 && ByValSize <= PtrByteSize &&
|
||||
VA.isRegLoc() && ByValSize <= PtrByteSize &&
|
||||
"Pass-by-value arguments are only supported in a single register.");
|
||||
|
||||
// Loads must be a power-of-2 size and cannot be larger than the
|
||||
|
|
|
@ -22,11 +22,10 @@
|
|||
define void @call_test_byval_1Byte() {
|
||||
entry:
|
||||
%s0 = alloca %struct.S0, align 8
|
||||
call void @test_byval_1Byte(%struct.S0* byval(%struct.S0) align 1 %s0, %struct.S1* byval(%struct.S1) align 1 @gS1)
|
||||
%call = call zeroext i8 @test_byval_1Byte(%struct.S0* byval(%struct.S0) align 1 %s0, %struct.S1* byval(%struct.S1) align 1 @gS1)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_1Byte(%struct.S0* byval(%struct.S0) align 1, %struct.S1* byval(%struct.S1) align 1)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_1Byte{{.*}}
|
||||
|
||||
|
@ -63,18 +62,59 @@ declare void @test_byval_1Byte(%struct.S0* byval(%struct.S0) align 1, %struct.S1
|
|||
; ASM64-NEXT: nop
|
||||
; ASM64-NEXT: addi 1, 1, 128
|
||||
|
||||
|
||||
define zeroext i8 @test_byval_1Byte(%struct.S0* byval(%struct.S0) align 1 %s0, %struct.S1* byval(%struct.S1) align 1 %s) {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.S1, %struct.S1* %s, i32 0, i32 0, i32 0
|
||||
%0 = load i8, i8* %arrayidx, align 1
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_1Byte
|
||||
|
||||
; 32BIT: fixedStack:
|
||||
; 32BIT-NEXT: - { id: 0, type: default, offset: 24, size: 4, alignment: 8, stack-id: default,
|
||||
; 32BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
; 32BIT: - { id: 1, type: default, offset: 24, size: 4, alignment: 8, stack-id: default,
|
||||
; 32BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
|
||||
; 32BIT: bb.0.entry:
|
||||
; 32BIT-NEXT: liveins: $r3
|
||||
; 32BIT: STW killed renamable $r3, 0, %fixed-stack.0 :: (store 4 into %fixed-stack.0, align 8)
|
||||
; 32BIT-NEXT: renamable $r3 = LBZ 0, %fixed-stack.0 :: (dereferenceable load 1
|
||||
; 32BIT-NEXT: BLR
|
||||
|
||||
; 64BIT: fixedStack:
|
||||
; 64BIT-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16, stack-id: default,
|
||||
; 64BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
; 64BIT: - { id: 1, type: default, offset: 48, size: 8, alignment: 16, stack-id: default,
|
||||
; 64BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
|
||||
; 64BIT: bb.0.entry:
|
||||
; 64BIT-NEXT: liveins: $x3
|
||||
; 64BIT: STD killed renamable $x3, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16)
|
||||
; 64BIT-NEXT: renamable $x3 = LBZ8 0, %fixed-stack.0 :: (dereferenceable load 1
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_1Byte:
|
||||
|
||||
; ASM32: stw 3, 24(1)
|
||||
; ASM32-NEXT: lbz 3, 24(1)
|
||||
; ASM32-NEXT: blr
|
||||
|
||||
; ASM64: std 3, 48(1)
|
||||
; ASM64-NEXT: lbz 3, 48(1)
|
||||
; ASM64-NEXT: blr
|
||||
|
||||
%struct.S2 = type { [2 x i8] }
|
||||
|
||||
@gS2 = external global %struct.S2, align 1
|
||||
|
||||
define void @call_test_byval_2Byte() {
|
||||
entry:
|
||||
call void @test_byval_2Byte(%struct.S2* byval(%struct.S2) align 1 @gS2)
|
||||
%call = call zeroext i8 @test_byval_2Byte(%struct.S2* byval(%struct.S2) align 1 @gS2)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_2Byte(%struct.S2* byval(%struct.S2) align 1)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_2Byte{{.*}}
|
||||
|
||||
; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1
|
||||
|
@ -110,18 +150,51 @@ declare void @test_byval_2Byte(%struct.S2* byval(%struct.S2) align 1)
|
|||
; ASM64-NEXT: nop
|
||||
; ASM64-NEXT: addi 1, 1, 112
|
||||
|
||||
%struct.S3 = type <{ i8, i16 }>
|
||||
|
||||
define zeroext i8 @test_byval_2Byte(%struct.S2* byval(%struct.S2) align 1 %s) {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.S2, %struct.S2* %s, i32 0, i32 0, i32 1
|
||||
%0 = load i8, i8* %arrayidx, align 1
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_2Byte
|
||||
; 32BIT: fixedStack:
|
||||
; 32BIT-NEXT: - { id: 0, type: default, offset: 24, size: 4, alignment: 8, stack-id: default,
|
||||
|
||||
; 32BIT: bb.0.entry:
|
||||
; 32BIT-NEXT: liveins: $r3
|
||||
; 32BIT: STW killed renamable $r3, 0, %fixed-stack.0 :: (store 4 into %fixed-stack.0, align 8)
|
||||
; 32BIT-NEXT: renamable $r3 = LBZ 1, %fixed-stack.0 :: (dereferenceable load 1
|
||||
|
||||
; 64BIT: fixedStack:
|
||||
; 64BIT-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16, stack-id: default,
|
||||
|
||||
; 64BIT: bb.0.entry:
|
||||
; 64BIT-NEXT: liveins: $x3
|
||||
; 64BIT: STD killed renamable $x3, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16)
|
||||
; 64BIT-NEXT: renamable $x3 = LBZ8 1, %fixed-stack.0 :: (dereferenceable load 1
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_2Byte:
|
||||
|
||||
; ASM32: stw 3, 24(1)
|
||||
; ASM32-NEXT: lbz 3, 25(1)
|
||||
; ASM32-NEXT: blr
|
||||
|
||||
; ASM64: std 3, 48(1)
|
||||
; ASM64-NEXT: lbz 3, 49(1)
|
||||
; ASM64-NEXT: blr
|
||||
|
||||
|
||||
%struct.S3 = type <{ i8, i16 }>
|
||||
@gS3 = external global %struct.S3, align 1
|
||||
|
||||
define void @call_test_byval_3Byte() {
|
||||
entry:
|
||||
call void @test_byval_3Byte(%struct.S3* byval(%struct.S3) align 1 @gS3)
|
||||
%call = call zeroext i16 @test_byval_3Byte(%struct.S3* byval(%struct.S3) align 1 @gS3)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_3Byte(%struct.S3* byval(%struct.S3) align 1)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_3Byte{{.*}}
|
||||
|
||||
; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings.
|
||||
|
@ -166,6 +239,44 @@ declare void @test_byval_3Byte(%struct.S3* byval(%struct.S3) align 1)
|
|||
; ASM64-NEXT: bl .test_byval_3Byte
|
||||
; ASM64-NEXT: nop
|
||||
|
||||
|
||||
define zeroext i16 @test_byval_3Byte(%struct.S3* byval(%struct.S3) align 1 %s) {
|
||||
entry:
|
||||
%gep = getelementptr inbounds %struct.S3, %struct.S3* %s, i32 0, i32 1
|
||||
%0 = load i16, i16* %gep, align 1
|
||||
ret i16 %0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_3Byte
|
||||
|
||||
; 32BIT: fixedStack:
|
||||
; 32BIT-NEXT: - { id: 0, type: default, offset: 24, size: 4, alignment: 8, stack-id: default,
|
||||
|
||||
; 32BIT: bb.0.entry:
|
||||
; 32BIT-NEXT: liveins: $r3
|
||||
; 32BIT: STW killed renamable $r3, 0, %fixed-stack.0 :: (store 4 into %fixed-stack.0, align 8)
|
||||
; 32BIT-NEXT: renamable $r3 = LHZ 1, %fixed-stack.0 :: (dereferenceable load 2
|
||||
|
||||
; 64BIT: fixedStack:
|
||||
; 64BIT-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16, stack-id: default,
|
||||
|
||||
; 64BIT: bb.0.entry:
|
||||
; 64BIT-NEXT: liveins: $x3
|
||||
; 64BIT: STD killed renamable $x3, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16)
|
||||
; 64BIT-NEXT: renamable $x3 = LHZ8 1, %fixed-stack.0 :: (dereferenceable load 2
|
||||
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_3Byte:
|
||||
|
||||
; ASM32: stw 3, 24(1)
|
||||
; ASM32-NEXT: lhz 3, 25(1)
|
||||
; ASM32-NEXT: blr
|
||||
|
||||
; ASM64: std 3, 48(1)
|
||||
; ASM64-NEXT: lhz 3, 49(1)
|
||||
; ASM64-NEXT: blr
|
||||
|
||||
|
||||
%struct.S4 = type { [4 x i8] }
|
||||
%struct.S4A = type { i32 }
|
||||
|
||||
|
@ -175,12 +286,10 @@ define void @call_test_byval_4Byte() {
|
|||
entry:
|
||||
%s0 = alloca %struct.S0, align 8
|
||||
%s4a = alloca %struct.S4A, align 4
|
||||
call void @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1 @gS4, %struct.S0* byval(%struct.S0) align 1 %s0, %struct.S4A* byval(%struct.S4A) align 4 %s4a)
|
||||
%call = call signext i32 @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1 @gS4, %struct.S0* byval(%struct.S0) align 1 %s0, %struct.S4A* byval(%struct.S4A) align 4 %s4a)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1, %struct.S0* byval(%struct.S0) align 1, %struct.S4A* byval(%struct.S4A) align 4)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_4Byte{{.*}}
|
||||
|
||||
; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1
|
||||
|
@ -219,3 +328,66 @@ declare void @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1, %struct.S0
|
|||
; ASM64-NEXT: nop
|
||||
; ASM64-NEXT: addi 1, 1, 128
|
||||
|
||||
|
||||
define signext i32 @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1 %s, %struct.S0* byval(%struct.S0) align 1, %struct.S4A* byval(%struct.S4A) align 4 %s4a) {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.S4, %struct.S4* %s, i32 0, i32 0, i32 3
|
||||
%gep = getelementptr inbounds %struct.S4A, %struct.S4A* %s4a, i32 0, i32 0
|
||||
%1 = load i8, i8* %arrayidx, align 1
|
||||
%2 = load i32, i32* %gep, align 4
|
||||
%conv = zext i8 %1 to i32
|
||||
%add = add nsw i32 %2, %conv
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_4Byte
|
||||
|
||||
; 32BIT: fixedStack:
|
||||
; 32BIT-NEXT: - { id: 0, type: default, offset: 28, size: 4, alignment: 4, stack-id: default,
|
||||
; 32BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
; 32BIT: - { id: 1, type: default, offset: 28, size: 4, alignment: 4, stack-id: default,
|
||||
; 32BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
; 32BIT: - { id: 2, type: default, offset: 24, size: 4, alignment: 8, stack-id: default,
|
||||
; 32BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
|
||||
; 32BIT: bb.0.entry:
|
||||
; 32BIT-NEXT: liveins: $r3
|
||||
; 32BIT: STW renamable $r3, 0, %fixed-stack.2 :: (store 4 into %fixed-stack.2, align 8)
|
||||
; 32BIT-DAG: STW killed renamable $r4, 0, %fixed-stack.0 :: (store 4 into %fixed-stack.0)
|
||||
; 32BIT-DAG: renamable $r[[SCRATCH:[0-9]+]] = RLWINM killed renamable $r3, 0, 24, 31
|
||||
; 32BIT-DAG: renamable $r3 = nsw ADD4 renamable $r4, killed renamable $r[[SCRATCH]]
|
||||
; 32BIT: BLR
|
||||
|
||||
; 64BIT: fixedStack:
|
||||
; 64BIT-NEXT: - { id: 0, type: default, offset: 56, size: 8, alignment: 8, stack-id: default,
|
||||
; 64BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
; 64BIT: - { id: 1, type: default, offset: 56, size: 8, alignment: 8, stack-id: default,
|
||||
; 64BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
; 64BIT: - { id: 2, type: default, offset: 48, size: 8, alignment: 16, stack-id: default,
|
||||
; 64BIT-NEXT: isImmutable: false, isAliased: true, callee-saved-register: '', callee-saved-restored: true,
|
||||
|
||||
; 64BIT: bb.0.entry:
|
||||
; 64BIT-NEXT: liveins: $x3
|
||||
; 64BIT: STD killed renamable $x3, 0, %fixed-stack.2 :: (store 8 into %fixed-stack.2, align 16)
|
||||
; 64BIT-NEXT: STD killed renamable $x4, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0)
|
||||
; 64BIT-DAG: renamable $r[[SCRATCH1:[0-9]+]] = LBZ 3, %fixed-stack.2 :: (dereferenceable load 1
|
||||
; 64BIT-DAG: renamable $r[[SCRATCH2:[0-9]+]] = LWZ 0, %fixed-stack.0 :: (dereferenceable load 4
|
||||
; 64BIT-NEXT: renamable $r[[SCRATCH3:[0-9]+]] = nsw ADD4 killed renamable $r[[SCRATCH2]], killed renamable $r[[SCRATCH1]]
|
||||
; 64BIT-NEXT: renamable $x3 = EXTSW_32_64 killed renamable $r[[SCRATCH3]]
|
||||
; 64BIT-NEXT: BLR8
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_4Byte:
|
||||
|
||||
; ASM32: stw 3, 24(1)
|
||||
; ASM32-DAG: stw 4, 28(1)
|
||||
; ASM32-DAG: clrlwi [[SCRATCH:[0-9]+]], 3, 24
|
||||
; ASM32-DAG: add 3, 4, [[SCRATCH]]
|
||||
; ASM32-NEXT: blr
|
||||
|
||||
; ASM64: std 3, 48(1)
|
||||
; ASM64-NEXT: std 4, 56(1)
|
||||
; ASM64-DAG: lbz [[SCRATCH1:[0-9]+]], 51(1)
|
||||
; ASM64-DAG: lwz [[SCRATCH2:[0-9]+]], 56(1)
|
||||
; ASM64-NEXT: add [[SCRATCH3:[0-9]+]], [[SCRATCH2]], [[SCRATCH1]]
|
||||
; ASM64-NEXT: extsw 3, [[SCRATCH3]]
|
||||
; ASM64-NEXT: blr
|
||||
|
|
|
@ -12,12 +12,10 @@
|
|||
|
||||
define void @call_test_byval_5Byte() {
|
||||
entry:
|
||||
call void @test_byval_5Byte(%struct.S5* byval(%struct.S5) align 1 @gS5)
|
||||
%call = call zeroext i8 @test_byval_5Byte(%struct.S5* byval(%struct.S5) align 1 @gS5)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_5Byte(%struct.S5* byval(%struct.S5) align 1)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_5Byte{{.*}}
|
||||
|
||||
; ASM-LABEL: .call_test_byval_5Byte:
|
||||
|
@ -42,18 +40,40 @@ declare void @test_byval_5Byte(%struct.S5* byval(%struct.S5) align 1)
|
|||
; ASM-NEXT: bl .test_byval_5Byte
|
||||
; ASM-NEXT: nop
|
||||
|
||||
|
||||
define zeroext i8 @test_byval_5Byte(%struct.S5* byval(%struct.S5) align 1 %s) {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.S5, %struct.S5* %s, i32 0, i32 0, i32 4
|
||||
%0 = load i8, i8* %arrayidx, align 1
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_5Byte
|
||||
|
||||
; CHECK: fixedStack:
|
||||
; CHECK-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16,
|
||||
; CHECK: bb.0.entry:
|
||||
; CHECK-NEXT: liveins: $x3
|
||||
; CHECK: STD killed renamable $x3, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16)
|
||||
; CHECK-NEXT: renamable $x3 = LBZ8 4, %fixed-stack.0 :: (dereferenceable load 1
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_5Byte:
|
||||
|
||||
; ASM: std 3, 48(1)
|
||||
; ASM-NEXT: lbz 3, 52(1)
|
||||
; ASM-NEXT: blr
|
||||
|
||||
|
||||
%struct.S6 = type { [6 x i8] }
|
||||
|
||||
@gS6 = external global %struct.S6, align 1
|
||||
|
||||
define void @call_test_byval_6Byte() {
|
||||
entry:
|
||||
call void @test_byval_6Byte(%struct.S6* byval(%struct.S6) align 1 @gS6)
|
||||
%call = call zeroext i8 @test_byval_6Byte(%struct.S6* byval(%struct.S6) align 1 @gS6)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_6Byte(%struct.S6* byval(%struct.S6) align 1)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_6Byte{{.*}}
|
||||
|
||||
; ASM-LABEL: .call_test_byval_6Byte:
|
||||
|
@ -78,18 +98,39 @@ declare void @test_byval_6Byte(%struct.S6* byval(%struct.S6) align 1)
|
|||
; ASM-NEXT: bl .test_byval_6Byte
|
||||
; ASM-NEXT: nop
|
||||
|
||||
|
||||
define zeroext i8 @test_byval_6Byte(%struct.S6* byval(%struct.S6) align 1 %s) {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.S6, %struct.S6* %s, i32 0, i32 0, i32 5
|
||||
%0 = load i8, i8* %arrayidx, align 1
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_6Byte
|
||||
|
||||
; CHECK: fixedStack:
|
||||
; CHECK-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16,
|
||||
; CHECK: bb.0.entry:
|
||||
; CHECK-NEXT: liveins: $x3
|
||||
; CHECK: STD killed renamable $x3, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16)
|
||||
; CHECK-NEXT: renamable $x3 = LBZ8 5, %fixed-stack.0 :: (dereferenceable load 1
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_6Byte:
|
||||
|
||||
; ASM: std 3, 48(1)
|
||||
; ASM-NEXT: lbz 3, 53(1)
|
||||
; ASM-NEXT: blr
|
||||
|
||||
%struct.S7 = type { [7 x i8] }
|
||||
|
||||
@gS7 = external global %struct.S7, align 1
|
||||
|
||||
define void @call_test_byval_7Byte() {
|
||||
entry:
|
||||
call void @test_byval_7Byte(%struct.S7* byval(%struct.S7) align 1 @gS7)
|
||||
%call = call zeroext i8 @test_byval_7Byte(%struct.S7* byval(%struct.S7) align 1 @gS7)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_7Byte(%struct.S7* byval(%struct.S7) align 1)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_7Byte{{.*}}
|
||||
|
||||
; ASM-LABEL: .call_test_byval_7Byte:
|
||||
|
@ -118,18 +159,40 @@ declare void @test_byval_7Byte(%struct.S7* byval(%struct.S7) align 1)
|
|||
; ASM-NEXT: bl .test_byval_7Byte
|
||||
; ASM-NEXT: nop
|
||||
|
||||
|
||||
define zeroext i8 @test_byval_7Byte(%struct.S7* byval(%struct.S7) align 1 %s) {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.S7, %struct.S7* %s, i32 0, i32 0, i32 6
|
||||
%0 = load i8, i8* %arrayidx, align 1
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_7Byte
|
||||
|
||||
; CHECK: fixedStack:
|
||||
; CHECK-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16,
|
||||
; CHECK: bb.0.entry:
|
||||
; CHECK-NEXT: liveins: $x3
|
||||
; CHECK: STD killed renamable $x3, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16)
|
||||
; CHECK-NEXT: renamable $x3 = LBZ8 6, %fixed-stack.0 :: (dereferenceable load 1
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_7Byte:
|
||||
|
||||
; ASM: std 3, 48(1)
|
||||
; ASM-NEXT: lbz 3, 54(1)
|
||||
; ASM-NEXT: blr
|
||||
|
||||
|
||||
%struct.S8 = type { [8 x i8] }
|
||||
|
||||
@gS8 = external global %struct.S8, align 1
|
||||
|
||||
define void @call_test_byval_8Byte() {
|
||||
entry:
|
||||
call void @test_byval_8Byte(%struct.S8* byval(%struct.S8) align 1 @gS8)
|
||||
%call = call zeroext i8 @test_byval_8Byte(%struct.S8* byval(%struct.S8) align 1 @gS8)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @test_byval_8Byte(%struct.S8* byval(%struct.S8) align 1)
|
||||
|
||||
; CHECK-LABEL: name: call_test_byval_8Byte{{.*}}
|
||||
|
||||
; ASM-LABEL: .call_test_byval_8Byte:
|
||||
|
@ -145,3 +208,29 @@ declare void @test_byval_8Byte(%struct.S8* byval(%struct.S8) align 1)
|
|||
; ASM-NEXT: ld 3, 0([[REGADDR]])
|
||||
; ASM-NEXT: bl .test_byval_8Byte
|
||||
; ASM-NEXT: nop
|
||||
|
||||
|
||||
define zeroext i8 @test_byval_8Byte(%struct.S8* byval(%struct.S8) align 1 %s) {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.S8, %struct.S8* %s, i32 0, i32 0, i32 7
|
||||
%0 = load i8, i8* %arrayidx, align 1
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_byval_8Byte
|
||||
|
||||
; CHECK: fixedStack:
|
||||
; CHECK-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16,
|
||||
; CHECK: bb.0.entry:
|
||||
; CHECK-NEXT: liveins: $x3
|
||||
; CHECK: renamable $x[[SCRATCH:[0-9]+]] = COPY $x3
|
||||
; CHECK-DAG: renamable $x3 = RLDICL $x3, 0, 56
|
||||
; CHECK-DAG: STD killed renamable $x[[SCRATCH]], 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16)
|
||||
|
||||
|
||||
; CHECKASM-LABEL: .test_byval_8Byte:
|
||||
|
||||
; ASM: mr [[SCRATCH:[0-9]+]], 3
|
||||
; ASM-DAG: clrldi 3, 3, 56
|
||||
; ASM-DAG: std [[SCRATCH]], 48(1)
|
||||
; ASM-NEXT: blr
|
||||
|
|
Loading…
Reference in New Issue