From f8e1622bf0835dec2bb97bcb73281d34dbde4e2d Mon Sep 17 00:00:00 2001
From: Thomas Lively <tlively@google.com>
Date: Tue, 26 Nov 2024 21:57:29 -0800
Subject: Use IRBuilder in the binary parser (#6963)

IRBuilder is a utility for turning arbitrary valid streams of Wasm
instructions into valid Binaryen IR. It is already used in the text
parser, so now use it in the binary parser as well. Since the IRBuilder
API for building each intruction requires only the information that the
binary and text formats include as immediates to that instruction, the
parser is now much simpler than before. In particular, it does not need
to manage a stack of instructions to figure out what the children of
each expression should be; IRBuilder handles this instead.

There are some differences between the IR constructed by IRBuilder and
the IR the binary parser constructed before this change. Most
importantly, IRBuilder generates better multivalue code because it
avoids eagerly breaking up multivalue results into individual components
that might need to be immediately reassembled into a tuple. It also
parses try-delegate more correctly, allowing the delegate to target
arbitrary labels, not just other `try`s. There are also a couple
superficial differences in the generated label and scratch local names.

As part of this change, add support for recording binary source
locations in IRBuilder.
---
 src/wasm/wasm-ir-builder.cpp | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

(limited to 'src/wasm/wasm-ir-builder.cpp')

diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index 54cd0149e..fcb1fc48d 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -150,6 +150,12 @@ void IRBuilder::push(Expression* expr) {
   scope.exprStack.push_back(expr);
 
   applyDebugLoc(expr);
+  if (binaryPos && func && lastBinaryPos != *binaryPos) {
+    func->expressionLocations[expr] =
+      BinaryLocations::Span{BinaryLocation(lastBinaryPos - codeSectionOffset),
+                            BinaryLocation(*binaryPos - codeSectionOffset)};
+    lastBinaryPos = *binaryPos;
+  }
 
   DBG(std::cerr << "After pushing " << ShallowExpression{expr} << ":\n");
   DBG(dump());
@@ -708,6 +714,11 @@ Result<> IRBuilder::visitFunctionStart(Function* func) {
   debugLoc = CanReceiveDebug();
   scopeStack.push_back(ScopeCtx::makeFunc(func));
   this->func = func;
+
+  if (binaryPos) {
+    lastBinaryPos = *binaryPos;
+  }
+
   return Ok{};
 }
 
@@ -841,6 +852,12 @@ Result<> IRBuilder::visitElse() {
   auto expr = finishScope();
   CHECK_ERR(expr);
   iff->ifTrue = *expr;
+
+  if (binaryPos && func) {
+    func->delimiterLocations[iff][BinaryLocations::Else] =
+      lastBinaryPos - codeSectionOffset;
+  }
+
   pushScope(ScopeCtx::makeElse(iff, originalLabel, label, labelUsed));
   return Ok{};
 }
@@ -868,6 +885,12 @@ Result<> IRBuilder::visitCatch(Name tag) {
     tryy->catchBodies.push_back(*expr);
   }
   tryy->catchTags.push_back(tag);
+
+  if (binaryPos && func) {
+    auto& delimiterLocs = func->delimiterLocations[tryy];
+    delimiterLocs[delimiterLocs.size()] = lastBinaryPos - codeSectionOffset;
+  }
+
   pushScope(
     ScopeCtx::makeCatch(tryy, originalLabel, label, labelUsed, branchLabel));
   // Push a pop for the exception payload if necessary.
@@ -878,6 +901,7 @@ Result<> IRBuilder::visitCatch(Name tag) {
     scopeStack[0].notePop();
     push(builder.makePop(params));
   }
+
   return Ok{};
 }
 
@@ -903,6 +927,12 @@ Result<> IRBuilder::visitCatchAll() {
   } else {
     tryy->catchBodies.push_back(*expr);
   }
+
+  if (binaryPos && func) {
+    auto& delimiterLocs = func->delimiterLocations[tryy];
+    delimiterLocs[delimiterLocs.size()] = lastBinaryPos - codeSectionOffset;
+  }
+
   pushScope(
     ScopeCtx::makeCatchAll(tryy, originalLabel, label, labelUsed, branchLabel));
   return Ok{};
@@ -980,6 +1010,10 @@ Result<> IRBuilder::visitEnd() {
     return block;
   };
 
+  // The binary position we record for the block instruction should start at the
+  // beginning of the block, not at the beginning of the `end`.
+  lastBinaryPos = scope.startPos;
+
   if (auto* func = scope.getFunction()) {
     func->body = maybeWrapForLabel(*expr);
     labelDepths.clear();
-- 
cgit v1.2.3