diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index f1f68a336864..e7a02462672b 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -628,6 +628,10 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new SPIRV64TargetInfo(Triple, Opts); } case llvm::Triple::wasm32: + // Use the Cheerp backend for CheerpOS, even if the + // externally visible target is upstream wasm32 + if (Triple.isCheerpOS()) + return new CheerpTargetInfo(Triple); if (Triple.getSubArch() != llvm::Triple::NoSubArch || Triple.getVendor() != llvm::Triple::UnknownVendor || !Triple.isOSBinFormatWasm()) diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 99fd578d0df1..795d92db6005 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -343,6 +343,12 @@ bool CheerpTargetInfo::handleTargetFeatures( return true; } +bool CheerpTargetInfo::isValidCPUName(StringRef Name) const +{ + // Be compatible with the default CPU name of the Wasm target + return Name == "generic"; +} + const Builtin::Info CheerpTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, nullptr}, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 7ae310d1f8a5..1c17a023a641 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -220,8 +220,14 @@ class CheerpTargetInfo : public TargetInfo { private: static const Builtin::Info BuiltinInfo[]; bool hasSIMD = false; + static llvm::Triple filterTriple(const llvm::Triple &triple) { + llvm::Triple ret(triple); + // Override the internal architecture when dealing with the wasm32-cheerpos-linux target + ret.setArch(llvm::Triple::cheerp); + return ret; + } public: - CheerpTargetInfo(const llvm::Triple &triple) : TargetInfo(triple) { + CheerpTargetInfo(const llvm::Triple &triple) : TargetInfo(filterTriple(triple)) { resetDataLayout("b-e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i24:8:8-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" "a:0:32-f16:16:16-f32:32:32-f64:64:64-n8:16:32-S64"); @@ -284,6 +290,8 @@ class CheerpTargetInfo : public TargetInfo { // Special handling for Cheerp, any name can be clobbered return true; } + bool isValidCPUName(StringRef Name) const final; + bool setCPU(const std::string &Name) final { return isValidCPUName(Name); } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 3bb08db8ab50..82058b0dc799 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -696,6 +696,11 @@ static llvm::Triple computeTargetTriple(const Driver &D, Target.setEnvironment(llvm::Triple::GenericJS); } + // Force a full triple when targeting CheerpOS + if (Target.getVendor() == llvm::Triple::CheerpOS) { + Target.setEnvironment(llvm::Triple::WebAssembly); + } + return Target; } @@ -5946,6 +5951,10 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, Args); else if (Target.getArch() == llvm::Triple::ve) TC = std::make_unique(*this, Target, Args); + // Take over control of the toolchain when targeting CheerpOS, + // we don't want to use system includes and libraries + else if ((Target.getVendor() == llvm::Triple::CheerpOS)) + TC = std::make_unique(*this, Target, Args); else TC = std::make_unique(*this, Target, Args); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 9369a1cf4377..1ae6dc3b95f9 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5925,7 +5925,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Pass cheerp-wasm-externref if anyref feature enabled - auto wasmFeatures = cheerp::getWasmFeatures(D, Args); + auto wasmFeatures = cheerp::getWasmFeatures(D, getToolChain().getTriple(), Args); if (std::binary_search(wasmFeatures.begin(), wasmFeatures.end(), cheerp::ANYREF)) { CmdArgs.push_back("-cheerp-wasm-externref"); } diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index b1c21a8aa954..fdc1b1b151d7 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -562,8 +562,9 @@ void cheerp::Link::ConstructJob(Compilation &C, const JobAction &JA, } const Driver &D = getToolChain().getDriver(); + const llvm::Triple& triple = getToolChain().getTriple(); bool hasUnalignedMemory = true; - auto features = getWasmFeatures(D, Args); + auto features = getWasmFeatures(D, triple, Args); if(std::find(features.begin(), features.end(), UNALIGNEDMEM) == features.end()) hasUnalignedMemory = false; @@ -591,7 +592,7 @@ void cheerp::Link::ConstructJob(Compilation &C, const JobAction &JA, AddStdLib("libc.bc"); AddStdLib("crt1.bc"); } - if (getToolChain().getTriple().isCheerpWasi()) + if (triple.isCheerpWasi()) AddStdLib("libwasi.bc"); else AddStdLib("libsystem.bc"); @@ -607,7 +608,7 @@ void cheerp::Link::ConstructJob(Compilation &C, const JobAction &JA, } if(((CheerpLinearOutput && CheerpLinearOutput->getValue() == StringRef("wasm")) || - (!CheerpLinearOutput && getToolChain().getTriple().isCheerpWasm())) && + (!CheerpLinearOutput && triple.isCheerpWasm())) && hasUnalignedMemory && (!Sanitizers || !Sanitizers->containsValue("address"))) { // We omit libwasm when building with AddressSanitizer, since it defines @@ -680,6 +681,7 @@ void cheerp::CheerpOptimizer::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { ArgStringList CmdArgs; const Driver &D = getToolChain().getDriver(); + const llvm::Triple& triple = getToolChain().getTriple(); std::string optPasses = ""; auto addPass = [&optPasses](const std::string& passInvocation)->void{ @@ -699,7 +701,7 @@ void cheerp::CheerpOptimizer::ConstructJob(Compilation &C, const JobAction &JA, cheerpFixFuncCasts->render(Args, CmdArgs); if(Arg* cheerpUseBigInts = Args.getLastArg(options::OPT_cheerp_use_bigints)) cheerpUseBigInts->render(Args, CmdArgs); - else if (getToolChain().getTriple().isCheerpWasmStandalone()) + else if (triple.isCheerpWasmStandalone()) CmdArgs.push_back("-cheerp-use-bigints"); // Malloc/Free are probably intercepted when using sanitizers, don't optimize @@ -721,7 +723,7 @@ void cheerp::CheerpOptimizer::ConstructJob(Compilation &C, const JobAction &JA, else { std::string linearOut("-cheerp-linear-output="); - if (getToolChain().getTriple().isCheerpWasm()) + if (triple.isCheerpWasm()) { linearOut += "wasm"; } @@ -732,7 +734,7 @@ void cheerp::CheerpOptimizer::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back(Args.MakeArgString(linearOut)); } - auto features = getWasmFeatures(D, Args); + auto features = getWasmFeatures(D, triple, Args); if(std::find(features.begin(), features.end(), EXPORTEDTABLE) != features.end()) CmdArgs.push_back("-cheerp-wasm-exported-table"); if(std::find(features.begin(), features.end(), EXPORTEDMEMORY) != features.end()) @@ -814,14 +816,20 @@ static cheerp::CheerpWasmOpt parseWasmOpt(StringRef opt) .Default(cheerp::INVALID); } -std::vector cheerp::getWasmFeatures(const Driver& D, const ArgList& Args) +std::vector cheerp::getWasmFeatures(const Driver& D, const llvm::Triple& triple, const ArgList& Args) { // Figure out which Wasm optional feature to enable/disable std::vector features; - // We enable memory growth/globalization/unaligned memory accesses by default + // We enable memory growth and unaligned memory accesses by default features.push_back(GROWMEM); features.push_back(GLOBALIZATION); features.push_back(UNALIGNEDMEM); + // For CheerpOS we also force the memory to be imported and shared + if(triple.isCheerpOS()) { + features.push_back(IMPORTEDMEMORY); + features.push_back(SHAREDMEM); + } + if(Arg* cheerpWasmEnable = Args.getLastArg(options::OPT_cheerp_wasm_enable_EQ)) { for (StringRef opt: cheerpWasmEnable->getValues()) { @@ -870,6 +878,7 @@ void cheerp::CheerpCompiler::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); + const llvm::Triple& triple = getToolChain().getTriple(); ArgStringList CmdArgs; @@ -880,7 +889,7 @@ void cheerp::CheerpCompiler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Output.getFilename()); } - bool isCheerpWasm = getToolChain().getTriple().isCheerpWasm(); + bool isCheerpWasm = triple.isCheerpWasm(); Arg* cheerpLinearOutput = Args.getLastArg(options::OPT_cheerp_linear_output_EQ); if (cheerpLinearOutput) cheerpLinearOutput->render(Args, CmdArgs); @@ -920,7 +929,7 @@ void cheerp::CheerpCompiler::ConstructJob(Compilation &C, const JobAction &JA, if(Arg* cheerpSecondaryOutputFile = Args.getLastArg(options::OPT_cheerp_secondary_output_file_EQ)) cheerpSecondaryOutputFile->render(Args, CmdArgs); else if( - ((isCheerpWasm && !getToolChain().getTriple().isCheerpWasmStandalone() && !cheerpLinearOutput) || + ((isCheerpWasm && !triple.isCheerpWasmStandalone() && !cheerpLinearOutput) || (cheerpLinearOutput && cheerpLinearOutput->getValue() != StringRef("asmjs")))) { SmallString<64> path(Output.getFilename()); @@ -964,7 +973,7 @@ void cheerp::CheerpCompiler::ConstructJob(Compilation &C, const JobAction &JA, } // Figure out which Wasm optional feature to enable/disable - auto features = getWasmFeatures(D, Args); + auto features = getWasmFeatures(D, triple, Args); bool noGrowMem = true; bool noSIMD = true; bool noGlobalization = true; @@ -977,6 +986,7 @@ void cheerp::CheerpCompiler::ConstructJob(Compilation &C, const JobAction &JA, { case SHAREDMEM: sharedMem = true; + noGlobalization = true; break; case GROWMEM: noGrowMem = false; @@ -1003,7 +1013,10 @@ void cheerp::CheerpCompiler::ConstructJob(Compilation &C, const JobAction &JA, noSIMD = false; break; case GLOBALIZATION: - noGlobalization = false; + // It never make sense to use globalized constants with shared memory, + // we would get accidentally thread-local global variables + if (!sharedMem) + noGlobalization = false; break; case UNALIGNEDMEM: noUnalignedMem = false; @@ -1080,7 +1093,7 @@ void cheerp::CheerpCompiler::ConstructJob(Compilation &C, const JobAction &JA, cheerpFixFuncCasts->render(Args, CmdArgs); if(Arg* cheerpUseBigInts = Args.getLastArg(options::OPT_cheerp_use_bigints)) cheerpUseBigInts->render(Args, CmdArgs); - else if (getToolChain().getTriple().isCheerpWasmStandalone()) + else if (triple.isCheerpWasmStandalone()) CmdArgs.push_back("-cheerp-use-bigints"); if(Arg* cheerpMakeDTS = Args.getLastArg(options::OPT_cheerp_make_dts)) cheerpMakeDTS->render(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h index 4ead215c58eb..072690b19090 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -49,7 +49,7 @@ namespace cheerp { GLOBALIZATION, UNALIGNEDMEM }; - std::vector getWasmFeatures(const Driver& D, const llvm::opt::ArgList& Args); + std::vector getWasmFeatures(const Driver& D, const llvm::Triple& triple, const llvm::opt::ArgList& Args); class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index acb240d19135..6e9c2a010929 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -181,7 +181,8 @@ class Triple { SUSE, OpenEmbedded, Leaningtech, - LastVendorType = Leaningtech + CheerpOS, + LastVendorType = CheerpOS }; enum OSType { UnknownOS, @@ -791,20 +792,24 @@ class Triple { /// Tests whether the target is cheerp-wasm bool isCheerpWasm() const { - return getArch() == Triple::cheerp && getEnvironment() == Triple::WebAssembly; + return (getArch() == Triple::cheerp && getEnvironment() == Triple::WebAssembly) || isCheerpOS(); } bool isCheerpWasi() const { return getArch() == Triple::cheerp && getOS() == Triple::WASI; } + bool isCheerpOS() const { + return getVendor() == Triple::CheerpOS; + } + bool isCheerpWasmStandalone() const { - return isCheerpWasi(); + return isCheerpWasi() || isCheerpOS(); } /// Tests whether the target is cheerp (including cheerp-wasm and cheerp-genericjs) bool isCheerp() const{ - return getArch() == Triple::cheerp; + return getArch() == Triple::cheerp || isCheerpOS(); } /// Tests whether the target supports the EHABI exception diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp index ff0c39d2704d..af62222c6c3c 100644 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -197,6 +197,7 @@ StringRef Triple::getVendorTypeName(VendorType Kind) { case SCEI: return "scei"; case SUSE: return "suse"; case Leaningtech: return "leaningtech"; + case CheerpOS: return "cheerpos"; } llvm_unreachable("Invalid VendorType!"); @@ -557,6 +558,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("suse", Triple::SUSE) .Case("oe", Triple::OpenEmbedded) .Case("leaningtech", Triple::Leaningtech) + .Case("cheerpos", Triple::CheerpOS) .Default(Triple::UnknownVendor); }