<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Aug 26, 2015 at 3:56 PM, Dan Gohman <span dir="ltr"><<a href="mailto:sunfish@mozilla.com" target="_blank">sunfish@mozilla.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Wed, Aug 26, 2015 at 3:09 PM, JF Bastien via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: jfb<br>
Date: Wed Aug 26 17:09:54 2015<br>
New Revision: 246092<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=246092&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=246092&view=rev</a><br>
Log:<br>
WebAssembly: handle private/internal globals.<br>
<br>
Things of note:<br>
 - Other linkage types aren't handled yet. We'll figure it out with dynamic linking.<br>
 - Special LLVM globals are either ignored, or error out for now.<br>
 - TLS isn't supported yet (WebAssembly will have threads later).<br>
 - There currently isn't a syntax for alignment, I left it in a comment so it's easy to hook up.<br>
 - Undef is convereted to whatever the type's appropriate null value is.<br>
 - assert versus report_fatal_error: follow what other AsmPrinters do, and assert only on what should have been caught elsewhere.<br>
<br>
Added:<br>
    llvm/trunk/test/CodeGen/WebAssembly/global.ll<br>
Modified:<br>
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp<br>
<br>
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=246092&r1=246091&r2=246092&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=246092&r1=246091&r2=246092&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (original)<br>
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Wed Aug 26 17:09:54 2015<br>
@@ -68,6 +68,8 @@ private:<br>
   // AsmPrinter Implementation.<br>
   //===------------------------------------------------------------------===//<br>
<br>
+  void EmitGlobalVariable(const GlobalVariable *GV) override;<br>
+<br>
   void EmitConstantPool() override;<br>
   void EmitFunctionEntryLabel() override;<br>
   void EmitFunctionBodyStart() override;<br>
@@ -79,12 +81,14 @@ private:<br>
 } // end anonymous namespace<br>
<br>
 //===----------------------------------------------------------------------===//<br>
+// Helpers.<br>
+//===----------------------------------------------------------------------===//<br>
<br>
 // Untyped, lower-case version of the opcode's name matching the names<br>
 // WebAssembly opcodes are expected to have. The tablegen names are uppercase<br>
 // and suffixed with their type (after an underscore).<br>
