[llvm] r246092 - WebAssembly: handle private/internal globals.

JF Bastien via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 15:09:54 PDT 2015


Author: jfb
Date: Wed Aug 26 17:09:54 2015
New Revision: 246092

URL: http://llvm.org/viewvc/llvm-project?rev=246092&view=rev
Log:
WebAssembly: handle private/internal globals.

Things of note:
 - Other linkage types aren't handled yet. We'll figure it out with dynamic linking.
 - Special LLVM globals are either ignored, or error out for now.
 - TLS isn't supported yet (WebAssembly will have threads later).
 - There currently isn't a syntax for alignment, I left it in a comment so it's easy to hook up.
 - Undef is convereted to whatever the type's appropriate null value is.
 - assert versus report_fatal_error: follow what other AsmPrinters do, and assert only on what should have been caught elsewhere.

Added:
    llvm/trunk/test/CodeGen/WebAssembly/global.ll
Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=246092&r1=246091&r2=246092&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Wed Aug 26 17:09:54 2015
@@ -68,6 +68,8 @@ private:
   // AsmPrinter Implementation.
   //===------------------------------------------------------------------===//
 
+  void EmitGlobalVariable(const GlobalVariable *GV) override;
+
   void EmitConstantPool() override;
   void EmitFunctionEntryLabel() override;
   void EmitFunctionBodyStart() override;
@@ -79,12 +81,14 @@ private:
 } // end anonymous namespace
 
 //===----------------------------------------------------------------------===//
+// Helpers.
+//===----------------------------------------------------------------------===//
 
 // Untyped, lower-case version of the opcode's name matching the names
 // WebAssembly opcodes are expected to have. The tablegen names are uppercase
 // and suffixed with their type (after an underscore).
