Support 64-bit data segment init-exps in Memory64 (#3593)

This as a consequence of https://reviews.llvm.org/D95651
diff --git a/src/passes/Memory64Lowering.cpp b/src/passes/Memory64Lowering.cpp
index cee174b..5e10047 100644
--- a/src/passes/Memory64Lowering.cpp
+++ b/src/passes/Memory64Lowering.cpp
@@ -91,6 +91,11 @@
   }
 
   void visitMemory(Memory* memory) {
+    for (auto& segment : memory->segments) {
+      auto* c = segment.offset->cast<Const>();
+      c->value = Literal(static_cast<uint32_t>(c->value.geti64()));
+      c->type = Type::i32;
+    }
     // This is visited last.
     memory->indexType = Type::i32;
   }
diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp
index 7848118..b5d317f 100644
--- a/src/passes/MemoryPacking.cpp
+++ b/src/passes/MemoryPacking.cpp
@@ -228,7 +228,7 @@
       }
       // Note the maximum address so far.
       maxAddress = std::max(
-        maxAddress, Address(c->value.getInteger() + segment.data.size()));
+        maxAddress, Address(c->value.getUnsigned() + segment.data.size()));
     }
   }
   // All active segments have constant offsets, known at this time, so we may be
@@ -239,7 +239,7 @@
   for (auto& segment : segments) {
     if (!segment.isPassive) {
       auto* c = segment.offset->cast<Const>();
-      Address start = c->value.getInteger();
+      Address start = c->value.getUnsigned();
       DisjointSpans::Span span{start, start + segment.data.size()};
       if (space.addAndCheckOverlap(span)) {
         std::cerr << "warning: active memory segments have overlap, which "
@@ -523,7 +523,12 @@
     Expression* offset = nullptr;
     if (!segment.isPassive) {
       if (auto* c = segment.offset->dynCast<Const>()) {
-        offset = builder.makeConst(int32_t(c->value.geti32() + range.start));
+        if (c->value.type == Type::i32) {
+          offset = builder.makeConst(int32_t(c->value.geti32() + range.start));
+        } else {
+          assert(c->value.type == Type::i64);
+          offset = builder.makeConst(int64_t(c->value.geti64() + range.start));
+        }
       } else {
         assert(ranges.size() == 1);
         offset = segment.offset;
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index b9a89c6..5032b72 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -3054,7 +3054,7 @@
           Flow ret;
           try {
             ret = this->visit(catchBody);
-          } catch (const WasmException& e) {
+          } catch (const WasmException&) {
             exceptionStack.pop_back();
             throw;
           }
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 0f5a031..ebc5888 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1354,7 +1354,7 @@
     throwError("unexpected end of input");
   }
   pos += size;
-  return {&input[pos - size], &input[pos]};
+  return {input.data() + (pos - size), input.data() + pos};
 }
 
 uint8_t WasmBinaryBuilder::getInt8() {
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index 50b4e9b..339214f 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -168,7 +168,7 @@
           segmentOffsets.push_back(UNKNOWN_OFFSET);
         }
       } else if (auto* addrConst = segment.offset->dynCast<Const>()) {
-        auto address = addrConst->value.geti32();
+        auto address = addrConst->value.getUnsigned();
         segmentOffsets.push_back(address);
       } else {
         // TODO(sbc): Wasm shared libraries have data segments with non-const
@@ -285,7 +285,7 @@
   }
 
   auto* value = arg->cast<Const>();
-  Address address = value->value.getInteger();
+  Address address = value->value.getUnsigned();
   asmConsts.push_back({address, stringTracker.stringAtAddr(address)});
 }
 
@@ -341,7 +341,7 @@
 static Address getExportedAddress(Module& wasm, Export* export_) {
   Global* g = wasm.getGlobal(export_->value);
   auto* addrConst = g->init->dynCast<Const>();
-  return addrConst->value.getInteger();
+  return addrConst->value.getUnsigned();
 }
 
 static std::vector<AsmConst> findEmAsmConsts(Module& wasm,
@@ -413,11 +413,11 @@
       return;
     }
 
-    int64_t address;
+    Address address;
     if (curr->kind == ExternalKind::Global) {
       auto* global = wasm.getGlobal(curr->value);
       Const* const_ = global->init->cast<Const>();
-      address = const_->value.getInteger();
+      address = const_->value.getUnsigned();
     } else if (curr->kind == ExternalKind::Function) {
       auto* func = wasm.getFunction(curr->value);
       // An EM_JS has a single const in the body. Typically it is just returned,
@@ -429,7 +429,7 @@
                 << curr->name;
       }
       auto* addrConst = consts.list[0];
-      address = addrConst->value.getInteger();
+      address = addrConst->value.getUnsigned();
     } else {
       return;
     }
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 1694701..339d3a0 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2615,7 +2615,12 @@
       }
       // (memory (data ..)) format
       auto j = parseMemoryIndex(inner, 1);