-static SmallString<32> Name(const WebAssemblyInstrInfo *TII,<br>
-                            const MachineInstr *MI) {<br>
+static SmallString<32> OpcodeName(const WebAssemblyInstrInfo *TII,<br>
+                                  const MachineInstr *MI) {<br>
   std::string N(StringRef(TII->getName(MI->getOpcode())).lower());<br>
   std::string::size_type End = N.rfind('_');<br>
   End = std::string::npos == End ? N.length() : End;<br>
@@ -93,7 +97,7 @@ static SmallString<32> Name(const WebAss<br>
<br>
 static std::string toSymbol(StringRef S) { return ("$" + S).str(); }<br>
<br>
-static const char *toType(const Type *Ty) {<br>
+static const char *toString(const Type *Ty) {<br>
   switch (Ty->getTypeID()) {<br>
   default: break;<br>
   case Type::FloatTyID:  return "f32";<br>
@@ -110,6 +114,91 @@ static const char *toType(const Type *Ty<br>
   return "<invalid>";<br>
 }<br>
<br>
+static std::string toString(const APFloat &FP) {<br>
+  static const size_t BufBytes = 128;<br>
+  char buf[BufBytes];<br>
+  if (FP.isNaN())<br>
+    assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||<br>
+            FP.bitwiseIsEqual(<br>
+                APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&<br>
+           "convertToHexString handles neither SNaN nor NaN payloads");<br>
+  // Use C99's hexadecimal floating-point representation.<br>
+  auto Written = FP.convertToHexString(<br>
+      buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);<br>
+  (void)Written;<br>
+  assert(Written != 0);<br>
+  assert(Written < BufBytes);<br>
+  return buf;<br>
+}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// WebAssemblyAsmPrinter Implementation.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+void WebAssemblyAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {<br>
+  SmallString<128> Str;<br>
+  raw_svector_ostream OS(Str);<br>
+  StringRef Name = GV->getName();<br>
+  DEBUG(dbgs() << "Global " << Name << '\n');<br>
+<br>
+  if (!GV->hasInitializer()) {<br>
+    DEBUG(dbgs() << "  Skipping declaration.\n");<br>
+    return;<br>
+  }<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+  // Check to see if this is a special global used by LLVM.<br>
+  static const char *Ignored[] = {"llvm.used", "llvm.metadata"};<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  for (const char *I : Ignored)<br>
+    if (Name == I)<br>
+      return;<br></blockquote><div><br></div></div></div><div>Are you proposing that we always ignore "llvm.used" or just ignore it temporarily?<br></div></div></div></div></blockquote><div><br></div><div>Ignore it for now, I'm not sure there's point in translating it in the future, but we'll see when we get there.</div><div> <span style="color:rgb(80,0,80)"> </span></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  // FIXME: Handle the following globals.<br>
+  static const char *Unhandled[] = {"llvm.global_ctors", "llvm.global_dtors"};<br>
+  for (const char *U : Unhandled)<br>
+    if (Name == U)<br>
+      report_fatal_error("Unhandled global");<br>
+  if (Name.startswith("llvm."))<br>
+    report_fatal_error("Unknown LLVM-internal global");<br>
+<br>
+  if (GV->isThreadLocal())<br>
+    report_fatal_error("TLS isn't yet supported by WebAssembly");<br>
+<br>
+  const DataLayout &DL = getDataLayout();<br>
+  const Constant *Init = GV->getInitializer();<br>
+  if (isa<UndefValue>(Init))<br>
+    Init = Constant::getNullValue(Init->getType());<br>
+  unsigned Align = DL.getPrefTypeAlignment(Init->getType());<br>
+<br>
+  switch (GV->getLinkage()) {<br>
+  case GlobalValue::InternalLinkage:<br>
+  case GlobalValue::PrivateLinkage:<br>
+    break;<br>
+  case GlobalValue::AppendingLinkage:<br>
+  case GlobalValue::LinkOnceAnyLinkage:<br>
+  case GlobalValue::LinkOnceODRLinkage:<br>
+  case GlobalValue::WeakAnyLinkage:<br>
+  case GlobalValue::WeakODRLinkage:<br>
+  case GlobalValue::ExternalLinkage:<br>
+  case GlobalValue::CommonLinkage:<br>
+    report_fatal_error("Linkage types other than internal and private aren't "<br>
+                       "supported by WebAssembly");<br></blockquote><div><br></div></div></div><div>"yet", since we likely will support some of these eventually.<br></div></div></div></div></blockquote><div><br></div><div>Fixed.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  default:<br>
+    llvm_unreachable("Unknown linkage type");<br>
+    return;<br>
+  }<br>
+<br>
+  OS << "(global " << toSymbol(Name) << ' ' << toString(Init->getType()) << ' ';<br></blockquote><div><br></div></span><div>If this is creating a wasm global variable, it isn't correct since wasm global variables aren't in linear memory, while C++ global variables are.<br></div></div></div></div></blockquote><div><br></div><div>I'm expecting us to separately write a pass which linearizes the heap, and leaves the non-address-taken globals around for this code to handle. It seems easier to get basic things running by having globals first (instead of proper linearization). WDYT?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  if (const auto *C = dyn_cast<ConstantInt>(Init)) {<br>
+    assert(C->getBitWidth() <= 64 && "Printing wider types unimplemented");<br>
+    OS << C->getZExtValue();<br>
+  } else if (const auto *C = dyn_cast<ConstantFP>(Init)) {<br>
+    OS << toString(C->getValueAPF());<br>
+  } else {<br>
+    assert(false && "Only integer and floating-point constants are supported");<br>
+  }<br>
+  OS << ") ;; align " << Align << "\n";<br>
+  OutStreamer->EmitRawText(OS.str());<br>
+}<br>
+<br>
 void WebAssemblyAsmPrinter::EmitConstantPool() {<br>
   assert(MF->getConstantPool()->getConstants().empty() &&<br>
          "WebAssembly disables constant pools");<br>
@@ -139,10 +228,10 @@ void WebAssemblyAsmPrinter::EmitFunction<br>
   raw_svector_ostream OS(Str);<br>
   const Function *F = MF->getFunction();<br>
   for (const Argument &A : F->args())<br>
-    OS << " (param " << toType(A.getType()) << ')';<br>
+    OS << " (param " << toString(A.getType()) << ')';<br>
   const Type *Rt = F->getReturnType();<br>
   if (!Rt->isVoidTy())<br>
-    OS << " (result " << toType(Rt) << ')';<br>
+    OS << " (result " << toString(Rt) << ')';<br>
   OS << '\n';<br>
   OutStreamer->EmitRawText(OS.str());<br>
 }<br>
@@ -171,7 +260,7 @@ void WebAssemblyAsmPrinter::EmitInstruct<br>
     OS << "(setlocal @" << TargetRegisterInfo::virtReg2Index(Reg) << ' ';<br>
   }<br>
<br>
-  OS << '(' << Name(TII, MI);<br>
+  OS << '(' << OpcodeName(TII, MI);<br>
   for (const MachineOperand &MO : MI->uses())<br>
     switch (MO.getType()) {<br>
     default:<br>
@@ -186,22 +275,7 @@ void WebAssemblyAsmPrinter::EmitInstruct<br>
       OS << ' ' << MO.getImm();<br>
     } break;<br>
     case MachineOperand::MO_FPImmediate: {<br>
-      static const size_t BufBytes = 128;<br>
-      char buf[BufBytes];<br>
-      APFloat FP = MO.getFPImm()->getValueAPF();<br>
-      if (FP.isNaN())<br>
-        assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) ||<br>
-                FP.bitwiseIsEqual(<br>
-                    APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) &&<br>
-               "convertToHexString handles neither SNaN nor NaN payloads");<br>
-      // Use C99's hexadecimal floating-point representation.<br>
-      auto Written =<br>
-          FP.convertToHexString(buf, /*hexDigits=*/0, /*upperCase=*/false,<br>
-                                APFloat::rmNearestTiesToEven);<br>
-      (void)Written;<br>
-      assert(Written != 0);<br>
-      assert(Written < BufBytes);<br>
-      OS << ' ' << buf;<br>
+      OS << ' ' << toString(MO.getFPImm()->getValueAPF());<br>
     } break;<br>
     case MachineOperand::MO_GlobalAddress: {<br>
       OS << ' ' << toSymbol(MO.getGlobal()->getName());<br><br></blockquote><div><br></div></div></div><div>I'm surprised there's no GVSym = getSymbol(GV), GVSym->redefineIfPossible(), and so on, and am surprised that to see handling for things like initializers. I had expected we would just leave everything in data sections, like LLVM usually does, especially for now.</div></div></div></div></blockquote><div><br></div><div>I keyed off  XCore's AsmPrinter as well as the basic one, it seems to do the basic that spec/forward.wasm wants :-)</div></div></div></div>