diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -6978,6 +6978,30 @@ return DAG.getNode(ISD::TRUNCATE, dl, ValVT, ArgValue); } +static unsigned roundToMultiple(unsigned Size, unsigned Multiple) { + // Round up. + unsigned Count = (Size + Multiple - 1) / Multiple; + return Count * Multiple; +} + +static unsigned mapArgRegToOffsetAIX(unsigned Reg, const PPCFrameLowering *FL) { + 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 &Ins, const SDLoc &dl, @@ -7015,12 +7039,12 @@ CCInfo.AllocateStack(LinkageSize, PtrByteSize); CCInfo.AnalyzeFormalArguments(Ins, CC_AIX); + SmallVector 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 +7057,47 @@ if (VA.isMemLoc() && VA.needsCustom()) continue; + if (Flags.isByVal()) { + if (!VA.isRegLoc()) + report_fatal_error( + "ByVal arguments passed on stack not implemented yet."); + + // First create the FrameIndex for the object, and add it to the In vals. + const unsigned TrueSize = Flags.getByValSize(); + const unsigned StackSize = roundToMultiple(TrueSize, PtrByteSize); + + if (TrueSize > 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); + + int FI = MF.getFrameInfo().CreateFixedObject( + StackSize, Offset, /* IsImmutable */ false, /* IsAliased */ true); + SDValue FrameIndex = DAG.getFrameIndex(FI, PtrVT); + + InVals.push_back(FrameIndex); + + // For zero sized ByVals no more is needed. + if (TrueSize == 0) + continue; + + 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. + SDValue CopyFrom = DAG.getCopyFromReg(Chain, dl, VReg, LocVT); + SDValue Store = + DAG.getStore(CopyFrom.getValue(1), dl, CopyFrom, FrameIndex, + MachinePointerInfo::getFixedStack(MF, FI, 0)); + + MemOps.push_back(Store); + continue; + } + if (VA.isRegLoc()) { MVT::SimpleValueType SVT = ValVT.getSimpleVT().SimpleTy; unsigned VReg = @@ -7080,6 +7145,9 @@ PPCFunctionInfo *FuncInfo = MF.getInfo(); FuncInfo->setMinReservedArea(CallerReservedArea); + if (!MemOps.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps); + return Chain; } diff --git a/llvm/test/CodeGen/PowerPC/aix-cc-byval.ll b/llvm/test/CodeGen/PowerPC/aix-cc-byval.ll --- a/llvm/test/CodeGen/PowerPC/aix-cc-byval.ll +++ b/llvm/test/CodeGen/PowerPC/aix-cc-byval.ll @@ -3,26 +3,24 @@ ; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec \ ; RUN: -mtriple powerpc-ibm-aix-xcoff < %s | \ -; RUN: FileCheck --check-prefixes=CHECKASM,ASM32PWR4 %s +; RUN: FileCheck --check-prefixes=CHECKASM,ASM32 %s ; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -stop-after=machine-cp -verify-machineinstrs < %s | \ ; RUN: FileCheck --check-prefixes=CHECK,64BIT %s ; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec \ ; RUN: -mtriple powerpc64-ibm-aix-xcoff < %s | \ -; RUN: FileCheck --check-prefixes=CHECKASM,ASM64PWR4 %s +; RUN: FileCheck --check-prefixes=CHECKASM,ASM64 %s %struct.S1 = type { [1 x i8] } @gS1 = external global %struct.S1, align 1 define void @call_test_byval_1Byte() { entry: - call void @test_byval_1Byte(%struct.S1* byval(%struct.S1) align 1 @gS1) + %call = call zeroext i8 @test_byval_1Byte(%struct.S1* byval(%struct.S1) align 1 @gS1) ret void } -declare void @test_byval_1Byte(%struct.S1* byval(%struct.S1) align 1) - ; CHECK-LABEL: name: call_test_byval_1Byte{{.*}} ; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 @@ -34,13 +32,13 @@ ; CHECKASM-LABEL: .call_test_byval_1Byte: -; ASM32PWR4: stwu 1, -64(1) -; ASM32PWR4-NEXT: lwz [[REG:[0-9]+]], LC{{[0-9]+}}(2) -; ASM32PWR4-NEXT: lbz 3, 0([[REG]]) -; ASM32PWR4-NEXT: slwi 3, 3, 24 -; ASM32PWR4-NEXT: bl .test_byval_1Byte -; ASM32PWR4-NEXT: nop -; ASM32PWR4-NEXT: addi 1, 1, 64 +; ASM32: stwu 1, -64(1) +; ASM32-NEXT: lwz [[REG:[0-9]+]], LC{{[0-9]+}}(2) +; ASM32-NEXT: lbz 3, 0([[REG]]) +; ASM32-NEXT: slwi 3, 3, 24 +; ASM32-NEXT: bl .test_byval_1Byte +; ASM32-NEXT: nop +; ASM32-NEXT: addi 1, 1, 64 ; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 ; 64BIT-NEXT: renamable $x[[REG:[0-9]+]] = LDtoc @gS1, $x2 :: (load 8 from got) @@ -49,14 +47,49 @@ ; 64BIT-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 ; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 -; ASM64PWR4: std 0, 16(1) -; ASM64PWR4-NEXT: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REG:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-NEXT: lbz 3, 0([[REG]]) -; ASM64PWR4-NEXT: sldi 3, 3, 56 -; ASM64PWR4-NEXT: bl .test_byval_1Byte -; ASM64PWR4-NEXT: nop -; ASM64PWR4-NEXT: addi 1, 1, 112 +; ASM64: std 0, 16(1) +; ASM64-NEXT: stdu 1, -112(1) +; ASM64-NEXT: ld [[REG:[0-9]+]], LC{{[0-9]+}}(2) +; ASM64-NEXT: lbz 3, 0([[REG]]) +; ASM64-NEXT: sldi 3, 3, 56 +; ASM64-NEXT: bl .test_byval_1Byte +; ASM64-NEXT: nop +; ASM64-NEXT: addi 1, 1, 112 + +define zeroext i8 @test_byval_1Byte(%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, + +; 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 + +; 64BIT: fixedStack: +; 64BIT-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16, + +; 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] } @@ -64,12 +97,10 @@ 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 @@ -81,13 +112,13 @@ ; CHECKASM-LABEL: .call_test_byval_2Byte: -; ASM32PWR4: stwu 1, -64(1) -; ASM32PWR4-NEXT: lwz [[REG:[0-9]+]], LC{{[0-9]+}}(2) -; ASM32PWR4-NEXT: lhz 3, 0([[REG]]) -; ASM32PWR4-NEXT: slwi 3, 3, 16 -; ASM32PWR4-NEXT: bl .test_byval_2Byte -; ASM32PWR4-NEXT: nop -; ASM32PWR4-NEXT: addi 1, 1, 64 +; ASM32: stwu 1, -64(1) +; ASM32-NEXT: lwz [[REG:[0-9]+]], LC{{[0-9]+}}(2) +; ASM32-NEXT: lhz 3, 0([[REG]]) +; ASM32-NEXT: slwi 3, 3, 16 +; ASM32-NEXT: bl .test_byval_2Byte +; ASM32-NEXT: nop +; ASM32-NEXT: addi 1, 1, 64 ; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 ; 64BIT-NEXT: renamable $x[[REG:[0-9]+]] = LDtoc @gS2, $x2 :: (load 8 from got) @@ -96,14 +127,50 @@ ; 64BIT-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 ; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 -; ASM64PWR4: std 0, 16(1) -; ASM64PWR4-NEXT: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REG:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-NEXT: lhz 3, 0([[REG]]) -; ASM64PWR4-NEXT: sldi 3, 3, 48 -; ASM64PWR4-NEXT: bl .test_byval_2Byte -; ASM64PWR4-NEXT: nop -; ASM64PWR4-NEXT: addi 1, 1, 112 +; ASM64: std 0, 16(1) +; ASM64-NEXT: stdu 1, -112(1) +; ASM64-NEXT: ld [[REG:[0-9]+]], LC{{[0-9]+}}(2) +; ASM64-NEXT: lhz 3, 0([[REG]]) +; ASM64-NEXT: sldi 3, 3, 48 +; ASM64-NEXT: bl .test_byval_2Byte +; ASM64-NEXT: nop +; ASM64-NEXT: addi 1, 1, 112 + +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, + +; 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, + +; 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 { [3 x i8] } @@ -111,12 +178,10 @@ define void @call_test_byval_3Byte() { entry: - call void @test_byval_3Byte(%struct.S3* byval(%struct.S3) align 1 @gS3) + %call = call zeroext i8 @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. @@ -132,14 +197,14 @@ ; CHECKASM-LABEL: .call_test_byval_3Byte: ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; ASM32PWR4: stwu 1, -64(1) -; ASM32PWR4-NEXT: lwz [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) -; ASM32PWR4-DAG: lhz [[REG1:[0-9]+]], 0([[REGADDR]]) -; ASM32PWR4-DAG: lbz [[REG2:[0-9]+]], 2([[REGADDR]]) -; ASM32PWR4-DAG: rlwinm 3, [[REG2]], 8, 16, 23 -; ASM32PWR4-DAG: rlwimi 3, [[REG1]], 16, 0, 15 -; ASM32PWR4-NEXT: bl .test_byval_3Byte -; ASM32PWR4-NEXT: nop +; ASM32: stwu 1, -64(1) +; ASM32-NEXT: lwz [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) +; ASM32-DAG: lhz [[REG1:[0-9]+]], 0([[REGADDR]]) +; ASM32-DAG: lbz [[REG2:[0-9]+]], 2([[REGADDR]]) +; ASM32-DAG: rlwinm 3, [[REG2]], 8, 16, 23 +; ASM32-DAG: rlwimi 3, [[REG1]], 16, 0, 15 +; ASM32-NEXT: bl .test_byval_3Byte +; ASM32-NEXT: nop ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. ; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 @@ -152,14 +217,51 @@ ; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; ASM64PWR4: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-DAG: lhz [[REG1:[0-9]+]], 0([[REGADDR]]) -; ASM64PWR4-DAG: lbz [[REG2:[0-9]+]], 2([[REGADDR]]) -; ASM64PWR4-DAG: rldic 3, [[REG2]], 40, 16 -; ASM64PWR4-DAG: rldimi 3, [[REG1]], 48, 0 -; ASM64PWR4-NEXT: bl .test_byval_3Byte -; ASM64PWR4-NEXT: nop +; ASM64: stdu 1, -112(1) +; ASM64-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) +; ASM64-DAG: lhz [[REG1:[0-9]+]], 0([[REGADDR]]) +; ASM64-DAG: lbz [[REG2:[0-9]+]], 2([[REGADDR]]) +; ASM64-DAG: rldic 3, [[REG2]], 40, 16 +; ASM64-DAG: rldimi 3, [[REG1]], 48, 0 +; ASM64-NEXT: bl .test_byval_3Byte +; ASM64-NEXT: nop + + +define zeroext i8 @test_byval_3Byte(%struct.S3* byval(%struct.S3) align 1 %s) { +entry: + %arrayidx = getelementptr inbounds %struct.S3, %struct.S3* %s, i32 0, i32 0, i32 2 + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} + +; CHECK-LABEL: name: test_byval_3Byte + +; 32BIT: fixedStack: +; 32BIT-NEXT: - { id: 0, type: default, offset: 24, size: 4, alignment: 8, + +; 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 2, %fixed-stack.0 :: (dereferenceable load 1 + +; 64BIT: fixedStack: +; 64BIT-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16, + +; 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 2, %fixed-stack.0 :: (dereferenceable load 1 + + +; CHECKASM-LABEL: .test_byval_3Byte: + +; ASM32: stw 3, 24(1) +; ASM32-NEXT: lbz 3, 26(1) +; ASM32-NEXT: blr + +; ASM64: std 3, 48(1) +; ASM64-NEXT: lbz 3, 50(1) +; ASM64-NEXT: blr %struct.S4 = type { [4 x i8] } @@ -167,12 +269,10 @@ define void @call_test_byval_4Byte() { entry: - call void @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1 @gS4) + %call = call zeroext i8 @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1 @gS4) ret void } -declare void @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1) - ; CHECK-LABEL: name: call_test_byval_4Byte{{.*}} ; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 @@ -183,12 +283,12 @@ ; CHECKASM-LABEL: .call_test_byval_4Byte: -; ASM32PWR4: stwu 1, -64(1) -; ASM32PWR4-NEXT: lwz [[REG:[0-9]+]], LC{{[0-9]+}}(2) -; ASM32PWR4-NEXT: lwz 3, 0([[REG]]) -; ASM32PWR4-NEXT: bl .test_byval_4Byte -; ASM32PWR4-NEXT: nop -; ASM32PWR4-NEXT: addi 1, 1, 64 +; ASM32: stwu 1, -64(1) +; ASM32-NEXT: lwz [[REG:[0-9]+]], LC{{[0-9]+}}(2) +; ASM32-NEXT: lwz 3, 0([[REG]]) +; ASM32-NEXT: bl .test_byval_4Byte +; ASM32-NEXT: nop +; ASM32-NEXT: addi 1, 1, 64 ; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 ; 64BIT-NEXT: renamable $x[[REG:[0-9]+]] = LDtoc @gS4, $x2 :: (load 8 from got) @@ -197,10 +297,48 @@ ; 64BIT-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 ; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 -; ASM64PWR4: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REG:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-NEXT: lwz 3, 0([[REG]]) -; ASM64PWR4-NEXT: sldi 3, 3, 32 -; ASM64PWR4-NEXT: bl .test_byval_4Byte -; ASM64PWR4-NEXT: nop -; ASM64PWR4-NEXT: addi 1, 1, 112 +; ASM64: stdu 1, -112(1) +; ASM64-NEXT: ld [[REG:[0-9]+]], LC{{[0-9]+}}(2) +; ASM64-NEXT: lwz 3, 0([[REG]]) +; ASM64-NEXT: sldi 3, 3, 32 +; ASM64-NEXT: bl .test_byval_4Byte +; ASM64-NEXT: nop +; ASM64-NEXT: addi 1, 1, 112 + +define zeroext i8 @test_byval_4Byte(%struct.S4* byval(%struct.S4) align 1 %s) { +entry: + %arrayidx = getelementptr inbounds %struct.S4, %struct.S4* %s, i32 0, i32 0, i32 3 + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} + +; CHECK-LABEL: name: test_byval_4Byte + +; 32BIT: fixedStack: +; 32BIT-NEXT: - { id: 0, type: default, offset: 24, size: 4, alignment: 8, + +; 32BIT: bb.0.entry: +; 32BIT-NEXT: liveins: $r3 +; 32BIT-DAG: renamable $r[[SCRATCH:[0-9]+]] = COPY $r3 +; 32BIT-DAG: renamable $r3 = RLWINM $r3, 0, 24, 31 +; 32BIT-NEXT: STW killed renamable $r[[SCRATCH]], 0, %fixed-stack.0 :: (store 4 into %fixed-stack.0, align 8) + +; 64BIT: fixedStack: +; 64BIT-NEXT: - { id: 0, type: default, offset: 48, size: 8, alignment: 16, + +; 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 3, %fixed-stack.0 :: (dereferenceable load 1 + +; CHECKASM-LABEL: .test_byval_4Byte: + +; ASM32: mr [[SCRATCH:[0-9]+]], 3 +; ASM32-NEXT: clrlwi 3, 3, 24 +; ASM32-NEXT: stw [[SCRATCH]], 24(1) +; ASM32-NEXT: blr + +; ASM64: std 3, 48(1) +; ASM64-NEXT: lbz 3, 51(1) +; ASM64-NEXT: blr + diff --git a/llvm/test/CodeGen/PowerPC/aix64-cc-byval.ll b/llvm/test/CodeGen/PowerPC/aix64-cc-byval.ll --- a/llvm/test/CodeGen/PowerPC/aix64-cc-byval.ll +++ b/llvm/test/CodeGen/PowerPC/aix64-cc-byval.ll @@ -1,9 +1,9 @@ ; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -stop-after=machine-cp -verify-machineinstrs < %s | \ -; RUN: FileCheck --check-prefixes=CHECK,64BIT %s +; RUN: FileCheck %s ; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec \ ; RUN: -mtriple powerpc64-ibm-aix-xcoff < %s | \ -; RUN: FileCheck --check-prefixes=CHECKASM,ASM64PWR4 %s +; RUN: FileCheck --check-prefix=ASM %s %struct.S5 = type { [5 x i8] } @@ -11,35 +11,57 @@ 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{{.*}} -; CHECKASM-LABEL: .call_test_byval_5Byte: - ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 -; 64BIT-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS5, $x2 :: (load 8 from got) -; 64BIT-DAG: renamable $x[[REG1:[0-9]+]] = LWZ8 0, killed renamable $x[[REGADDR]] :: (load 4) -; 64BIT-DAG: renamable $x[[REG2:[0-9]+]] = LBZ8 4, renamable $x[[REGADDR]] :: (load 1) -; 64BIT-DAG: renamable $x3 = RLWINM8 killed renamable $x[[REG2]], 24, 0, 7 -; 64BIT-DAG: renamable $x3 = RLDIMI killed renamable $x3, killed renamable $x[[REG1]], 32, 0 -; 64BIT-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 -; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 +; CHECK: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; CHECK-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS5, $x2 :: (load 8 from got) +; CHECK-DAG: renamable $x[[REG1:[0-9]+]] = LWZ8 0, killed renamable $x[[REGADDR]] :: (load 4) +; CHECK-DAG: renamable $x[[REG2:[0-9]+]] = LBZ8 4, renamable $x[[REGADDR]] :: (load 1) +; CHECK-DAG: renamable $x3 = RLWINM8 killed renamable $x[[REG2]], 24, 0, 7 +; CHECK-DAG: renamable $x3 = RLDIMI killed renamable $x3, killed renamable $x[[REG1]], 32, 0 +; CHECK-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; CHECK-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + +; ASM-LABEL: .call_test_byval_5Byte: ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; ASM64PWR4: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-DAG: lwz [[REG1:[0-9]+]], 0([[REGADDR]]) -; ASM64PWR4-DAG: lbz [[REG2:[0-9]+]], 4([[REGADDR]]) -; ASM64PWR4-DAG: rlwinm 3, [[REG2]], 24, 0, 7 -; ASM64PWR4-DAG: rldimi 3, [[REG1]], 32, 0 -; ASM64PWR4-NEXT: bl .test_byval_5Byte -; ASM64PWR4-NEXT: nop +; ASM: stdu 1, -112(1) +; ASM-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) +; ASM-DAG: lwz [[REG1:[0-9]+]], 0([[REGADDR]]) +; ASM-DAG: lbz [[REG2:[0-9]+]], 4([[REGADDR]]) +; ASM-DAG: rlwinm 3, [[REG2]], 24, 0, 7 +; ASM-DAG: rldimi 3, [[REG1]], 32, 0 +; 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] } @@ -47,35 +69,56 @@ 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{{.*}} -; CHECKASM-LABEL: .call_test_byval_6Byte: - ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 -; 64BIT-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS6, $x2 :: (load 8 from got) -; 64BIT-DAG: renamable $x[[REG1:[0-9]+]] = LWZ8 0, killed renamable $x[[REGADDR]] :: (load 4) -; 64BIT-DAG: renamable $x[[REG2:[0-9]+]] = LHZ8 4, renamable $x[[REGADDR]] :: (load 2) -; 64BIT-DAG: renamable $x3 = RLWINM8 killed renamable $x[[REG2]], 16, 0, 15 -; 64BIT-DAG: renamable $x3 = RLDIMI killed renamable $x3, killed renamable $x[[REG1]], 32, 0 -; 64BIT-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 -; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 +; CHECK: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; CHECK-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS6, $x2 :: (load 8 from got) +; CHECK-DAG: renamable $x[[REG1:[0-9]+]] = LWZ8 0, killed renamable $x[[REGADDR]] :: (load 4) +; CHECK-DAG: renamable $x[[REG2:[0-9]+]] = LHZ8 4, renamable $x[[REGADDR]] :: (load 2) +; CHECK-DAG: renamable $x3 = RLWINM8 killed renamable $x[[REG2]], 16, 0, 15 +; CHECK-DAG: renamable $x3 = RLDIMI killed renamable $x3, killed renamable $x[[REG1]], 32, 0 +; CHECK-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; CHECK-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + +; ASM-LABEL: .call_test_byval_6Byte: ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; ASM64PWR4: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-DAG: lwz [[REG1:[0-9]+]], 0([[REGADDR]]) -; ASM64PWR4-DAG: lhz [[REG2:[0-9]+]], 4([[REGADDR]]) -; ASM64PWR4-DAG: rlwinm 3, [[REG2]], 16, 0, 15 -; ASM64PWR4-DAG: rldimi 3, [[REG1]], 32, 0 -; ASM64PWR4-NEXT: bl .test_byval_6Byte -; ASM64PWR4-NEXT: nop +; ASM: stdu 1, -112(1) +; ASM-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) +; ASM-DAG: lwz [[REG1:[0-9]+]], 0([[REGADDR]]) +; ASM-DAG: lhz [[REG2:[0-9]+]], 4([[REGADDR]]) +; ASM-DAG: rlwinm 3, [[REG2]], 16, 0, 15 +; ASM-DAG: rldimi 3, [[REG1]], 32, 0 +; 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] } @@ -83,39 +126,60 @@ 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{{.*}} -; CHECKASM-LABEL: .call_test_byval_7Byte: - ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 -; 64BIT-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS7, $x2 :: (load 8 from got) -; 64BIT-DAG: renamable $x[[REG1:[0-9]+]] = LWZ8 0, killed renamable $x[[REGADDR]] :: (load 4) -; 64BIT-DAG: renamable $x[[REG2:[0-9]+]] = LHZ8 4, renamable $x[[REGADDR]] :: (load 2) -; 64BIT-DAG: renamable $x[[REG3:[0-9]+]] = LBZ8 6, renamable $x[[REGADDR]] :: (load 1) -; 64BIT-DAG: renamable $x3 = RLWINM8 killed renamable $x[[REG3]], 8, 16, 23 -; 64BIT-DAG: renamable $x3 = RLWIMI8 killed renamable $x3, killed renamable $x[[REG2]], 16, 0, 15 -; 64BIT-DAG: renamable $x3 = RLDIMI killed renamable $x3, killed renamable $x[[REG1]], 32, 0 -; 64BIT-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 -; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 +; CHECK: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; CHECK-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS7, $x2 :: (load 8 from got) +; CHECK-DAG: renamable $x[[REG1:[0-9]+]] = LWZ8 0, killed renamable $x[[REGADDR]] :: (load 4) +; CHECK-DAG: renamable $x[[REG2:[0-9]+]] = LHZ8 4, renamable $x[[REGADDR]] :: (load 2) +; CHECK-DAG: renamable $x[[REG3:[0-9]+]] = LBZ8 6, renamable $x[[REGADDR]] :: (load 1) +; CHECK-DAG: renamable $x3 = RLWINM8 killed renamable $x[[REG3]], 8, 16, 23 +; CHECK-DAG: renamable $x3 = RLWIMI8 killed renamable $x3, killed renamable $x[[REG2]], 16, 0, 15 +; CHECK-DAG: renamable $x3 = RLDIMI killed renamable $x3, killed renamable $x[[REG1]], 32, 0 +; CHECK-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; CHECK-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + +; ASM-LABEL: .call_test_byval_7Byte: ; The DAG block permits some invalid inputs for the benefit of allowing more valid orderings. -; ASM64PWR4: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-DAG: lwz [[REG1:[0-9]+]], 0([[REGADDR]]) -; ASM64PWR4-DAG: lhz [[REG2:[0-9]+]], 4([[REGADDR]]) -; ASM64PWR4-DAG: lbz [[REG3:[0-9]+]], 6([[REGADDR]]) -; ASM64PWR4-DAG: rlwinm 3, [[REG3]], 8, 16, 23 -; ASM64PWR4-DAG: rlwimi 3, [[REG2]], 16, 0, 15 -; ASM64PWR4-DAG: rldimi 3, [[REG1]], 32, 0 -; ASM64PWR4-NEXT: bl .test_byval_7Byte -; ASM64PWR4-NEXT: nop +; ASM: stdu 1, -112(1) +; ASM-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) +; ASM-DAG: lwz [[REG1:[0-9]+]], 0([[REGADDR]]) +; ASM-DAG: lhz [[REG2:[0-9]+]], 4([[REGADDR]]) +; ASM-DAG: lbz [[REG3:[0-9]+]], 6([[REGADDR]]) +; ASM-DAG: rlwinm 3, [[REG3]], 8, 16, 23 +; ASM-DAG: rlwimi 3, [[REG2]], 16, 0, 15 +; ASM-DAG: rldimi 3, [[REG1]], 32, 0 +; 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] } @@ -123,24 +187,47 @@ 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{{.*}} +; CHECK: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; CHECK-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS8, $x2 :: (load 8 from got) +; CHECK-NEXT: renamable $x3 = LD 0, killed renamable $x[[REGADDR]] :: (load 8) +; CHECK-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; CHECK-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + ; CHECKASM-LABEL: .call_test_byval_8Byte: -; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 -; 64BIT-NEXT: renamable $x[[REGADDR:[0-9]+]] = LDtoc @gS8, $x2 :: (load 8 from got) -; 64BIT-NEXT: renamable $x3 = LD 0, killed renamable $x[[REGADDR]] :: (load 8) -; 64BIT-NEXT: BL8_NOP , csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 -; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 - -; ASM64PWR4: stdu 1, -112(1) -; ASM64PWR4-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) -; ASM64PWR4-NEXT: ld 3, 0([[REGADDR]]) -; ASM64PWR4-NEXT: bl .test_byval_8Byte -; ASM64PWR4-NEXT: nop +; ASM: stdu 1, -112(1) +; ASM-NEXT: ld [[REGADDR:[0-9]+]], LC{{[0-9]+}}(2) +; 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