-      auto offset = allocator.alloc<Const>()->set(Literal(int32_t(0)));
+      auto offset = allocator.alloc<Const>();
+      if (wasm.memory.is64()) {
+        offset->set(Literal(int64_t(0)));
+      } else {
+        offset->set(Literal(int32_t(0)));
+      }
       parseInnerData(inner, j, {}, offset, false);
       wasm.memory.initial = wasm.memory.segments[0].data.size();
       return;
@@ -2641,8 +2646,13 @@
     }
     const char* input = curr[j]->c_str();
     auto* offset = allocator.alloc<Const>();
-    offset->type = Type::i32;
-    offset->value = Literal(int32_t(offsetValue));
+    if (wasm.memory.is64()) {
+      offset->type = Type::i64;
+      offset->value = Literal(offsetValue);
+    } else {
+      offset->type = Type::i32;
+      offset->value = Literal(int32_t(offsetValue));
+    }
     if (auto size = strlen(input)) {
       std::vector<char> data;
       stringToBinary(input, size, data);
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 6bcdb0e..7e9c30c 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2818,7 +2818,7 @@
                       "memory is shared, but atomics are disabled");
   }
   for (auto& segment : curr.segments) {
-    Index size = segment.data.size();
+    auto size = segment.data.size();
     if (segment.isPassive) {
       info.shouldBeTrue(module.features.hasBulkMemory(),
                         segment.offset,
@@ -2828,11 +2828,20 @@
                          segment.offset,
                          "passive segment should not have an offset");
     } else {
-      if (!info.shouldBeEqual(segment.offset->type,
-                              Type(Type::i32),
-                              segment.offset,
-                              "segment offset should be i32")) {
-        continue;
+      if (curr.is64()) {
+        if (!info.shouldBeEqual(segment.offset->type,
+                                Type(Type::i64),
+                                segment.offset,
+                                "segment offset should be i64")) {
+          continue;
+        }
+      } else {
+        if (!info.shouldBeEqual(segment.offset->type,
+                                Type(Type::i32),
+                                segment.offset,
+                                "segment offset should be i32")) {
+          continue;
+        }
       }
       info.shouldBeTrue(checkSegmentOffset(segment.offset,
                                            segment.data.size(),
@@ -2840,8 +2849,8 @@
                         segment.offset,
                         "memory segment offset should be reasonable");
       if (segment.offset->is<Const>()) {
-        Index start = segment.offset->cast<Const>()->value.geti32();
-        Index end = start + size;
+        auto start = segment.offset->cast<Const>()->value.getUnsigned();
+        auto end = start + size;
         info.shouldBeTrue(end <= curr.initial * Memory::kPageSize,
                           segment.data.size(),
                           "segment size should fit in memory (end)");
diff --git a/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast b/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast
index f70444f..15ea29e 100644
--- a/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast
+++ b/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast
@@ -1,6 +1,6 @@
 (module
  (memory $0 i64 1 1)
- (data (i32.const 0) "\00\00\00\00\00\00\00\00\00\00")
+ (data (i64.const 0) "\00\00\00\00\00\00\00\00\00\00")
  (func $func_1
   (local i64)
   (drop (i32.load (i64.const 4)))
diff --git a/test/spec/address64.wast b/test/spec/address64.wast
index 0003e5d..b3b009a 100644
--- a/test/spec/address64.wast
+++ b/test/spec/address64.wast
@@ -2,7 +2,7 @@
 
 (module
   (memory i64 1)
-  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+  (data (i64.const 0) "abcdefghijklmnopqrstuvwxyz")
 
   (func (export "8u_good1") (param $i i64) (result i32)
     (i32.load8_u offset=0 (local.get $i))                   ;; 97 'a'
@@ -215,7 +215,7 @@
 
 (module
   (memory i64 1)
-  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+  (data (i64.const 0) "abcdefghijklmnopqrstuvwxyz")
 
   (func (export "8u_good1") (param $i i64) (result i64)
     (i64.load8_u offset=0 (local.get $i))                   ;; 97 'a'
@@ -498,7 +498,7 @@
 
 (module
   (memory i64 1)
-  (data (i32.const 0) "\00\00\00\00\00\00\a0\7f\01\00\d0\7f")
+  (data (i64.const 0) "\00\00\00\00\00\00\a0\7f\01\00\d0\7f")
 
   (func (export "32_good1") (param $i i64) (result f32)
     (f32.load offset=0 (local.get $i))                   ;; 0.0 '\00\00\00\00'
@@ -545,7 +545,7 @@
 
 (module
   (memory i64 1)
-  (data (i32.const 0) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\f4\7f\01\00\00\00\00\00\fc\7f")
+  (data (i64.const 0) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\f4\7f\01\00\00\00\00\00\fc\7f")
 
   (func (export "64_good1") (param $i i64) (result f64)
     (f64.load offset=0 (local.get $i))                     ;; 0.0 '\00\00\00\00\00\00\00\00'
diff --git a/test/spec/bulk-memory64.wast b/test/spec/bulk-memory64.wast
index 5d0090e..6c0ec7b 100644
--- a/test/spec/bulk-memory64.wast
+++ b/test/spec/bulk-memory64.wast
@@ -46,7 +46,7 @@
 ;; memory.copy
 (module
   (memory i64 1 1)
-  (data (i32.const 0) "\aa\bb\cc\dd")
+  (data (i64.const 0) "\aa\bb\cc\dd")
 
   (func (export "copy") (param i64 i64 i64)
     (memory.copy
@@ -153,7 +153,7 @@
 (module
   (memory i64 1)
   (data passive "")
-  (data (i32.const 0) "")
+  (data (i64.const 0) "")
 
   (func (export "drop_passive") (data.drop 0))
   (func (export "init_passive")
diff --git a/test/spec/memory64.wast b/test/spec/memory64.wast
index 8424e0c..da4ba59 100644
--- a/test/spec/memory64.wast
+++ b/test/spec/memory64.wast
@@ -52,7 +52,7 @@
 
 (module
   (memory i64 1)
-  (data (i32.const 0) "ABC\a7D") (data (i32.const 20) "WASM")
+  (data (i64.const 0) "ABC\a7D") (data (i64.const 20) "WASM")
 
   ;; Data section
   (func (export "data") (result i32)
diff --git a/test/spec/memory_trap64.wast b/test/spec/memory_trap64.wast
index 77e802a..78d39d8 100644
--- a/test/spec/memory_trap64.wast
+++ b/test/spec/memory_trap64.wast
@@ -33,8 +33,8 @@
 
 (module
   (memory i64 1)
-  (data (i32.const 0) "abcdefgh")
-  (data (i32.const 0xfff8) "abcdefgh")
+  (data (i64.const 0) "abcdefgh")
+  (data (i64.const 0xfff8) "abcdefgh")
 
   (func (export "i32.load") (param $a i64) (result i32)
     (i32.load (local.get $a))
diff --git a/test/spec/old_address64.wast b/test/spec/old_address64.wast
index 5fd193b..4036809 100644
--- a/test/spec/old_address64.wast
+++ b/test/spec/old_address64.wast
@@ -2,7 +2,7 @@
   (import "spectest" "print" (func $print (param i32)))
 
   (memory i64 1)
-  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+  (data (i64.const 0) "abcdefghijklmnopqrstuvwxyz")
 
   (func (export "good") (param $i i64)
     (call $print (i32.load8_u offset=0 (local.get $i)))  ;; 97 'a'