blob: f949730390df8e0b0e652c71052e92173165899b [file] [log] [blame]
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "iree/compiler/Dialect/HAL/Target/LLVM/LinkerTool.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/FormatVariadic.h"
#define DEBUG_TYPE "llvmaot-linker"
namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace HAL {
// Wasm linker using wasm-ld for producing WebAssembly binaries.
// wasm-ld behaves like traditional ELF linkers and uses similar flags.
//
// For details on the linking process and file formats, see:
// * https://lld.llvm.org/WebAssembly.html
// * https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
//
// For more background on WebAssembly, see:
// * https://webassembly.org/
// * https://developer.mozilla.org/en-US/docs/WebAssembly
//
// When working with WebAssembly files, these projects are useful:
// * https://github.com/WebAssembly/wabt
// * https://github.com/bytecodealliance/wasmtime
//
// Use -iree-llvm-target-triple=wasm32-unknown-unknown.
class WasmLinkerTool : public LinkerTool {
public:
using LinkerTool::LinkerTool;
std::string getToolPath() const override {
// First check for setting the linker explicitly.
auto toolPath = LinkerTool::getToolPath();
if (!toolPath.empty()) return toolPath;
// No explicit linker specified, search the environment for common tools.
toolPath = findToolInEnvironment({"wasm-ld"});
if (!toolPath.empty()) return toolPath;
llvm::errs() << "No Wasm linker tool specified or discovered\n";
return "";
}
LogicalResult configureModule(llvm::Module *llvmModule,
ArrayRef<StringRef> entryPointNames) override {
for (auto &func : *llvmModule) {
// Enable frame pointers to ensure that stack unwinding works.
func.addFnAttr("frame-pointer", "all");
// -ffreestanding-like behavior.
func.addFnAttr("no-builtins");
}
// https://lld.llvm.org/WebAssembly.html#exports
for (auto entryPointName : entryPointNames) {
auto *entryPointFn = llvmModule->getFunction(entryPointName);
entryPointFn->addFnAttr("wasm-export-name", entryPointName);
}
return success();
}
Optional<Artifacts> linkDynamicLibrary(
StringRef libraryName, ArrayRef<Artifact> objectFiles) override {
Artifacts artifacts;
// Create the wasm binary file name; if we only have a single input object
// we can just reuse that.
if (objectFiles.size() == 1) {
artifacts.libraryFile =
Artifact::createVariant(objectFiles.front().path, "wasm");
} else {
artifacts.libraryFile = Artifact::createTemporary(libraryName, "wasm");
}
artifacts.libraryFile.close();
SmallVector<std::string, 8> flags = {
getToolPath(),
// entry symbol not defined (pass --no-entry to suppress): _start
"--no-entry",
// Allow undefined symbols, provided by the runtime environment (?)
// TODO(scotttodd): figure out how to avoid this.
"--allow-undefined",
// Treat warnings as errors.
"--fatal-warnings",
"-o " + artifacts.libraryFile.path,
};
// Strip debug information when not requested.
if (!targetOptions.debugSymbols) {
flags.push_back("--strip-debug");
}
// Link all input objects. Note that we are not linking whole-archive as
// we want to allow dropping of unused codegen outputs.
for (auto &objectFile : objectFiles) {
flags.push_back(objectFile.path);
}
auto commandLine = llvm::join(flags, " ");
if (failed(runLinkCommand(commandLine))) return llvm::None;
return artifacts;
}
};
std::unique_ptr<LinkerTool> createWasmLinkerTool(
llvm::Triple &targetTriple, LLVMTargetOptions &targetOptions) {
return std::make_unique<WasmLinkerTool>(targetTriple, targetOptions);
}
} // namespace HAL
} // namespace IREE
} // namespace iree_compiler
} // namespace mlir