-static SmallString<32> Name(const WebAssemblyInstrInfo *TII,
-                            const MachineInstr *MI) {
+static SmallString<32> OpcodeName(const WebAssemblyInstrInfo *TII,
+                                  const MachineInstr *MI) {
   std::string N(StringRef(TII->getName(MI->getOpcode())).lower());
   std::string::size_type End = N.rfind('_');
   End = std::string::npos == End ? N.length() : End;
@@ -93,7 +97,7 @@ static SmallString<32> Name(const WebAss
 
 static std::string toSymbol(StringRef S) { return ("$" + S).str(); }
 
-static const char *toType(const Type *Ty) {
+static const char *toString(const Type *Ty) {
   switch (Ty->getTypeID()) {
   default: break;
   case Type::FloatTyID:  return "f32";
@@ -110,6 +114,91 @@ static const char *toType(const Type *Ty
   return "<invalid>";
 }
 
+static std::string toString(const APFloat &FP) {
+  static const size_t BufBytes = 128;
+  char buf[BufBytes];
+  if (FP.isNaN())
+    assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||
+            FP.bitwiseIsEqual(
+                APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&
+           "convertToHexString handles neither SNaN nor NaN payloads");
+  // Use C99's hexadecimal floating-point representation.
+  auto Written = FP.convertToHexString(
+      buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
+  (void)Written;
+  assert(Written != 0);
+  assert(Written < BufBytes);
+  return buf;
+}
+
+//===----------------------------------------------------------------------===//
+// WebAssemblyAsmPrinter Implementation.
+//===----------------------------------------------------------------------===//
+
+void WebAssemblyAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
+  SmallString<128> Str;
+  raw_svector_ostream OS(Str);
+  StringRef Name = GV->getName();
+  DEBUG(dbgs() << "Global " << Name << '\n');
+
+  if (!GV->hasInitializer()) {
+    DEBUG(dbgs() << "  Skipping declaration.\n");
+    return;
+  }
+
+  // Check to see if this is a special global used by LLVM.
+  static const char *Ignored[] = {"llvm.used", "llvm.metadata"};
+  for (const char *I : Ignored)
+    if (Name == I)
+      return;
+  // FIXME: Handle the following globals.
+  static const char *Unhandled[] = {"llvm.global_ctors", "llvm.global_dtors"};
+  for (const char *U : Unhandled)
+    if (Name == U)
+      report_fatal_error("Unhandled global");
+  if (Name.startswith("llvm."))
+    report_fatal_error("Unknown LLVM-internal global");
+
+  if (GV->isThreadLocal())
+    report_fatal_error("TLS isn't yet supported by WebAssembly");
+
+  const DataLayout &DL = getDataLayout();
+  const Constant *Init = GV->getInitializer();
+  if (isa<UndefValue>(Init))
+    Init = Constant::getNullValue(Init->getType());
+  unsigned Align = DL.getPrefTypeAlignment(Init->getType());
+
+  switch (GV->getLinkage()) {
+  case GlobalValue::InternalLinkage:
+  case GlobalValue::PrivateLinkage:
+    break;
+  case GlobalValue::AppendingLinkage:
+  case GlobalValue::LinkOnceAnyLinkage:
+  case GlobalValue::LinkOnceODRLinkage:
+  case GlobalValue::WeakAnyLinkage:
+  case GlobalValue::WeakODRLinkage:
+  case GlobalValue::ExternalLinkage:
+  case GlobalValue::CommonLinkage:
+    report_fatal_error("Linkage types other than internal and private aren't "
+                       "supported by WebAssembly");
+  default:
+    llvm_unreachable("Unknown linkage type");
+    return;
+  }
+
+  OS << "(global " << toSymbol(Name) << ' ' << toString(Init->getType()) << ' ';
+  if (const auto *C = dyn_cast<ConstantInt>(Init)) {
+    assert(C->getBitWidth() <= 64 && "Printing wider types unimplemented");
+    OS << C->getZExtValue();
+  } else if (const auto *C = dyn_cast<ConstantFP>(Init)) {
+    OS << toString(C->getValueAPF());
+  } else {
+    assert(false && "Only integer and floating-point constants are supported");
+  }
+  OS << ") ;; align " << Align << "\n";
+  OutStreamer->EmitRawText(OS.str());
+}
+
 void WebAssemblyAsmPrinter::EmitConstantPool() {
   assert(MF->getConstantPool()->getConstants().empty() &&
          "WebAssembly disables constant pools");
@@ -139,10 +228,10 @@ void WebAssemblyAsmPrinter::EmitFunction
   raw_svector_ostream OS(Str);
   const Function *F = MF->getFunction();
   for (const Argument &A : F->args())
-    OS << " (param " << toType(A.getType()) << ')';
+    OS << " (param " << toString(A.getType()) << ')';
   const Type *Rt = F->getReturnType();
   if (!Rt->isVoidTy())
-    OS << " (result " << toType(Rt) << ')';
+    OS << " (result " << toString(Rt) << ')';
   OS << '\n';
   OutStreamer->EmitRawText(OS.str());
 }
@@ -171,7 +260,7 @@ void WebAssemblyAsmPrinter::EmitInstruct
     OS << "(setlocal @" << TargetRegisterInfo::virtReg2Index(Reg) << ' ';
   }
 
-  OS << '(' << Name(TII, MI);
+  OS << '(' << OpcodeName(TII, MI);
   for (const MachineOperand &MO : MI->uses())
     switch (MO.getType()) {
     default:
@@ -186,22 +275,7 @@ void WebAssemblyAsmPrinter::EmitInstruct
       OS << ' ' << MO.getImm();
     } break;
     case MachineOperand::MO_FPImmediate: {
-      static const size_t BufBytes = 128;
-      char buf[BufBytes];
-      APFloat FP = MO.getFPImm()->getValueAPF();
-      if (FP.isNaN())
-        assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||
-                FP.bitwiseIsEqual(
-                    APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&
-               "convertToHexString handles neither SNaN nor NaN payloads");
-      // Use C99's hexadecimal floating-point representation.
-      auto Written =
-          FP.convertToHexString(buf, /*hexDigits=*/0, /*upperCase=*/false,
-                                APFloat::rmNearestTiesToEven);
-      (void)Written;
-      assert(Written != 0);
-      assert(Written < BufBytes);
-      OS << ' ' << buf;
+      OS << ' ' << toString(MO.getFPImm()->getValueAPF());
     } break;
     case MachineOperand::MO_GlobalAddress: {
       OS << ' ' << toSymbol(MO.getGlobal()->getName());

Added: llvm/trunk/test/CodeGen/WebAssembly/global.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/global.ll?rev=246092&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/global.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/global.ll Wed Aug 26 17:09:54 2015
@@ -0,0 +1,37 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck %s
+
+; Test that globals assemble as expected.
+
+target datalayout = "e-p:32:32-i64:64-v128:8:128-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; CHECK-NOT: llvm.used
+; CHECK-NOT: llvm.metadata
+ at llvm.used = appending global [1 x i32*] [i32* @g], section "llvm.metadata"
+
+ at g = private global i32 1337; ; CHECK: (global $g i32 1337)
+
+ at ud = internal global i32 undef;            ; CHECK: (global $ud i32 0)
+ at nil = internal global i32 zeroinitializer; ; CHECK: (global $nil i32 0)
+ at z = internal global i32 0;                 ; CHECK: (global $z i32 0)
+ at one = internal global i32 1;               ; CHECK: (global $one i32 1)
+ at answer = internal global i32 42;           ; CHECK: (global $answer i32 42)
+ at u32max = internal global i32 -1;           ; CHECK: (global $u32max i32 4294967295)
+
+ at ud64 = internal global i64 undef;            ; CHECK: (global $ud64 i64 0)
+ at nil64 = internal global i64 zeroinitializer; ; CHECK: (global $nil64 i64 0)
+ at z64 = internal global i64 0;                 ; CHECK: (global $z64 i64 0)
+ at twoP32 = internal global i64 4294967296;     ; CHECK: (global $twoP32 i64 4294967296)
+ at u64max = internal global i64 -1;             ; CHECK: (global $u64max i64 18446744073709551615)
+
+ at f32ud = internal global float undef;            ; CHECK: (global $f32ud f32 0x0p0)
+ at f32nil = internal global float zeroinitializer; ; CHECK: (global $f32nil f32 0x0p0)
+ at f32z = internal global float 0.0;               ; CHECK: (global $f32z f32 0x0p0)
+ at f32nz = internal global float -0.0;             ; CHECK: (global $f32nz f32 -0x0p0)
+ at f32two = internal global float 2.0;             ; CHECK: (global $f32two f32 0x1p1)
+
+ at f64ud = internal global double undef;            ; CHECK: (global $f64ud f64 0x0p0)
+ at f64nil = internal global double zeroinitializer; ; CHECK: (global $f64nil f64 0x0p0)
+ at f64z = internal global double 0.0;               ; CHECK: (global $f64z f64 0x0p0)
+ at f64nz = internal global double -0.0;             ; CHECK: (global $f64nz f64 -0x0p0)
+ at f64two = internal global double 2.0;             ; CHECK: (global $f64two f64 0x1p1)




More information about the llvm-commits mailing list