[llvm] r271599 - [WebAssembly] Emit type signatures for declared functions

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 2 14:34:18 PDT 2016


Author: dschuff
Date: Thu Jun  2 16:34:18 2016
New Revision: 271599

URL: http://llvm.org/viewvc/llvm-project?rev=271599&view=rev
Log:
[WebAssembly] Emit type signatures for declared functions

Under emscripten, C code can take the address of a function implemented
in Javascript (which is exposed via an import in wasm). Because imports
do not have linear memory address in wasm, we need to generate a thunk
to be the target of the indirect call; it call the import directly.

To make this possible, LLVM needs to emit the type signatures for these
functions, because they may not be called directly or referred to other
than where the address is taken.

This uses s new .s directive (.functype) which specifies the signature.

Differential Revision: http://reviews.llvm.org/D20891

Added:
    llvm/trunk/test/CodeGen/WebAssembly/indirect-import.ll
Modified:
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp?rev=271599&r1=271598&r2=271599&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp Thu Jun  2 16:34:18 2016
@@ -64,6 +64,16 @@ void WebAssemblyTargetAsmStreamer::emitL
 
 void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; }
 
+void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
+    StringRef name, SmallVectorImpl<MVT> &SignatureVTs, size_t NumResults) {
+  OS << "\t.functype\t" << name;
+  if (NumResults == 0) OS << ", void";
+  for (auto Ty : SignatureVTs) {
+    OS << ", " << WebAssembly::TypeToString(Ty);
+  }
+  OS << "\n";
+}
+
 // FIXME: What follows is not the real binary encoding.
 
 static void EncodeTypes(MCStreamer &Streamer, ArrayRef<MVT> Types) {

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h?rev=271599&r1=271598&r2=271599&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h Thu Jun  2 16:34:18 2016
@@ -37,6 +37,12 @@ public:
   virtual void emitLocal(ArrayRef<MVT> Types) = 0;
   /// .endfunc
   virtual void emitEndFunc() = 0;
+  /// .functype
+  virtual void emitIndirectFunctionType(StringRef name,
+                                        SmallVectorImpl<MVT> &SignatureVTs,
+                                        size_t NumResults) {
+    llvm_unreachable("emitIndirectFunctionType not implemented");
+  }
 };
 
 /// This part is for ascii assembly output
@@ -50,6 +56,9 @@ public:
   void emitResult(ArrayRef<MVT> Types) override;
   void emitLocal(ArrayRef<MVT> Types) override;
   void emitEndFunc() override;
+  void emitIndirectFunctionType(StringRef name,
+                                SmallVectorImpl<MVT> &SignatureVTs,
+                                size_t NumResults) override;
 };
 
 /// This part is for ELF object output

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=271599&r1=271598&r2=271599&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Thu Jun  2 16:34:18 2016
@@ -67,6 +67,7 @@ private:
   // AsmPrinter Implementation.
   //===------------------------------------------------------------------===//
 
+  void EmitEndOfAsmFile(Module &M) override;
   void EmitJumpTableInfo() override;
   void EmitConstantPool() override;
   void EmitFunctionBodyStart() override;
@@ -124,16 +125,6 @@ WebAssemblyTargetStreamer *WebAssemblyAs
 //===----------------------------------------------------------------------===//
 // WebAssemblyAsmPrinter Implementation.
 //===----------------------------------------------------------------------===//
-
-void WebAssemblyAsmPrinter::EmitConstantPool() {
-  assert(MF->getConstantPool()->getConstants().empty() &&
-         "WebAssembly disables constant pools");
-}
-
-void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
-  // Nothing to do; jump tables are incorporated into the instruction stream.
-}
-
 static void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
                                  Type *Ty, SmallVectorImpl<MVT> &ValueVTs) {
   const DataLayout &DL(F.getParent()->getDataLayout());
@@ -150,6 +141,36 @@ static void ComputeLegalValueVTs(const F
   }
 }
 
