authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-15 18:41:52+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-18 07:43:33+02:00
logea073a6b767cc6597ff2b6ec3b5f14fde81dd6fc
tree62e9740562c7e213ffd8bacde41b26ba94651a01
parent502f5d824626675aecf9daaaf6af7548ef3e7f09

wasm: Support 128bit integers for max/min/ctz/clz

`airMaxMin` was slightly updated to automatically support 128 bit integers, by using the `cmp` function, instead of doing it manually. This makes the function more maintanable as well. `ctz` and `clz` now support 128 bit integers, while updating the previous implementation also.

1 files changed, 56 insertions(+), 32 deletions(-)

src/arch/wasm/CodeGen.zig+56-32
......@@ -4154,7 +4154,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
41544154 return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits});
41554155 };
41564156
4157 if (wasm_bits == 64) {
4157 if (wasm_bits > 32) {
41584158 return self.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits});
41594159 }
41604160
......@@ -4236,32 +4236,26 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro
42364236 return self.fail("TODO: `@maximum` and `@minimum` for vectors", .{});
42374237 }
42384238
4239 if (ty.abiSize(self.target) > 8) {
4240 return self.fail("TODO: `@maximum` and `@minimum` for types larger than 8 bytes", .{});
4239 if (ty.abiSize(self.target) > 16) {
4240 return self.fail("TODO: `@maximum` and `@minimum` for types larger than 16 bytes", .{});
42414241 }
42424242
42434243 const lhs = try self.resolveInst(bin_op.lhs);
42444244 const rhs = try self.resolveInst(bin_op.rhs);
42454245
4246 // operands to select from
4247 try self.emitWValue(lhs);
4248 try self.emitWValue(rhs);
4246 const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
42494247
4250 // operands to compare
4251 try self.emitWValue(lhs);
4252 try self.emitWValue(rhs);
4253 const opcode = buildOpcode(.{
4254 .op = if (op == .max) .gt else .lt,
4255 .signedness = if (ty.isSignedInt()) .signed else .unsigned,
4256 .valtype1 = typeToValtype(ty, self.target),
4257 });
4258 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
4248 // operands to select from
4249 try self.lowerToStack(lhs);
4250 try self.lowerToStack(rhs);
4251 try self.emitWValue(cmp_result);
42594252
42604253 // based on the result from comparison, return operand 0 or 1.
42614254 try self.addTag(.select);
42624255
42634256 // store result in local
4264 const result = try self.allocLocal(ty);
4257 const result_ty = if (isByRef(ty, self.target)) Type.u32 else ty;
4258 const result = try self.allocLocal(result_ty);
42654259 try self.addLabel(.local_set, result.local);
42664260 return result;
42674261}
......@@ -4302,31 +4296,39 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
43024296 return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});
43034297 };
43044298
4305 try self.emitWValue(operand);
43064299 switch (wasm_bits) {
43074300 32 => {
4301 try self.emitWValue(operand);
43084302 try self.addTag(.i32_clz);
4309
4310 if (wasm_bits != int_info.bits) {
4311 const tmp = try self.allocLocal(ty);
4312 try self.addLabel(.local_set, tmp.local);
4313 const val: i32 = -@intCast(i32, wasm_bits - int_info.bits);
4314 return self.wrapBinOp(tmp, .{ .imm32 = @bitCast(u32, val) }, ty, .add);
4315 }
43164303 },
43174304 64 => {
4305 try self.emitWValue(operand);
43184306 try self.addTag(.i64_clz);
4307 try self.addTag(.i32_wrap_i64);
4308 },
4309 128 => {
4310 const msb = try self.load(operand, Type.u64, 0);
4311 const lsb = try self.load(operand, Type.u64, 8);
4312 const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
43194313
4320 if (wasm_bits != int_info.bits) {
4321 const tmp = try self.allocLocal(ty);
4322 try self.addLabel(.local_set, tmp.local);
4323 const val: i64 = -@intCast(i64, wasm_bits - int_info.bits);
4324 return self.wrapBinOp(tmp, .{ .imm64 = @bitCast(u64, val) }, ty, .add);
4325 }
4314 try self.emitWValue(lsb);
4315 try self.addTag(.i64_clz);
4316 try self.emitWValue(msb);
4317 try self.addTag(.i64_clz);
4318 try self.emitWValue(.{ .imm64 = 64 });
4319 try self.addTag(.i64_add);
4320 try self.emitWValue(neq);
4321 try self.addTag(.select);
4322 try self.addTag(.i32_wrap_i64);
43264323 },
43274324 else => unreachable,
43284325 }
43294326
4327 if (wasm_bits != int_info.bits) {
4328 try self.emitWValue(.{ .imm32 = wasm_bits - int_info.bits });
4329 try self.addTag(.i32_sub);
4330 }
4331
43304332 const result = try self.allocLocal(result_ty);
43314333 try self.addLabel(.local_set, result.local);
43324334 return result;
......@@ -4365,12 +4367,34 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
43654367 } else try self.emitWValue(operand);
43664368 try self.addTag(.i64_ctz);
43674369 },
4370 128 => {
4371 const msb = try self.load(operand, Type.u64, 0);
4372 const lsb = try self.load(operand, Type.u64, 8);
4373 const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
4374
4375 try self.emitWValue(msb);
4376 try self.addTag(.i64_ctz);
4377 try self.emitWValue(lsb);
4378 if (wasm_bits != int_info.bits) {
4379 try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));
4380 try self.addTag(.i64_or);
4381 }
4382 try self.addTag(.i64_ctz);
4383 try self.addImm64(64);
4384 if (wasm_bits != int_info.bits) {
4385 try self.addTag(.i64_or);
4386 } else {
4387 try self.addTag(.i64_add);
4388 }
4389 try self.emitWValue(neq);
4390 try self.addTag(.select);
4391 },
43684392 else => unreachable,
43694393 }
43704394
4371 const result = try self.allocLocal(result_ty);
4395 const result = try self.allocLocal(ty);
43724396 try self.addLabel(.local_set, result.local);
4373 return result;
4397 return self.intcast(result, ty, result_ty);
43744398}
43754399
43764400fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !WValue {