forked from OSchip/llvm-project
[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
This commit is contained in:
parent
197bda587b
commit
00072c08c7
|
@ -50,7 +50,8 @@ enum CCMangling {
|
||||||
CCM_Fast,
|
CCM_Fast,
|
||||||
CCM_RegCall,
|
CCM_RegCall,
|
||||||
CCM_Vector,
|
CCM_Vector,
|
||||||
CCM_Std
|
CCM_Std,
|
||||||
|
CCM_WasmMainArgcArgv
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool isExternC(const NamedDecl *ND) {
|
static bool isExternC(const NamedDecl *ND) {
|
||||||
|
@ -63,6 +64,16 @@ static CCMangling getCallingConvMangling(const ASTContext &Context,
|
||||||
const NamedDecl *ND) {
|
const NamedDecl *ND) {
|
||||||
const TargetInfo &TI = Context.getTargetInfo();
|
const TargetInfo &TI = Context.getTargetInfo();
|
||||||
const llvm::Triple &Triple = TI.getTriple();
|
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<FunctionDecl>(ND))
|
||||||
|
if (FD->isMain() && FD->hasPrototype() && FD->param_size() == 2)
|
||||||
|
return CCM_WasmMainArgcArgv;
|
||||||
|
|
||||||
if (!Triple.isOSWindows() || !Triple.isX86())
|
if (!Triple.isOSWindows() || !Triple.isX86())
|
||||||
return CCM_Other;
|
return CCM_Other;
|
||||||
|
|
||||||
|
@ -143,6 +154,12 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
|
||||||
|
|
||||||
const ASTContext &ASTContext = getASTContext();
|
const ASTContext &ASTContext = getASTContext();
|
||||||
CCMangling CC = getCallingConvMangling(ASTContext, D);
|
CCMangling CC = getCallingConvMangling(ASTContext, D);
|
||||||
|
|
||||||
|
if (CC == CCM_WasmMainArgcArgv) {
|
||||||
|
Out << "__main_argc_argv";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool MCXX = shouldMangleCXXName(D);
|
bool MCXX = shouldMangleCXXName(D);
|
||||||
const TargetInfo &TI = Context.getTargetInfo();
|
const TargetInfo &TI = Context.getTargetInfo();
|
||||||
if (CC == CCM_Other || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
|
if (CC == CCM_Other || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
|
||||||
|
|
|
@ -448,6 +448,10 @@ void CodeGenModule::Release() {
|
||||||
CodeGenFunction(*this).EmitCfiCheckStub();
|
CodeGenFunction(*this).EmitCfiCheckStub();
|
||||||
}
|
}
|
||||||
emitAtAvailableLinkGuard();
|
emitAtAvailableLinkGuard();
|
||||||
|
if (Context.getTargetInfo().getTriple().isWasm() &&
|
||||||
|
!Context.getTargetInfo().getTriple().isOSEmscripten()) {
|
||||||
|
EmitMainVoidAlias();
|
||||||
|
}
|
||||||
emitLLVMUsed();
|
emitLLVMUsed();
|
||||||
if (SanStats)
|
if (SanStats)
|
||||||
SanStats->finish();
|
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.
|
/// Turns the given pointer into a constant.
|
||||||
static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context,
|
static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context,
|
||||||
const void *Ptr) {
|
const void *Ptr) {
|
||||||
|
|
|
@ -1023,6 +1023,9 @@ public:
|
||||||
/// for the uninstrumented functions.
|
/// for the uninstrumented functions.
|
||||||
void EmitDeferredUnusedCoverageMappings();
|
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.
|
/// Tell the consumer that this variable has been instantiated.
|
||||||
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
|
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
|
||||||
|
|
||||||
|
|
|
@ -433,8 +433,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case llvm::Triple::UnknownOS:
|
case llvm::Triple::UnknownOS:
|
||||||
if (triple.getArch() == llvm::Triple::wasm32 ||
|
if (triple.isWasm())
|
||||||
triple.getArch() == llvm::Triple::wasm64)
|
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <stddef.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]);
|
||||||
|
|
||||||
|
int foo(void) {
|
||||||
|
return main(0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: call i32 @__main_argc_argv(
|
|
@ -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()
|
|
@ -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)
|
Loading…
Reference in New Issue