+void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
+  for (const auto &F : M) {
+    // Emit function type info for all undefined functions
+    if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
+      SmallVector<MVT, 4> SignatureVTs;
+      ComputeLegalValueVTs(F, TM, F.getReturnType(), SignatureVTs);
+      if (SignatureVTs.size() > 1) {
+        report_fatal_error(
+            "Import functions with nontrival return types are not supported");
+      }
+      size_t NumResults = SignatureVTs.size();
+      for (auto &Arg : F.args()) {
+        ComputeLegalValueVTs(F, TM, Arg.getType(), SignatureVTs);
+      }
+
+      getTargetStreamer()->emitIndirectFunctionType(F.getName(), SignatureVTs,
+                                                    NumResults);
+    }
+  }
+}
+
+void WebAssemblyAsmPrinter::EmitConstantPool() {
+  assert(MF->getConstantPool()->getConstants().empty() &&
+         "WebAssembly disables constant pools");
+}
+
+void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
+  // Nothing to do; jump tables are incorporated into the instruction stream.
+}
+
 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
   if (!MFI->getParams().empty())
     getTargetStreamer()->emitParam(MFI->getParams());

Added: llvm/trunk/test/CodeGen/WebAssembly/indirect-import.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/indirect-import.ll?rev=271599&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/indirect-import.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/indirect-import.ll Thu Jun  2 16:34:18 2016
@@ -0,0 +1,70 @@
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs -fast-isel | FileCheck %s
+
+; ModuleID = 'test/dot_s/indirect-import.c'
+source_filename = "test/dot_s/indirect-import.c"
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32"
+
+%struct.big = type { float, double, i32 }
+
+; Function Attrs: nounwind
+; CHECK: bar:
+define hidden i32 @bar() #0 {
+entry:
+  %fd = alloca float (double)*, align 4
+  %vj = alloca void (i64)*, align 4
+  %v = alloca void ()*, align 4
+  %ijidf = alloca i32 (i64, i32, double, float)*, align 4
+  %vs = alloca void (%struct.big*)*, align 4
+  %s = alloca void (%struct.big*)*, align 4
+
+; CHECK: i32.const       {{.+}}=, extern_fd at FUNCTION
+  store float (double)* @extern_fd, float (double)** %fd, align 4
+; CHECK: i32.const       {{.+}}=, extern_vj at FUNCTION
+  store void (i64)* @extern_vj, void (i64)** %vj, align 4
+  %0 = load void (i64)*, void (i64)** %vj, align 4
+  call void %0(i64 1)
+
+; CHECK: i32.const       {{.+}}=, extern_v at FUNCTION
+  store void ()* @extern_v, void ()** %v, align 4
+  %1 = load void ()*, void ()** %v, align 4
+  call void %1()
+
+; CHECK: i32.const       {{.+}}=, extern_ijidf at FUNCTION
+  store i32 (i64, i32, double, float)* @extern_ijidf, i32 (i64, i32, double, float)** %ijidf, align 4
+  %2 = load i32 (i64, i32, double, float)*, i32 (i64, i32, double, float)** %ijidf, align 4
+  %call = call i32 %2(i64 1, i32 2, double 3.000000e+00, float 4.000000e+00)
+
+; CHECK: i32.const       {{.+}}=, extern_struct at FUNCTION
+  store void (%struct.big*)* @extern_struct, void (%struct.big*)** %vs, align 4
+
+; CHECK: i32.const       {{.+}}=, extern_sret at FUNCTION
+  store void (%struct.big*)* @extern_sret, void (%struct.big*)** %s, align 4
+  %3 = load float (double)*, float (double)** %fd, align 4
+  %4 = ptrtoint float (double)* %3 to i32
+  ret i32 %4
+}
+
+declare float @extern_fd(double) #1
+
+declare void @extern_vj(i64) #1
+
+declare void @extern_v() #1
+
+declare i32 @extern_ijidf(i64, i32, double, float) #1
+
+declare void @extern_struct(%struct.big* byval align 8) #1
+
+declare void @extern_sret(%struct.big* sret) #1
+
+attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+
+; CHECK: .functype       extern_fd, f32, f64
+; CHECK: .functype       extern_vj, void, i64
+; CHECK: .functype       extern_v, void
+; CHECK: .functype       extern_ijidf, i32, i64, i32, f64, f32
+; CHECK: .functype       extern_struct, void, i32
+; CHECK: .functype       extern_sret, void, i32




More information about the llvm-commits mailing list