Commit 1150fc13dc

Luuk de Gram <luuk@degram.dev>
2021-07-19 15:56:02
wasm: Resolve regressions, add intcast support
1 parent 9575629
Changed files (1)
src
codegen
src/codegen/wasm.zig
@@ -24,8 +24,8 @@ const WValue = union(enum) {
     none: void,
     /// Index of the local variable
     local: u32,
-    /// Instruction holding a constant `Value`
-    constant: Air.Inst.Index,
+    /// Holds a memoized typed value
+    constant: TypedValue,
     /// Offset position in the list of bytecode instructions
     code_offset: usize,
     /// Used for variables that create multiple locals on the stack when allocated
@@ -484,7 +484,7 @@ pub const Result = union(enum) {
 };
 
 /// Hashmap to store generated `WValue` for each `Air.Inst.Ref`
-pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Ref, WValue);
+pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue);
 
 /// Code represents the `Code` section of wasm that
 /// belongs to a function
@@ -548,14 +548,23 @@ pub const Context = struct {
     /// Resolves the `WValue` for the given instruction `inst`
     /// When the given instruction has a `Value`, it returns a constant instead
     fn resolveInst(self: Context, ref: Air.Inst.Ref) WValue {
-        const ref_type = self.air.getRefType(ref);
-        if (ref_type.hasCodeGenBits()) return .none;
+        const inst_index = Air.refToIndex(ref) orelse {
+            const tv = Air.Inst.Ref.typed_value_map[@enumToInt(ref)];
+            if (!tv.ty.hasCodeGenBits()) {
+                return WValue.none;
+            }
+            return WValue{ .constant = tv };
+        };
 
-        if (self.air.instructions.items(.tag)[@enumToInt(ref)] == .constant) {
-            return WValue{ .constant = @enumToInt(ref) };
+        const inst_type = self.air.typeOfIndex(inst_index);
+        if (!inst_type.hasCodeGenBits()) return .none;
+
+        if (self.air.instructions.items(.tag)[inst_index] == .constant) {
+            const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;
+            return WValue{ .constant = .{ .ty = inst_type, .val = self.air.values[ty_pl.payload] } };
         }
 
-        return self.values.get(ref).?; // Instruction does not dominate all uses!
+        return self.values.get(inst_index).?; // Instruction does not dominate all uses!
     }
 
     /// Using a given `Type`, returns the corresponding wasm Valtype
@@ -611,12 +620,7 @@ pub const Context = struct {
                 try writer.writeByte(wasm.opcode(.local_get));
                 try leb.writeULEB128(writer, idx);
             },
-            .constant => |index| {
-                const ty_pl = self.air.instructions.items(.data)[index].ty_pl;
-                const value = self.air.values[ty_pl.payload];
-                // create a new constant onto the stack
-                try self.emitConstant(value, self.air.getRefType(ty_pl.ty));
-            },
+            .constant => |tv| try self.emitConstant(tv.val, tv.ty), // Creates a new constant on the stack
         }
     }
 
@@ -838,7 +842,7 @@ pub const Context = struct {
     fn genBody(self: *Context, body: []const Air.Inst.Index) InnerError!void {
         for (body) |inst| {
             const result = try self.genInst(inst);
-            try self.values.putNoClobber(self.gpa, @intToEnum(Air.Inst.Ref, inst), result);
+            try self.values.putNoClobber(self.gpa, inst, result);
         }
     }
 
@@ -856,8 +860,7 @@ pub const Context = struct {
         const args = self.air.extra[extra.end..][0..extra.data.args_len];
 
         const target: *Decl = blk: {
-            const ty_pl = self.air.instructions.items(.data)[@enumToInt(pl_op.operand)].ty_pl;
-            const func_val = self.air.values[ty_pl.payload];
+            const func_val = self.air.value(pl_op.operand).?;
 
             if (func_val.castTag(.function)) |func| {
                 break :blk func.data.owner_decl;
@@ -868,7 +871,7 @@ pub const Context = struct {
         };
 
         for (args) |arg| {
-            const arg_val = self.resolveInst(@intToEnum(Air.Inst.Ref, arg));
+            const arg_val = self.resolveInst(Air.indexToRef(arg));
             try self.emitWValue(arg_val);
         }
 
@@ -902,7 +905,7 @@ pub const Context = struct {
                 // we simply assign the local_index to the rhs one.
                 // This allows us to update struct fields without having to individually
                 // set each local as each field's index will be calculated off the struct's base index
-                .multi_value => self.values.put(self.gpa, bin_op.lhs, rhs) catch unreachable, // Instruction does not dominate all uses!
+                .multi_value => self.values.put(self.gpa, Air.refToIndex(bin_op.lhs).?, rhs) catch unreachable, // Instruction does not dominate all uses!
                 .constant, .none => {
                     // emit all values onto the stack if constant
                     try self.emitWValue(rhs);
@@ -1294,10 +1297,8 @@ pub const Context = struct {
             try self.startBlock(.block, blocktype, null);
             try self.emitWValue(target);
 
-            // cases must represent a constant of which its type is in the `typed_value_map`
-            // Therefore we can simply retrieve it.
-            const ty_val = Air.Inst.Ref.typed_value_map[@enumToInt(case.data.item)];
-            try self.emitConstant(ty_val.val, target_ty);
+            const val = self.air.value(case.data.item).?;
+            try self.emitConstant(val, target_ty);
             const opcode = buildOpcode(.{
                 .valtype1 = valtype,
                 .op = .ne, // not equal because we jump out the block if it does not match the condition