Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
671 views
in Technique[技术] by (71.8m points)

clang - Exporting functions from LLVM C++ API to WebAssembly

Situation: I currently parse a front-end language and generate function definitions in LLVM IR.

I can compile the function definition to a WebAssembly file using the LLVM12 C++ API.

However, the generated wasm code does not "export" any of the compiled functions and thus cannot be accessed from a javascript that loads the wasm file.

Question: Could someone let me know what I might be missing? How does one tell the llvm compiler to create exports for the defined functions. I tried setting the function visibility to llvm::GlobalValue::DefaultVisibility. But that doesn't seem to help.

The generated IR for the function (with default visibility) looks like

define double @f(double %x) #0 {
entry:
  %multmp = fmul double %x, 2.000000e+00
  ret double %multmp
}

attributes #0 = { "target-features" }

The function to compile the module containing the function definition to the Wasm target looks like this:

llvm::Module *TheModule; // module containing the function definition

// function to compile to Wasm target
bool compile_file(){
  const char *TargetTriple = "wasm-wasi";
  
  // create a llvm::Target for the specified triple
  std::string Error;
  const llvm::Target *Target =   llvm::TargetRegistry::lookupTarget(TargetTriple, Error);
  if(!Target) {
    llvm::errs() << Error;
    return false;
  }
  
  // set the options and features for the target and create a TargetMachine instance
  auto CPU = "generic";
  auto Features = "";

  llvm::TargetOptions opt;
  auto RM = llvm::Optional<llvm::Reloc::Model>();
  auto TheTargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM);
  TheModule->setDataLayout(TheTargetMachine->createDataLayout());

  // create a output stream to write the compiled code to a .wasm file in the current directory
  std::error_code EC;
  llvm::raw_fd_ostream dest("output.wasm", EC, llvm::sys::fs::OF_None);

  if(EC) {
    llvm::errs() << "Could not open file: " << EC.message();
    return false;
  }


  // set the visibility of all functions in the module to DefaultVisibility
  auto &functionList = TheModule->getFunctionList();
  for (auto &function : functionList) {
    function.setVisibility(llvm::GlobalValue::DefaultVisibility);
  }
  
  // add a emit pass to write the generated code to the wasm file 
  llvm::legacy::PassManager pass;
  if(TheTargetMachine->addPassesToEmitFile(pass,dest,nullptr,llvm::CGFT_ObjectFile)){
    llvm::errs() << "TheTargetMachine can't emit a file of this type";
    return false;
  }
  // run the pass on the module and flush the output stream to the file
  pass.run(*(TheModule));
  dest.flush();
  // return true on success
  return true;

This outputs a wasm file that looks like

(module
  (type $t0 (func (param f64) (result f64)))
  (import "env" "__linear_memory" (memory $env.__linear_memory 0))
  (import "env" "__indirect_function_table" (table $env.__indirect_function_table 0 funcref))
  (func $f0 (type $t0) (param $p0 f64) (result f64)
    local.get $p0
    local.get $p0
    f64.add))

However, this generated file has a problem. It does not add an "export" statement to make the function f0 visible to the outside world, which would allow a javascript loading the wasm module to call the function f0. Ideally, the generated file should have the function definition line looking like

func $f0 (export "f") (type $t0) (param $p0 f64) (result f64)
    local.get $p0
    local.get $p0
    f64.add))

This way the loading javascript will have access to a function named "f" that it can call from the wasm.

Is there a way to specify to the LLVM C++ API that the function should be exported?

question from:https://stackoverflow.com/questions/65646383/exporting-functions-from-llvm-c-api-to-webassembly

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can trigger the export of a given symbol by setting the wasm-export-name and wasm-export-name attributes.

In C/C++ these correspond the export_name and export_module clang attribtes.

See llvm/test/CodeGen/WebAssembly/export-name.ll in the llvm tree for an example of this.

You can also ask the linker to export a given symbol with the --export command line flag. See https://lld.llvm.org/WebAssembly.html#exports.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...