diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h --- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h +++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h @@ -174,6 +174,7 @@ void printModuleLevelGV(const GlobalVariable *GVar, raw_ostream &O, bool processDemoted, const NVPTXSubtarget &STI); void emitGlobals(const Module &M); + void emitGlobalAlias(const Module &M, const GlobalAlias &GA); void emitHeader(Module &M, raw_ostream &O, const NVPTXSubtarget &STI); void emitKernelFunctionDirectives(const Function &F, raw_ostream &O) const; void emitVirtualRegister(unsigned int vr, raw_ostream &); diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp --- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp @@ -473,6 +473,7 @@ CurrentFnSym->print(O, MAI); emitFunctionParamList(F, O); + O << "\n"; if (isKernelFunction(*F)) emitKernelFunctionDirectives(*F, O); @@ -623,6 +624,7 @@ getSymbol(F)->print(O, MAI); O << "\n"; emitFunctionParamList(F, O); + O << "\n"; if (shouldEmitPTXNoReturn(F, TM)) O << ".noreturn"; O << ";\n"; @@ -790,10 +792,12 @@ } bool NVPTXAsmPrinter::doInitialization(Module &M) { - if (M.alias_size()) { - report_fatal_error("Module has aliases, which NVPTX does not support."); - return true; // error - } + const NVPTXTargetMachine &NTM = static_cast(TM); + const NVPTXSubtarget &STI = + *static_cast(NTM.getSubtargetImpl()); + if (M.alias_size() && (STI.getPTXVersion() < 63 || STI.getSmVersion() < 30)) + report_fatal_error(".alias requires PTX version >= 6.3 and sm_30"); + if (!isEmptyXXStructor(M.getNamedGlobal("llvm.global_ctors")) && !LowerCtorDtor) { report_fatal_error( @@ -850,6 +854,32 @@ OutStreamer->emitRawText(OS2.str()); } +void NVPTXAsmPrinter::emitGlobalAlias(const Module &M, const GlobalAlias &GA) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + + MCSymbol *Name = getSymbol(&GA); + const Function *F = dyn_cast(GA.getAliasee()); + if (!F || isKernelFunction(*F)) + report_fatal_error("NVPTX aliasee must be a non-kernel function"); + + if (GA.hasLinkOnceLinkage() || GA.hasWeakLinkage() || + GA.hasAvailableExternallyLinkage() || GA.hasCommonLinkage()) + report_fatal_error("NVPTX aliasee must not be '.weak'"); + + OS << "\n"; + emitLinkageDirective(F, OS); + OS << ".func "; + printReturnValStr(F, OS); + OS << Name->getName(); + emitFunctionParamList(F, OS); + OS << ";\n"; + + OS << ".alias " << Name->getName() << ", " << F->getName() << ";\n"; + + OutStreamer->emitRawText(OS.str()); +} + void NVPTXAsmPrinter::emitHeader(Module &M, raw_ostream &O, const NVPTXSubtarget &STI) { O << "//\n"; @@ -906,6 +936,16 @@ GlobalsEmitted = true; } + // If we have any aliases we emit them at the end. + SmallVector AliasesToRemove; + for (GlobalAlias &Alias : M.aliases()) { + emitGlobalAlias(M, Alias); + AliasesToRemove.push_back(&Alias); + } + + for (GlobalAlias *A : AliasesToRemove) + A->eraseFromParent(); + // call doFinalization bool ret = AsmPrinter::doFinalization(M); @@ -1465,7 +1505,7 @@ bool hasImageHandles = STI.hasImageHandles(); if (F->arg_empty() && !F->isVarArg()) { - O << "()\n"; + O << "()"; return; } @@ -1659,7 +1699,7 @@ O << TLI->getParamName(F, /* vararg */ -1) << "[]"; } - O << "\n)\n"; + O << "\n)"; } void NVPTXAsmPrinter::setAndEmitFunctionVirtualRegisters( diff --git a/llvm/test/CodeGen/NVPTX/alias-errors.ll b/llvm/test/CodeGen/NVPTX/alias-errors.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/alias-errors.ll @@ -0,0 +1,9 @@ +; RUN: not --crash llc < %s -march=nvptx64 -mcpu=sm_30 -mattr=+ptx43 2>&1 | FileCheck %s --check-prefix=ATTR +; RUN: not --crash llc < %s -march=nvptx64 -mcpu=sm_20 -mattr=+ptx63 2>&1 | FileCheck %s --check-prefix=ATTR +; RUN: not --crash llc < %s -march=nvptx64 -mcpu=sm_30 -mattr=+ptx63 2>&1 | FileCheck %s --check-prefix=ALIAS + +; ATTR: .alias requires PTX version >= 6.3 and sm_30 + +; ALIAS: NVPTX aliasee must be a non-kernel function +@a = global i32 42, align 8 +@b = internal alias i32, ptr @a diff --git a/llvm/test/CodeGen/NVPTX/alias.ll b/llvm/test/CodeGen/NVPTX/alias.ll --- a/llvm/test/CodeGen/NVPTX/alias.ll +++ b/llvm/test/CodeGen/NVPTX/alias.ll @@ -1,7 +1,27 @@ -; RUN: not --crash llc < %s -march=nvptx -mcpu=sm_20 2>&1 | FileCheck %s - -; Check that llc dies gracefully when given an alias. +; RUN: llc < %s -march=nvptx64 -mcpu=sm_30 -mattr=+ptx63 | FileCheck %s define i32 @a() { ret i32 0 } -; CHECK: ERROR: Module has aliases @b = internal alias i32 (), ptr @a +@c = internal alias i32 (), ptr @a + +define void @foo(i32 %0, ptr %1) { ret void } +@bar = alias i32 (), ptr @foo + +; CHECK: .visible .func (.param .b32 func_retval0) a() + +; CHECK: .visible .func foo( +; CHECK-NEXT: .param .b32 foo_param_0, +; CHECK-NEXT: .param .b64 foo_param_1 +; CHECK-NEXT: ) + +; CHECK: .visible .func (.param .b32 func_retval0) b(); +; CHECK-NEXT: .alias b, a; + +; CHECK: .visible .func (.param .b32 func_retval0) c(); +; CHECK-NEXT: .alias c, a; + +; CHECK: .visible .func bar( +; CHECK-NEXT: .param .b32 foo_param_0, +; CHECK-NEXT: .param .b64 foo_param_1 +; CHECK-NEXT: ); +; CHECK-NEXT: .alias bar, foo;