Index: llvm/lib/Target/PowerPC/PPCISelLowering.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -4871,6 +4871,7 @@ bool isPPC64 = Subtarget.isPPC64(); bool isSVR4ABI = Subtarget.isSVR4ABI(); bool isELFv2ABI = Subtarget.isELFv2ABI(); + bool isAIXABI = Subtarget.isAIXABI(); EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); NodeTys.push_back(MVT::Other); // Returns a chain @@ -5049,17 +5050,18 @@ Ops.push_back(DAG.getRegister(RegsToPass[i].first, RegsToPass[i].second.getValueType())); - // All calls, in both the ELF V1 and V2 ABIs, need the TOC register live - // into the call. - // We do need to reserve X2 to appease the verifier for the PATCHPOINT. - if (isSVR4ABI && isPPC64) { + // All calls, in the AIX ABI and 64-bit ELF ABIs, need the TOC register + // live into the call. + // We do need to reserve R2/X2 to appease the verifier for the PATCHPOINT. + if ((isSVR4ABI && isPPC64) || isAIXABI) { setUsesTOCBasePtr(DAG); - // We cannot add X2 as an operand here for PATCHPOINT, because there is no - // way to mark dependencies as implicit here. We will add the X2 dependency - // in EmitInstrWithCustomInserter. + // We cannot add R2/X2 as an operand here for PATCHPOINT, because there is + // no way to mark dependencies as implicit here. + // We will add the R2/X2 dependency in EmitInstrWithCustomInserter. if (!isPatchPoint) - Ops.push_back(DAG.getRegister(PPC::X2, PtrVT)); + Ops.push_back(DAG.getRegister(isPPC64 ? PPC::X2 + : PPC::R2, PtrVT)); } return CallOpc; @@ -6596,9 +6598,6 @@ unsigned PtrByteSize = isPPC64 ? 8 : 4; unsigned NumOps = Outs.size(); - if (NumOps != 0) - report_fatal_error("Call lowering with parameters is not implemented " - "on AIX yet."); // Count how many bytes are to be pushed on the stack, including the linkage // area, parameter list area. @@ -6620,17 +6619,81 @@ Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl); SDValue CallSeqStart = Chain; - if (!isFunctionGlobalAddress(Callee) && - !isa(Callee)) - report_fatal_error("Handling of indirect call is unimplemented!"); + static const MCPhysReg GPR_32[] = { // 32-bit registers. + PPC::R3, PPC::R4, PPC::R5, PPC::R6, + PPC::R7, PPC::R8, PPC::R9, PPC::R10 + }; + static const MCPhysReg GPR_64[] = { // 64-bit registers. + PPC::X3, PPC::X4, PPC::X5, PPC::X6, + PPC::X7, PPC::X8, PPC::X9, PPC::X10 + }; + + const unsigned NumGPRs = isPPC64 ? array_lengthof(GPR_64) + : array_lengthof(GPR_32); + const MCPhysReg *GPR = isPPC64 ? GPR_64 : GPR_32; + unsigned GPR_idx = 0; SmallVector, 8> RegsToPass; - SDValue InFlag; if (isTailCall) report_fatal_error("Handling of tail call is unimplemented!"); int SPDiff = 0; + for (unsigned i = 0; i != NumOps; ++i) { + SDValue Arg = OutVals[i]; + ISD::ArgFlagsTy Flags = Outs[i].Flags; + + // Promote integers if needed. + if (Arg.getValueType() == MVT::i1 || + (isPPC64 && Arg.getValueType() == MVT::i32)) { + unsigned ExtOp = Flags.isSExt() ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; + Arg = DAG.getNode(ExtOp, dl, PtrVT, Arg); + } + + // Note: "by value" is code for passing a structure by value, not + // basic types. + if (Flags.isByVal()) + report_fatal_error("Passing structure by value is unimplemented!"); + + switch (Arg.getSimpleValueType().SimpleTy) { + default: llvm_unreachable("Unexpected ValueType for argument!"); + case MVT::i1: + case MVT::i32: + case MVT::i64: + if (GPR_idx != NumGPRs) + RegsToPass.push_back(std::make_pair(GPR[GPR_idx++], Arg)); + else + report_fatal_error("Handling of placing parameters on stack is " + "unimplemented!"); + break; + case MVT::f32: + case MVT::f64: + case MVT::v4f32: + case MVT::v4i32: + case MVT::v8i16: + case MVT::v16i8: + case MVT::v2f64: + case MVT::v2i64: + case MVT::v1i128: + case MVT::f128: + case MVT::v4f64: + case MVT::v4i1: + report_fatal_error("Handling of this parameter type is unimplemented!"); + } + } + + if (!isFunctionGlobalAddress(Callee) && + !isa(Callee)) + report_fatal_error("Handling of indirect call is unimplemented!"); + + // Build a sequence of copy-to-reg nodes chained together with token chain + // and flag operands which copy the outgoing args into the appropriate regs. + SDValue InFlag; + for (auto Reg : RegsToPass) { + Chain = DAG.getCopyToReg(Chain, dl, Reg.first, Reg.second, InFlag); + InFlag = Chain.getValue(1); + } + return FinishCall(CallConv, dl, isTailCall, isVarArg, isPatchPoint, /* unused except on PPC64 ELFv1 */ false, DAG, RegsToPass, InFlag, Chain, CallSeqStart, Callee, SPDiff, Index: llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -298,6 +298,11 @@ markSuperRegs(Reserved, PPC::R13); // Small Data Area pointer register } + // Always reserve r2 on AIX for now. + // TODO: Make r2 allocatable on AIX/XCOFF for some leaf functions. + if (Subtarget.isAIXABI()) + markSuperRegs(Reserved, PPC::R2); // System-reserved register + // On PPC64, r13 is the thread pointer. Never allocate this register. if (TM.isPPC64()) markSuperRegs(Reserved, PPC::R13); Index: llvm/test/CodeGen/PowerPC/aix_gpr_param.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/aix_gpr_param.ll @@ -0,0 +1,124 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -stop-after=machine-cp < %s | \ +; RUN: FileCheck --check-prefix=32BIT %s + +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -stop-after=machine-cp < %s | \ +; RUN: FileCheck --check-prefix=64BIT %s + +define void @test_call_gpr() { +entry: + %b = alloca i32, align 4 +; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 +; 32BIT: $r3 = LI 97 +; 32BIT: BL_NOP @test_char, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r2, implicit-def $r1 +; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 + +; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; 64BIT: $x3 = LI8 97 +; 64BIT: BL8_NOP @test_char, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + call void @test_char(i8 signext 97) + +; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 +; 32BIT: $r3 = LI 97 +; 32BIT: $r4 = LI 97 +; 32BIT: $r5 = LI 97 +; 32BIT: $r6 = LI 97 +; 32BIT: BL_NOP @test_chars, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit killed $r4, implicit killed $r5, implicit killed $r6, implicit $r2, implicit-def $r1 +; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 + +; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; 64BIT: $x3 = LI8 97 +; 64BIT: $x4 = LI8 97 +; 64BIT: $x5 = LI8 97 +; 64BIT: $x6 = LI8 97 +; 64BIT: BL8_NOP @test_chars, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit killed $x4, implicit killed $x5, implicit killed $x6, implicit $x2, implicit-def $r1 +; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + call void @test_chars(i8 signext 97, i8 signext 97, i8 signext 97, i8 signext 97) + +; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 +; 32BIT: $r3 = LI 1 +; 32BIT: BL_NOP @test_int, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r2, implicit-def $r1 +; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 + +; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; 64BIT: $x3 = LI8 1 +; 64BIT: BL8_NOP @test_int, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + call void @test_int(i32 1) + +; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 +; 32BIT: $r3 = LI 1 +; 32BIT: $r4 = LI 1 +; 32BIT: $r5 = LI 1 +; 32BIT: $r6 = LI 1 +; 32BIT: $r7 = LI 1 +; 32BIT: $r8 = LI 1 +; 32BIT: $r9 = LI 1 +; 32BIT: $r10 = LI 1 +; 32BIT: BL_NOP @test_ints, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit killed $r4, implicit killed $r5, implicit killed $r6, implicit killed $r7, implicit killed $r8, implicit killed $r9, implicit killed $r10, implicit $r2, implicit-def $r1 +; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 + +; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; 64BIT: $x3 = LI8 1 +; 64BIT: $x4 = LI8 1 +; 64BIT: $x5 = LI8 1 +; 64BIT: $x6 = LI8 1 +; 64BIT: $x7 = LI8 1 +; 64BIT: $x8 = LI8 1 +; 64BIT: $x9 = LI8 1 +; 64BIT: $x10 = LI8 1 +; 64BIT: BL8_NOP @test_ints, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit killed $x4, implicit killed $x5, implicit killed $x6, implicit killed $x7, implicit killed $x8, implicit killed $x9, implicit killed $x10, implicit $x2, implicit-def $r1 +; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + call void @test_ints(i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1) + +; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 +; 32BIT: $r3 = LI 1 +; 32BIT: BL_NOP @test_i1, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r2, implicit-def $r1 +; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 + +; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; 64BIT: $x3 = LI8 1 +; 64BIT: BL8_NOP @test_i1, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + call void @test_i1(i1 1) + +; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 +; 32BIT: $r3 = LI 0 +; 32BIT: $r4 = LI 1 +; 32BIT: BL_NOP @test_i64, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit killed $r4, implicit $r2, implicit-def $r1 +; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 + +; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; 64BIT: $x3 = LI8 1 +; 64BIT: BL8_NOP @test_i64, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + call void @test_i64(i64 1) + +; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 +; 32BIT: renamable $r3 = ADDI %stack.0.b, 0 +; 32BIT: BL_NOP @test_int_ptr, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r2, implicit-def $r1 +; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 + +; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 +; 64BIT: renamable $x3 = ADDI8 %stack.0.b, 0 +; 64BIT: BL8_NOP @test_int_ptr, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x2, implicit-def $r1 +; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 + store i32 0, i32* %b, align 4 + call void @test_int_ptr(i32* %b) + + ret void +} + +declare void @test_char(i8 signext) + +declare void @test_chars(i8 signext, i8 signext, i8 signext, i8 signext) + +declare void @test_int(i32) + +declare void @test_ints(i32, i32, i32, i32, i32, i32, i32, i32) + +declare void @test_i1(i1) + +declare void @test_i64(i64) + +declare void @test_int_ptr(i32*) Index: llvm/test/CodeGen/PowerPC/test_call_aix.ll =================================================================== --- llvm/test/CodeGen/PowerPC/test_call_aix.ll +++ llvm/test/CodeGen/PowerPC/test_call_aix.ll @@ -9,11 +9,11 @@ define void @test_call() { entry: ; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 -; 32BIT: BL_NOP @foo, csr_aix32, implicit-def dead $lr, implicit $rm, implicit-def $r1 +; 32BIT: BL_NOP @foo, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r2, implicit-def $r1 ; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 ; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 -; 64BIT: BL8_NOP @foo, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit-def $r1 +; 64BIT: BL8_NOP @foo, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x2, implicit-def $r1 ; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 call void bitcast (void (...)* @foo to void ()*)() @@ -28,11 +28,11 @@ define void @test_local_call() { entry: ; 32BIT: ADJCALLSTACKDOWN 56, 0, implicit-def dead $r1, implicit $r1 -; 32BIT: BL @foo_local, csr_aix32, implicit-def dead $lr, implicit $rm, implicit-def $r1 +; 32BIT: BL @foo_local, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r2, implicit-def $r1 ; 32BIT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 ; 64BIT: ADJCALLSTACKDOWN 112, 0, implicit-def dead $r1, implicit $r1 -; 64BIT: BL8 @foo_local, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit-def $r1 +; 64BIT: BL8 @foo_local, csr_aix64, implicit-def dead $lr8, implicit $rm, implicit $x2, implicit-def $r1 ; 64BIT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 call void @foo_local()