diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -27,6 +27,7 @@ #include "PPCTargetStreamer.h" #include "TargetInfo/PowerPCTargetInfo.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" @@ -47,6 +48,7 @@ #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" @@ -147,6 +149,9 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter { private: + /// Symbols lowered from ExternalSymbolSDNodes. + SmallPtrSet ExtSymSDNodeSymbols; + static void ValidateGV(const GlobalVariable *GV); public: @@ -168,6 +173,10 @@ void emitFunctionDescriptor() override; void emitEndOfAsmFile(Module &) override; + + void emitInstruction(const MachineInstr *MI) override; + + bool doFinalization(Module &M) override; }; } // end anonymous namespace @@ -1752,6 +1761,55 @@ return Result; } +void PPCAIXAsmPrinter::emitInstruction(const MachineInstr *MI) { + switch (MI->getOpcode()) { + default: + break; + case PPC::BL8: + case PPC::BL: + case PPC::BL8_NOP: + case PPC::BL_NOP: { + const MachineOperand &MO = MI->getOperand(0); + if (MO.isSymbol()) { + MCSymbolXCOFF *S = + cast(OutContext.getOrCreateSymbol(MO.getSymbolName())); + if (!S->hasRepresentedCsectSet()) { + // On AIX, an undefined symbol needs to be associated with a + // MCSectionXCOFF to get the correct storage mapping class. + // In this case, XCOFF::XMC_PR. + MCSectionXCOFF *Sec = OutContext.getXCOFFSection( + S->getName(), XCOFF::XMC_PR, XCOFF::XTY_ER, XCOFF::C_EXT, + SectionKind::getMetadata()); + S->setRepresentedCsect(Sec); + } + ExtSymSDNodeSymbols.insert(S); + } + } break; + case PPC::BL_TLS: + case PPC::BL8_TLS: + case PPC::BL8_TLS_: + case PPC::BL8_NOP_TLS: + report_fatal_error("TLS call not yet implemented"); + case PPC::TAILB: + case PPC::TAILB8: + case PPC::TAILBA: + case PPC::TAILBA8: + case PPC::TAILBCTR: + case PPC::TAILBCTR8: + if (MI->getOperand(0).isSymbol()) + report_fatal_error("Tail call for extern symbol not yet implemented."); + break; + } + return PPCAsmPrinter::emitInstruction(MI); +} + +bool PPCAIXAsmPrinter::doFinalization(Module &M) { + bool Ret = PPCAsmPrinter::doFinalization(M); + for (MCSymbol *Sym : ExtSymSDNodeSymbols) + OutStreamer->emitSymbolAttribute(Sym, MCSA_Extern); + return Ret; +} + /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code /// for a MachineFunction to the given output stream, in a format that the /// Darwin assembler can deal with. 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 @@ -5270,13 +5270,18 @@ // On AIX, direct function calls reference the symbol for the function's // entry point, which is named by prepending a "." before the function's // C-linkage name. + const auto getFunctionEntryPointSymbol = [&](StringRef SymName) { + auto &Context = DAG.getMachineFunction().getMMI().getContext(); + return cast( + Context.getOrCreateSymbol(Twine(".") + Twine(SymName))); + }; + const auto getAIXFuncEntryPointSymbolSDNode = [&](StringRef FuncName, bool IsDeclaration, const XCOFF::StorageClass &SC) { - auto &Context = DAG.getMachineFunction().getMMI().getContext(); + MCSymbolXCOFF *S = getFunctionEntryPointSymbol(FuncName); - MCSymbolXCOFF *S = cast( - Context.getOrCreateSymbol(Twine(".") + Twine(FuncName))); + auto &Context = DAG.getMachineFunction().getMMI().getContext(); if (IsDeclaration && !S->hasRepresentedCsectSet()) { // On AIX, an undefined symbol needs to be associated with a @@ -5311,22 +5316,21 @@ if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { const char *SymName = S->getSymbol(); - if (!Subtarget.isAIXABI()) - return DAG.getTargetExternalSymbol(SymName, Callee.getValueType(), - UsePlt ? PPCII::MO_PLT : 0); - - // If there exists a user-declared function whose name is the same as the - // ExternalSymbol's, then we pick up the user-declared version. - const Module *Mod = DAG.getMachineFunction().getFunction().getParent(); - if (const Function *F = - dyn_cast_or_null(Mod->getNamedValue(SymName))) { - const XCOFF::StorageClass SC = - TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F); - return getAIXFuncEntryPointSymbolSDNode(F->getName(), F->isDeclaration(), - SC); + if (Subtarget.isAIXABI()) { + // If there exists a user-declared function whose name is the same as the + // ExternalSymbol's, then we pick up the user-declared version. + const Module *Mod = DAG.getMachineFunction().getFunction().getParent(); + if (const Function *F = + dyn_cast_or_null(Mod->getNamedValue(SymName))) { + const XCOFF::StorageClass SC = + TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F); + return getAIXFuncEntryPointSymbolSDNode(F->getName(), + F->isDeclaration(), SC); + } + SymName = getFunctionEntryPointSymbol(SymName)->getName().data(); } - - return getAIXFuncEntryPointSymbolSDNode(SymName, true, XCOFF::C_EXT); + return DAG.getTargetExternalSymbol(SymName, Callee.getValueType(), + UsePlt ? PPCII::MO_PLT : 0); } // No transformation needed. diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -3202,9 +3202,13 @@ // Calls for AIX only def : Pat<(PPCcall (i32 mcsym:$dst)), (BL mcsym:$dst)>; + def : Pat<(PPCcall_nop (i32 mcsym:$dst)), (BL_NOP mcsym:$dst)>; +def : Pat<(PPCcall_nop (i32 texternalsym:$dst)), + (BL_NOP texternalsym:$dst)>; + def : Pat<(PPCtc_return (i32 tglobaladdr:$dst), imm:$imm), (TCRETURNdi tglobaladdr:$dst, imm:$imm)>; diff --git a/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll b/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll --- a/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll +++ b/llvm/test/CodeGen/PowerPC/aix-cc-byval-mem.ll @@ -88,7 +88,7 @@ ; 32BIT-DAG: $r3 = COPY %0 ; 32BIT-DAG: $r4 = COPY %1 ; 32BIT-DAG: $r5 = COPY %2 -; 32BIT-NEXT: BL_NOP , csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3 +; 32BIT-NEXT: BL_NOP &.memcpy, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3 ; 32BIT-NEXT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 ; 32BIT: ADJCALLSTACKDOWN 312, 0, implicit-def dead $r1, implicit $r1 ; 32BIT-DAG: $r3 = COPY %{{[0-9]+}} @@ -120,7 +120,7 @@ ; 64BIT-DAG: $x3 = COPY %0 ; 64BIT-DAG: $x4 = COPY %1 ; 64BIT-DAG: $x5 = COPY %2 -; 64BIT-NEXT: BL8_NOP , csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3 +; 64BIT-NEXT: BL8_NOP &.memcpy, csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3 ; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 ; 64BIT: ADJCALLSTACKDOWN 368, 0, implicit-def dead $r1, implicit $r1 ; 64BIT-DAG: $x3 = COPY %{{[0-9]+}} @@ -187,7 +187,7 @@ ; 32BIT-DAG: $r3 = COPY %2 ; 32BIT-DAG: $r4 = COPY %1 ; 32BIT-DAG: $r5 = COPY %3 -; 32BIT-NEXT: BL_NOP , csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3 +; 32BIT-NEXT: BL_NOP &.memcpy, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3 ; 32BIT-NEXT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 ; 32BIT: ADJCALLSTACKDOWN 92, 0, implicit-def dead $r1, implicit $r1 ; 32BIT-DAG: $r3 = COPY %{{[0-9]+}} @@ -305,7 +305,7 @@ ; 32BIT-DAG: $r3 = COPY %3 ; 32BIT-DAG: $r4 = COPY %4 ; 32BIT-DAG: $r5 = COPY %5 -; 32BIT-NEXT: BL_NOP , csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3 +; 32BIT-NEXT: BL_NOP &.memcpy, csr_aix32, implicit-def dead $lr, implicit $rm, implicit $r3, implicit $r4, implicit $r5, implicit $r2, implicit-def $r1, implicit-def $r3 ; 32BIT-NEXT: ADJCALLSTACKUP 56, 0, implicit-def dead $r1, implicit $r1 ; 32BIT: ADJCALLSTACKDOWN 316, 0, implicit-def dead $r1, implicit $r1 ; 32BIT-DAG: $r3 = COPY %{{[0-9]+}} @@ -349,7 +349,7 @@ ; 64BIT-DAG: $x3 = COPY %2 ; 64BIT-DAG: $x4 = COPY %1 ; 64BIT-DAG: $x5 = COPY %3 -; 64BIT-NEXT: BL8_NOP , csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3 +; 64BIT-NEXT: BL8_NOP &.memcpy, csr_ppc64, implicit-def dead $lr8, implicit $rm, implicit $x3, implicit $x4, implicit $x5, implicit $x2, implicit-def $r1, implicit-def $x3 ; 64BIT-NEXT: ADJCALLSTACKUP 112, 0, implicit-def dead $r1, implicit $r1 ; 64BIT: ADJCALLSTACKDOWN 344, 0, implicit-def dead $r1, implicit $r1 ; 64BIT-DAG: $x3 = COPY %{{[0-9]+}} diff --git a/llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll b/llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll --- a/llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll +++ b/llvm/test/CodeGen/PowerPC/aix-external-sym-sdnode-lowering.ll @@ -14,5 +14,5 @@ declare double @llvm.ceil.f64(double) -; 32BIT: BL_NOP -; 64BIT: BL8_NOP +; 32BIT: BL_NOP &.ceil +; 64BIT: BL8_NOP &.ceil diff --git a/llvm/test/CodeGen/PowerPC/aix-llvm-intrinsic.ll b/llvm/test/CodeGen/PowerPC/aix-llvm-intrinsic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-llvm-intrinsic.ll @@ -0,0 +1,66 @@ +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 -mattr=-altivec < %s | \ +; RUN: FileCheck %s + +; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr4 -mattr=-altivec < %s | \ +; RUN: FileCheck %s + +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -mattr=-altivec -filetype=obj -o %t.o < %s +; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefix=CHECKSYM %s +; RUN: llvm-readobj --relocations --expand-relocs %t.o | FileCheck --check-prefix=CHECKRELOC %s + +; RUN: not --crash llc -verify-machineinstrs -mcpu=pwr4 -mtriple powerpc64-ibm-aix-xcoff \ +; RUN: -mattr=-altivec -filetype=obj -o %t.o 2>&1 < %s | \ +; RUN: FileCheck --check-prefix=XCOFF64 %s +; XCOFF64: LLVM ERROR: 64-bit XCOFF object files are not supported yet. + +%struct.S = type { i32, i32 } + +@s = external global %struct.S, align 4 + +define void @bar() { +entry: + %0 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4 + %1 = trunc i32 %0 to i8 + %2 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4 + call void @llvm.memset.p0i8.i32(i8* align 4 bitcast (%struct.S* @s to i8*), i8 %1, i32 %2, i1 false) + ret void +} + +declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg) + +; CHECK: .bar: +; CHECK-NEXT: # %bb.0: # %entry +; CHECK-NEXT: mflr 0 +; CHECK: bl .memset + +; CHECK: .extern .memset + +; CHECKSYM: Symbol { +; CHECKSYM-NEXT: Index: 0 +; CHECKSYM-NEXT: Name: .memset +; CHECKSYM-NEXT: Value (RelocatableAddress): 0x0 +; CHECKSYM-NEXT: Section: N_UNDEF +; CHECKSYM-NEXT: Type: 0x0 +; CHECKSYM-NEXT: StorageClass: C_EXT (0x2) +; CHECKSYM-NEXT: NumberOfAuxEntries: 1 +; CHECKSYM-NEXT: CSECT Auxiliary Entry { +; CHECKSYM-NEXT: Index: 1 +; CHECKSYM-NEXT: SectionLen: 0 +; CHECKSYM-NEXT: ParameterHashIndex: 0x0 +; CHECKSYM-NEXT: TypeChkSectNum: 0x0 +; CHECKSYM-NEXT: SymbolAlignmentLog2: 0 +; CHECKSYM-NEXT: SymbolType: XTY_ER (0x0) +; CHECKSYM-NEXT: StorageMappingClass: XMC_PR (0x0) +; CHECKSYM-NEXT: StabInfoIndex: 0x0 +; CHECKSYM-NEXT: StabSectNum: 0x0 +; CHECKSYM-NEXT: } +; CHECKSYM-NEXT: } + +; CHECKRELOC: Relocation {{[{][[:space:]] *}}Virtual Address: 0x18 +; CHECKRELOC-NEXT: Symbol: .memset (0) +; CHECKRELOC-NEXT: IsSigned: Yes +; CHECKRELOC-NEXT: FixupBitValue: 0 +; CHECKRELOC-NEXT: Length: 26 +; CHECKRELOC-NEXT: Type: R_RBR (0x1A) +; CHECKRELOC-NEXT: } diff --git a/llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll b/llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll --- a/llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll +++ b/llvm/test/CodeGen/PowerPC/aix-user-defined-memcpy.ll @@ -8,6 +8,10 @@ ; RUN: llvm-objdump -D %t.o | FileCheck --check-prefix=32-DIS %s +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -mcpu=pwr4 -mattr=-altivec < %s | \ +; RUN: FileCheck %s + ; RUN: not --crash llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \ ; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj < %s 2>&1 | FileCheck \ ; RUN: --check-prefix=64-CHECK %s @@ -35,6 +39,8 @@ ; 2. There is no relocation associated with the call, since callee is defined. ; 3. Branch instruction in raw data is branching back to the right callee location. +; CHECK-NOT: .extern .memcpy + ; 32-SYM: Symbol {{[{][[:space:]] *}}Index: [[#Index:]]{{[[:space:]] *}}Name: .memcpy ; 32-SYM-NEXT: Value (RelocatableAddress): 0x0 ; 32-SYM-NEXT: Section: .text