From 00072c08c75050ae2c835b7bb0e505475dbcd7b9 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 25 Nov 2019 09:50:58 -0800 Subject: [PATCH] [WebAssembly] Mangle the argc/argv `main` as `__wasm_argc_argv`. WebAssembly enforces a rule that caller and callee signatures must match. This means that the traditional technique of passing `main` `argc` and `argv` even when it doesn't need them doesn't work. Currently the backend renames `main` to `__original_main`, however this doesn't interact well with LTO'ing libc, and the name isn't intuitive. This patch allows us to transition to `__main_argc_argv` instead. This implements the proposal in https://github.com/WebAssembly/tool-conventions/pull/134 with a flag to disable it when targeting Emscripten, though this is expected to be temporary, as discussed in the proposal comments. Differential Revision: https://reviews.llvm.org/D70700 --- clang/lib/AST/Mangle.cpp | 19 ++++++++++++++++++- clang/lib/CodeGen/CodeGenModule.cpp | 15 +++++++++++++++ clang/lib/CodeGen/CodeGenModule.h | 3 +++ clang/lib/Frontend/InitHeaderSearch.cpp | 3 +-- clang/test/CodeGen/wasm-call-main.c | 13 +++++++++++++ clang/test/CodeGen/wasm-main.c | 9 +++++++++ clang/test/CodeGen/wasm-main_argc_argv.c | 9 +++++++++ 7 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/wasm-call-main.c create mode 100644 clang/test/CodeGen/wasm-main.c create mode 100644 clang/test/CodeGen/wasm-main_argc_argv.c diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 6fd1840905b3..1a2cb29f0ec7 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -50,7 +50,8 @@ enum CCMangling { CCM_Fast, CCM_RegCall, CCM_Vector, - CCM_Std + CCM_Std, + CCM_WasmMainArgcArgv }; static bool isExternC(const NamedDecl *ND) { @@ -63,6 +64,16 @@ static CCMangling getCallingConvMangling(const ASTContext &Context, const NamedDecl *ND) { const TargetInfo &TI = Context.getTargetInfo(); const llvm::Triple &Triple = TI.getTriple(); + + // On wasm, the argc/argv form of "main" is renamed so that the startup code + // can call it with the correct function signature. + // On Emscripten, users may be exporting "main" and expecting to call it + // themselves, so we can't mangle it. + if (Triple.isWasm() && !Triple.isOSEmscripten()) + if (const FunctionDecl *FD = dyn_cast(ND)) + if (FD->isMain() && FD->hasPrototype() && FD->param_size() == 2) + return CCM_WasmMainArgcArgv; + if (!Triple.isOSWindows() || !Triple.isX86()) return CCM_Other; @@ -143,6 +154,12 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) { const ASTContext &ASTContext = getASTContext(); CCMangling CC = getCallingConvMangling(ASTContext, D); + + if (CC == CCM_WasmMainArgcArgv) { + Out << "__main_argc_argv"; + return; + } + bool MCXX = shouldMangleCXXName(D); const TargetInfo &TI = Context.getTargetInfo(); if (CC == CCM_Other || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 652efd857064..faff623a2973 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -448,6 +448,10 @@ void CodeGenModule::Release() { CodeGenFunction(*this).EmitCfiCheckStub(); } emitAtAvailableLinkGuard(); + if (Context.getTargetInfo().getTriple().isWasm() && + !Context.getTargetInfo().getTriple().isOSEmscripten()) { + EmitMainVoidAlias(); + } emitLLVMUsed(); if (SanStats) SanStats->finish(); @@ -5600,6 +5604,17 @@ void CodeGenModule::EmitDeferredUnusedCoverageMappings() { } } +void CodeGenModule::EmitMainVoidAlias() { + // In order to transition away from "__original_main" gracefully, emit an + // alias for "main" in the no-argument case so that libc can detect when + // new-style no-argument main is in used. + if (llvm::Function *F = getModule().getFunction("main")) { + if (!F->isDeclaration() && F->arg_size() == 0 && !F->isVarArg() && + F->getReturnType()->isIntegerTy(Context.getTargetInfo().getIntWidth())) + addUsedGlobal(llvm::GlobalAlias::create("__main_void", F)); + } +} + /// Turns the given pointer into a constant. static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context, const void *Ptr) { diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index e8162fcfc0cd..48a3938ceeec 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1023,6 +1023,9 @@ public: /// for the uninstrumented functions. void EmitDeferredUnusedCoverageMappings(); + /// Emit an alias for "main" if it has no arguments (needed for wasm). + void EmitMainVoidAlias(); + /// Tell the consumer that this variable has been instantiated. void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); diff --git a/clang/lib/Frontend/InitHeaderSearch.cpp b/clang/lib/Frontend/InitHeaderSearch.cpp index 851f5a4cc05c..159cd47f7831 100644 --- a/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/clang/lib/Frontend/InitHeaderSearch.cpp @@ -433,8 +433,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, break; case llvm::Triple::UnknownOS: - if (triple.getArch() == llvm::Triple::wasm32 || - triple.getArch() == llvm::Triple::wasm64) + if (triple.isWasm()) return; break; } diff --git a/clang/test/CodeGen/wasm-call-main.c b/clang/test/CodeGen/wasm-call-main.c new file mode 100644 index 000000000000..f22ba651c9b1 --- /dev/null +++ b/clang/test/CodeGen/wasm-call-main.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm %s | FileCheck %s + +// Mangle argc/argv main even when it's not defined in this TU. + +#include + +int main(int argc, char *argv[]); + +int foo(void) { + return main(0, NULL); +} + +// CHECK: call i32 @__main_argc_argv( diff --git a/clang/test/CodeGen/wasm-main.c b/clang/test/CodeGen/wasm-main.c new file mode 100644 index 000000000000..33dbdac2a5ba --- /dev/null +++ b/clang/test/CodeGen/wasm-main.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm %s | FileCheck %s + +// Don't mangle the no-arg form of main. + +int main(void) { + return 0; +} + +// CHECK-LABEL: define i32 @main() diff --git a/clang/test/CodeGen/wasm-main_argc_argv.c b/clang/test/CodeGen/wasm-main_argc_argv.c new file mode 100644 index 000000000000..194afc2fd5af --- /dev/null +++ b/clang/test/CodeGen/wasm-main_argc_argv.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm %s | FileCheck %s + +// Mangle the argc/argv form of main. + +int main(int argc, char **argv) { + return 0; +} + +// CHECK-LABEL: define i32 @__main_argc_argv(i32 %argc, i8** %argv)