Commit 219fa192c6

Luuk de Gram <luuk@degram.dev>
2022-04-02 15:48:26
wasm: Implement `@maximum` & `@minimum`
This implements the `max` and `min` AIR instructions by checking whether LHS is great/lesser than RHS. If that's the case, we assign LHS to the result, otherwise assign RHS to it instead.
1 parent 3ee44ce
Changed files (1)
src
arch
src/arch/wasm/CodeGen.zig
@@ -1307,6 +1307,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .shl_exact => self.airBinOp(inst, .shl),
         .shr, .shr_exact => self.airBinOp(inst, .shr),
         .xor => self.airBinOp(inst, .xor),
+        .max => self.airMaxMin(inst, .max),
+        .min => self.airMaxMin(inst, .min),
 
         .add_with_overflow => self.airBinOpOverflow(inst, .add),
         .sub_with_overflow => self.airBinOpOverflow(inst, .sub),
@@ -1431,8 +1433,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .div_floor,
         .div_exact,
         .mod,
-        .max,
-        .min,
         .assembly,
         .shl_sat,
         .ret_addr,
@@ -3873,3 +3873,42 @@ fn airBinOpOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue
 
     return result_ptr;
 }
+
+fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerError!WValue {
+    if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
+    const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+    const ty = self.air.typeOfIndex(inst);
+    if (ty.zigTypeTag() == .Vector) {
+        return self.fail("TODO: `@maximum` and `@minimum` for vectors", .{});
+    }
+
+    if (ty.abiSize(self.target) > 8) {
+        return self.fail("TODO: `@maximum` and `@minimum` for types larger than 8 bytes", .{});
+    }
+
+    const lhs = try self.resolveInst(bin_op.lhs);
+    const rhs = try self.resolveInst(bin_op.rhs);
+
+    const result = try self.allocLocal(ty);
+
+    try self.startBlock(.block, wasm.block_empty);
+    try self.startBlock(.block, wasm.block_empty);
+
+    // check if LHS is greater/lesser than RHS
+    const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
+    try self.addLabel(.local_get, cmp_result.local);
+    try self.addLabel(.br_if, 0); // break to outer loop if LHS is greater/lesser than RHS
+
+    // set RHS as max/min
+    try self.emitWValue(rhs);
+    try self.addLabel(.local_set, result.local);
+    try self.addLabel(.br, 1); // break out of all blocks
+    try self.endBlock();
+
+    // set LHS as max/min
+    try self.emitWValue(lhs);
+    try self.addLabel(.local_set, result.local);
+    try self.endBlock();
+
+    return result;
+}