From 2a3cf5e5834302a9525a721627c17902399b8d62 Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Wed, 15 Apr 2020 09:58:22 -0400 Subject: [PATCH] [PowerPC][AIX] Pass ByVal formal args that span registers and stack. Implement passing of ByVal formal arguments when the argument is passed partly in the argument registers, with the remainder of the argument passed on the stack. Differential Revision: https://reviews.llvm.org/D78515 --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 22 ++-- .../PowerPC/aix-cc-byval-limitation1.ll | 11 -- llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll | 105 +++++++++++++++++- .../CodeGen/PowerPC/aix-cc-byval-split.ll | 73 +++++++++++- 4 files changed, 182 insertions(+), 29 deletions(-) delete mode 100644 llvm/test/CodeGen/PowerPC/aix-cc-byval-limitation1.ll diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 69dca9b78cafe..ac2483cd1abd2 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -7232,20 +7232,24 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX( unsigned Offset = 0; HandleRegLoc(VA.getLocReg(), Offset); Offset += PtrByteSize; - for (; Offset != StackSize; Offset += PtrByteSize) { - assert(I != End && - "Expecting enough RegLocs to copy entire ByVal arg."); - - if (!ArgLocs[I].isRegLoc()) - report_fatal_error("Passing ByVals split between registers and stack " - "not yet implemented."); - + for (; Offset != StackSize && ArgLocs[I].isRegLoc(); + Offset += PtrByteSize) { assert(ArgLocs[I].getValNo() == VA.getValNo() && - "Expecting more RegLocs for ByVal argument."); + "RegLocs should be for ByVal argument."); const CCValAssign RL = ArgLocs[I++]; HandleRegLoc(RL.getLocReg(), Offset); } + + if (Offset != StackSize) { + assert(ArgLocs[I].getValNo() == VA.getValNo() && + "Expected MemLoc for remaining bytes."); + assert(ArgLocs[I].isMemLoc() && "Expected MemLoc for remaining bytes."); + // Consume the MemLoc.The InVal has already been emitted, so nothing + // more needs to be done. + ++I; + } + continue; } diff --git a/llvm/test/CodeGen/PowerPC/aix-cc-byval-limitation1.ll b/llvm/test/CodeGen/PowerPC/aix-cc-byval-limitation1.ll deleted file mode 100644 index eca919bee34bb..0000000000000 --- a/llvm/test/CodeGen/PowerPC/aix-cc-byval-limitation1.ll +++ /dev/null @@ -1,11 +0,0 @@ -; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s -; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s - -%struct.S = type { [65 x i8] } - -define void @foo(%struct.S* byval(%struct.S) align 1 %s) { -entry: - ret void -} - -; CHECK: LLVM ERROR: Passing ByVals split between registers and stack not yet implemented. diff --git a/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll b/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll index a87a5899b2935..3f24a43ad6b2c 100644 --- a/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll +++ b/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll @@ -176,8 +176,6 @@ entry: ret void } -declare void @test_byval_mem3(i32, float, %struct_S57* byval(%struct_S57) align 1) - ; CHECK-LABEL: name: call_test_byval_mem3 ; Confirm the expected memcpy call is independent of the call to test_byval_mem3. @@ -236,6 +234,53 @@ declare void @test_byval_mem3(i32, float, %struct_S57* byval(%struct_S57) align ; ASM64BIT: bl .test_byval_mem3 ; ASM64BIT: addi 1, 1, 128 +define void @test_byval_mem3(i32, float, %struct_S57* byval(%struct_S57) align 1 %s) { +entry: + ret void +} + + +;CHECK-LABEL: name: test_byval_mem3 + +; 32BIT: fixedStack: +; 32BIT-NEXT: - { id: 0, type: default, offset: 32, size: 60, alignment: 16, stack-id: default, + +; 32BIT: bb.0.entry: +; 32BIT-NEXT: liveins: $r5, $r6, $r7, $r8, $r9, $r10 + +; 32BIT-DAG: %2:gprc = COPY $r5 +; 32BIT-DAG: %3:gprc = COPY $r6 +; 32BIT-DAG: %4:gprc = COPY $r7 +; 32BIT-DAG: %5:gprc = COPY $r8 +; 32BIT-DAG: %6:gprc = COPY $r9 +; 32BIT-DAG: %7:gprc = COPY $r10 +; 32BIT-NEXT: STW %2, 0, %fixed-stack.0 :: (store 4 into %fixed-stack.0 +; 32BIT-DAG: STW %3, 4, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 4 +; 32BIT-DAG: STW %4, 8, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 8 +; 32BIT-DAG: STW %5, 12, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 12 +; 32BIT-DAG: STW %6, 16, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 16 +; 32BIT-DAG: STW %7, 20, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 20 +; 32BIT-NEXT: BLR implicit $lr, implicit $rm + +; 64BIT: fixedStack: +; 64BIT-NEXT: - { id: 0, type: default, offset: 64, size: 64, alignment: 16, stack-id: default, + +; 64BIT: bb.0.entry +; 64BIT-NEXT: liveins: $x5, $x6, $x7, $x8, $x9, $x10 + +; 64BIT-DAG: %2:g8rc = COPY $x5 +; 64BIT-DAG: %3:g8rc = COPY $x6 +; 64BIT-DAG: %4:g8rc = COPY $x7 +; 64BIT-DAG: %5:g8rc = COPY $x8 +; 64BIT-DAG: %6:g8rc = COPY $x9 +; 64BIT-DAG: %7:g8rc = COPY $x10 +; 64BIT-NEXT: STD %2, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0, align 16) +; 64BIT-DAG: STD %3, 8, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 8) +; 64BIT-DAG: STD %4, 16, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 16, align 16) +; 64BIT-DAG: STD %5, 24, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 24) +; 64BIT-DAG: STD %6, 32, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 32, align 16) +; 64BIT-DAG: STD %7, 40, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 40) +; 64BIT-NEXT: BLR8 implicit $lr8, implicit $rm %struct_S31 = type { [31 x i8] } @@ -247,7 +292,6 @@ entry: ret void } -declare void @test_byval_mem4(i32, %struct_S31* byval(%struct_S31) align 1, %struct_S256* byval(%struct_S256) align 1) ; CHECK-LABEL: name: call_test_byval_mem4 @@ -340,3 +384,58 @@ declare void @test_byval_mem4(i32, %struct_S31* byval(%struct_S31) align 1, %str ; ASM64BIT-DAG: ld 10, 16([[REG1]]) ; ASM64BIT: bl .test_byval_mem4 ; ASM64BIT: addi 1, 1, 352 + +define void @test_byval_mem4(i32, %struct_S31* byval(%struct_S31) align 1, %struct_S256* byval(%struct_S256) align 1 %s) { +entry: + ret void +} + +; CHECK-LABEL: name: test_byval_mem4 + +; 32BIT: fixedStack: +; 32BIT: - { id: 0, type: default, offset: 60, size: 256, alignment: 4, stack-id: default, +; 32BIT: - { id: 1, type: default, offset: 28, size: 32, alignment: 4, stack-id: default, +; 32BIT: stack: [] + +; 32BIT: bb.0.entry: +; 32BIT-NEXT: liveins: $r4, $r5, $r6, $r7, $r8, $r9, $r10 + +; 32BIT-DAG: %1:gprc = COPY $r4 +; 32BIT-DAG: %2:gprc = COPY $r5 +; 32BIT-DAG: %3:gprc = COPY $r6 +; 32BIT-DAG: %4:gprc = COPY $r7 +; 32BIT-DAG: %5:gprc = COPY $r8 +; 32BIT-DAG: %6:gprc = COPY $r9 +; 32BIT-DAG: %7:gprc = COPY $r10 +; 32BIT-NEXT: STW %1, 0, %fixed-stack.1 :: (store 4 into %fixed-stack.1 +; 32BIT-DAG: STW %2, 4, %fixed-stack.1 :: (store 4 into %fixed-stack.1 + 4 +; 32BIT-DAG: STW %3, 8, %fixed-stack.1 :: (store 4 into %fixed-stack.1 + 8 +; 32BIT-DAG: STW %4, 12, %fixed-stack.1 :: (store 4 into %fixed-stack.1 + 12 +; 32BIT-DAG: STW %5, 16, %fixed-stack.1 :: (store 4 into %fixed-stack.1 + 16 +; 32BIT-DAG: STW %6, 20, %fixed-stack.1 :: (store 4 into %fixed-stack.1 + 20 +; 32BIT-DAG: STW %7, 24, %fixed-stack.1 :: (store 4 into %fixed-stack.1 + 24 +; 32BIT-NEXT: BLR implicit $lr, implicit $rm + +; 64BIT: fixedStack: +; 64BIT: - { id: 0, type: default, offset: 88, size: 256, alignment: 8, stack-id: default, +; 64BIT: - { id: 1, type: default, offset: 56, size: 32, alignment: 8, stack-id: default, +; 64BIT: stack: [] + +; 64BIT: bb.0.entry: +; 64BIT-NEXT: liveins: $x4, $x5, $x6, $x7, $x8, $x9, $x10 + +; 64BIT-DAG: %1:g8rc = COPY $x4 +; 64BIT-DAG: %2:g8rc = COPY $x5 +; 64BIT-DAG: %3:g8rc = COPY $x6 +; 64BIT-DAG: %4:g8rc = COPY $x7 +; 64BIT-DAG: %5:g8rc = COPY $x8 +; 64BIT-DAG: %6:g8rc = COPY $x9 +; 64BIT-DAG: %7:g8rc = COPY $x10 +; 64BIT-NEXT: STD %1, 0, %fixed-stack.1 :: (store 8 into %fixed-stack.1 +; 64BIT-DAG: STD %2, 8, %fixed-stack.1 :: (store 8 into %fixed-stack.1 + 8 +; 64BIT-DAG: STD %3, 16, %fixed-stack.1 :: (store 8 into %fixed-stack.1 + 16 +; 64BIT-DAG: STD %4, 24, %fixed-stack.1 :: (store 8 into %fixed-stack.1 + 24 +; 64BIT-DAG: STD %5, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0 +; 64BIT-DAG: STD %6, 8, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 8 +; 64BIT-DAG: STD %7, 16, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 16 +; 64BIT-NEXT: BLR8 implicit $lr8, implicit $rm diff --git a/llvm/test/CodeGen/PowerPC/aix-cc-byval-split.ll b/llvm/test/CodeGen/PowerPC/aix-cc-byval-split.ll index 535998af9190f..e9155f236c9e1 100644 --- a/llvm/test/CodeGen/PowerPC/aix-cc-byval-split.ll +++ b/llvm/test/CodeGen/PowerPC/aix-cc-byval-split.ll @@ -1,10 +1,10 @@ -; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff -stop-after=machine-cp \ -; RUN: -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs 2>&1 < %s | FileCheck %s +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -stop-after=machine-cp \ +; RUN: -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs 2>&1 < %s | \ +; RUN: FileCheck --check-prefix=CHECK32 %s -; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff -stop-after=machine-cp \ -; RUN: -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs 2>&1 < %s | FileCheck %s - -; CHECK: LLVM ERROR: Passing ByVals split between registers and stack not yet implemented. +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -stop-after=machine-cp \ +; RUN: -mcpu=pwr4 -mattr=-altivec -verify-machineinstrs 2>&1 < %s | \ +; RUN: FileCheck --check-prefix=CHECK64 %s %struct.Spill = type { [12 x i64 ] } @GS = external global %struct.Spill, align 4 @@ -18,3 +18,64 @@ entry: %add = add i64 %a, %b ret i64 %add } + +; CHECK32: name: test +; CHECK32: liveins: +; CHECK32: - { reg: '$r3', virtual-reg: '' } +; CHECK32: - { reg: '$r4', virtual-reg: '' } +; CHECK32: - { reg: '$r5', virtual-reg: '' } +; CHECK32: - { reg: '$r6', virtual-reg: '' } +; CHECK32: - { reg: '$r7', virtual-reg: '' } +; CHECK32: - { reg: '$r8', virtual-reg: '' } +; CHECK32: - { reg: '$r9', virtual-reg: '' } +; CHECK32: - { reg: '$r10', virtual-reg: '' } +; CHECK32: fixedStack: +; CHECK32: - { id: 0, type: default, offset: 24, size: 96, alignment: 8, stack-id: default, +; CHECK32: stack: [] + +; CHECK32: bb.0.entry: +; CHECK32-NEXT: liveins: $r3, $r4, $r5, $r6, $r7, $r8, $r9, $r10 + +; CHECK32-DAG: STW killed renamable $r3, 0, %fixed-stack.0 :: (store 4 into %fixed-stack.0 +; CHECK32-DAG: STW killed renamable $r4, 4, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 4 +; CHECK32-DAG: STW killed renamable $r5, 8, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 8 +; CHECK32-DAG: STW killed renamable $r6, 12, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 12 +; CHECK32-DAG: STW renamable $r7, 16, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 16 +; CHECK32-DAG: STW renamable $r8, 20, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 20 +; CHECK32-DAG: STW killed renamable $r9, 24, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 24 +; CHECK32-DAG: STW killed renamable $r10, 28, %fixed-stack.0 :: (store 4 into %fixed-stack.0 + 28 +; CHECK32: renamable $r[[REG1:[0-9]+]] = LWZ 84, %fixed-stack.0 +; CHECK32: renamable $r[[REG2:[0-9]+]] = LWZ 80, %fixed-stack.0 +; CHECK32: renamable $r4 = ADDC killed renamable $r8, killed renamable $r[[REG1]], implicit-def $carry +; CHECK32: renamable $r3 = ADDE killed renamable $r7, killed renamable $r[[REG2]], implicit-def dead $carry, implicit killed $carry +; CHECK32: BLR implicit $lr, implicit $rm, implicit $r3, implicit $r4 + + +; CHECK64: name: test +; CHECK64: liveins: +; CHECK64: - { reg: '$x3', virtual-reg: '' } +; CHECK64: - { reg: '$x4', virtual-reg: '' } +; CHECK64: - { reg: '$x5', virtual-reg: '' } +; CHECK64: - { reg: '$x6', virtual-reg: '' } +; CHECK64: - { reg: '$x7', virtual-reg: '' } +; CHECK64: - { reg: '$x8', virtual-reg: '' } +; CHECK64: - { reg: '$x9', virtual-reg: '' } +; CHECK64: - { reg: '$x10', virtual-reg: '' } +; CHECK64: fixedStack: +; CHECK64: - { id: 0, type: default, offset: 48, size: 96, alignment: 16, stack-id: default, +; CHECK64: stack: [] + +; CHECK64: bb.0.entry: +; CHECK64: liveins: $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10 + +; CHECK64: STD killed renamable $x3, 0, %fixed-stack.0 :: (store 8 into %fixed-stack.0 +; CHECK64: STD killed renamable $x4, 8, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 8 +; CHECK64: STD renamable $x5, 16, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 16 +; CHECK64: STD killed renamable $x6, 24, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 24 +; CHECK64: STD killed renamable $x7, 32, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 32 +; CHECK64: STD killed renamable $x8, 40, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 40 +; CHECK64: STD killed renamable $x9, 48, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 48 +; CHECK64: STD killed renamable $x10, 56, %fixed-stack.0 :: (store 8 into %fixed-stack.0 + 56 +; CHECK64: renamable $x[[REG1:[0-9]+]] = LD 80, %fixed-stack.0 +; CHECK64: renamable $x3 = ADD8 killed renamable $x5, killed renamable $x[[REG1]] +; CHECK64: BLR8 implicit $lr8, implicit $rm, implicit $x3