authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-02 15:48:26+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-02 21:54:01+02:00
log219fa192c6311c627d4b507c928ebcf2920af9e8
treede3ef8a882d5b0abe840abaf9bd3a0c096e026ab
parent3ee44ce949117e8e91348ef870b18b23571a408d

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 files changed, 41 insertions(+), 2 deletions(-)

src/arch/wasm/CodeGen.zig+41-2
......@@ -1307,6 +1307,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
13071307 .shl_exact => self.airBinOp(inst, .shl),
13081308 .shr, .shr_exact => self.airBinOp(inst, .shr),
13091309 .xor => self.airBinOp(inst, .xor),
1310 .max => self.airMaxMin(inst, .max),
1311 .min => self.airMaxMin(inst, .min),
13101312
13111313 .add_with_overflow => self.airBinOpOverflow(inst, .add),
13121314 .sub_with_overflow => self.airBinOpOverflow(inst, .sub),
......@@ -1431,8 +1433,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
14311433 .div_floor,
14321434 .div_exact,
14331435 .mod,
1434 .max,
1435 .min,
14361436 .assembly,
14371437 .shl_sat,
14381438 .ret_addr,
......@@ -3873,3 +3873,42 @@ fn airBinOpOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue
38733873
38743874 return result_ptr;
38753875}
3876
3877fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerError!WValue {
3878 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3879 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3880 const ty = self.air.typeOfIndex(inst);
3881 if (ty.zigTypeTag() == .Vector) {
3882 return self.fail("TODO: `@maximum` and `@minimum` for vectors", .{});
3883 }
3884
3885 if (ty.abiSize(self.target) > 8) {
3886 return self.fail("TODO: `@maximum` and `@minimum` for types larger than 8 bytes", .{});
3887 }
3888
3889 const lhs = try self.resolveInst(bin_op.lhs);
3890 const rhs = try self.resolveInst(bin_op.rhs);
3891
3892 const result = try self.allocLocal(ty);
3893
3894 try self.startBlock(.block, wasm.block_empty);
3895 try self.startBlock(.block, wasm.block_empty);
3896
3897 // check if LHS is greater/lesser than RHS
3898 const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
3899 try self.addLabel(.local_get, cmp_result.local);
3900 try self.addLabel(.br_if, 0); // break to outer loop if LHS is greater/lesser than RHS
3901
3902 // set RHS as max/min
3903 try self.emitWValue(rhs);
3904 try self.addLabel(.local_set, result.local);
3905 try self.addLabel(.br, 1); // break out of all blocks
3906 try self.endBlock();
3907
3908 // set LHS as max/min
3909 try self.emitWValue(lhs);
3910 try self.addLabel(.local_set, result.local);
3911 try self.endBlock();
3912
3913 return result;
3914}