CurrentFnSym->print(O, MAI);
emitFunctionParamList(F, O);
+ O << "\n";
if (isKernelFunction(*F))
emitKernelFunctionDirectives(*F, O);
getSymbol(F)->print(O, MAI);
O << "\n";
emitFunctionParamList(F, O);
+ O << "\n";
if (shouldEmitPTXNoReturn(F, TM))
O << ".noreturn";
O << ";\n";
}
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<const NVPTXTargetMachine &>(TM);
+ const NVPTXSubtarget &STI =
+ *static_cast<const NVPTXSubtarget *>(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(
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<Function>(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";
GlobalsEmitted = true;
}
+ // If we have any aliases we emit them at the end.
+ SmallVector<GlobalAlias *> 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);
bool hasImageHandles = STI.hasImageHandles();
if (F->arg_empty() && !F->isVarArg()) {
- O << "()\n";
+ O << "()";
return;
}
O << TLI->getParamName(F, /* vararg */ -1) << "[]";
}
- O << "\n)\n";
+ O << "\n)";
}
void NVPTXAsmPrinter::setAndEmitFunctionVirtualRegisters(
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 &);
-; 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;