aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-05-15 18:41:52 +0200
committerLuuk de Gram <luuk@degram.dev>2022-05-18 07:43:33 +0200
commitea073a6b767cc6597ff2b6ec3b5f14fde81dd6fc (patch)
tree62e9740562c7e213ffd8bacde41b26ba94651a01
parent502f5d824626675aecf9daaaf6af7548ef3e7f09 (diff)
downloadzig-ea073a6b767cc6597ff2b6ec3b5f14fde81dd6fc.tar.gz
zig-ea073a6b767cc6597ff2b6ec3b5f14fde81dd6fc.zip
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.
-rw-r--r--src/arch/wasm/CodeGen.zig88
1 files changed, 56 insertions, 32 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 001ffa8e7e..3193361efe 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -4154,7 +4154,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits});
};
- if (wasm_bits == 64) {
+ if (wasm_bits > 32) {
return self.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits});
}
@@ -4236,32 +4236,26 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro
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", .{});
+ if (ty.abiSize(self.target) > 16) {
+ return self.fail("TODO: `@maximum` and `@minimum` for types larger than 16 bytes", .{});
}
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
- // operands to select from
- try self.emitWValue(lhs);
- try self.emitWValue(rhs);
+ const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
- // operands to compare
- try self.emitWValue(lhs);
- try self.emitWValue(rhs);
- const opcode = buildOpcode(.{
- .op = if (op == .max) .gt else .lt,
- .signedness = if (ty.isSignedInt()) .signed else .unsigned,
- .valtype1 = typeToValtype(ty, self.target),
- });
- try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
+ // operands to select from
+ try self.lowerToStack(lhs);
+ try self.lowerToStack(rhs);
+ try self.emitWValue(cmp_result);
// based on the result from comparison, return operand 0 or 1.
try self.addTag(.select);
// store result in local
- const result = try self.allocLocal(ty);
+ const result_ty = if (isByRef(ty, self.target)) Type.u32 else ty;
+ const result = try self.allocLocal(result_ty);
try self.addLabel(.local_set, result.local);
return result;
}
@@ -4302,31 +4296,39 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});
};
- try self.emitWValue(operand);
switch (wasm_bits) {
32 => {
+ try self.emitWValue(operand);
try self.addTag(.i32_clz);
-
- if (wasm_bits != int_info.bits) {
- const tmp = try self.allocLocal(ty);
- try self.addLabel(.local_set, tmp.local);
- const val: i32 = -@intCast(i32, wasm_bits - int_info.bits);
- return self.wrapBinOp(tmp, .{ .imm32 = @bitCast(u32, val) }, ty, .add);
- }
},
64 => {
+ try self.emitWValue(operand);
try self.addTag(.i64_clz);
+ try self.addTag(.i32_wrap_i64);
+ },
+ 128 => {
+ const msb = try self.load(operand, Type.u64, 0);
+ const lsb = try self.load(operand, Type.u64, 8);
+ const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
- if (wasm_bits != int_info.bits) {
- const tmp = try self.allocLocal(ty);
- try self.addLabel(.local_set, tmp.local);
- const val: i64 = -@intCast(i64, wasm_bits - int_info.bits);
- return self.wrapBinOp(tmp, .{ .imm64 = @bitCast(u64, val) }, ty, .add);
- }
+ try self.emitWValue(lsb);
+ try self.addTag(.i64_clz);
+ try self.emitWValue(msb);
+ try self.addTag(.i64_clz);
+ try self.emitWValue(.{ .imm64 = 64 });
+ try self.addTag(.i64_add);
+ try self.emitWValue(neq);
+ try self.addTag(.select);
+ try self.addTag(.i32_wrap_i64);
},
else => unreachable,
}
+ if (wasm_bits != int_info.bits) {
+ try self.emitWValue(.{ .imm32 = wasm_bits - int_info.bits });
+ try self.addTag(.i32_sub);
+ }
+
const result = try self.allocLocal(result_ty);
try self.addLabel(.local_set, result.local);
return result;
@@ -4365,12 +4367,34 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
} else try self.emitWValue(operand);
try self.addTag(.i64_ctz);
},
+ 128 => {
+ const msb = try self.load(operand, Type.u64, 0);
+ const lsb = try self.load(operand, Type.u64, 8);
+ const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
+
+ try self.emitWValue(msb);
+ try self.addTag(.i64_ctz);
+ try self.emitWValue(lsb);
+ if (wasm_bits != int_info.bits) {
+ try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));
+ try self.addTag(.i64_or);
+ }
+ try self.addTag(.i64_ctz);
+ try self.addImm64(64);
+ if (wasm_bits != int_info.bits) {
+ try self.addTag(.i64_or);
+ } else {
+ try self.addTag(.i64_add);
+ }
+ try self.emitWValue(neq);
+ try self.addTag(.select);
+ },
else => unreachable,
}
- const result = try self.allocLocal(result_ty);
+ const result = try self.allocLocal(ty);
try self.addLabel(.local_set, result.local);
- return result;
+ return self.intcast(result, ty, result_ty);
}
fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !WValue {