| ... | @@ -1317,6 +1317,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1317,6 +1317,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1317 | .mul_with_overflow => self.airBinOpOverflow(inst, .mul), | 1317 | .mul_with_overflow => self.airBinOpOverflow(inst, .mul), |
| 1318 | | 1318 | |
| 1319 | .clz => self.airClz(inst), | 1319 | .clz => self.airClz(inst), |
| | 1320 | .ctz => self.airCtz(inst), |
| 1320 | | 1321 | |
| 1321 | .cmp_eq => self.airCmp(inst, .eq), | 1322 | .cmp_eq => self.airCmp(inst, .eq), |
| 1322 | .cmp_gte => self.airCmp(inst, .gte), | 1323 | .cmp_gte => self.airCmp(inst, .gte), |
| ... | @@ -1440,7 +1441,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1440,7 +1441,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1440 | .shl_sat, | 1441 | .shl_sat, |
| 1441 | .ret_addr, | 1442 | .ret_addr, |
| 1442 | .frame_addr, | 1443 | .frame_addr, |
| 1443 | .ctz, | | |
| 1444 | .byte_swap, | 1444 | .byte_swap, |
| 1445 | .bit_reverse, | 1445 | .bit_reverse, |
| 1446 | .is_err_ptr, | 1446 | .is_err_ptr, |
| ... | @@ -3978,3 +3978,44 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3978,3 +3978,44 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3978 | try self.addLabel(.local_set, result.local); | 3978 | try self.addLabel(.local_set, result.local); |
| 3979 | return result; | 3979 | return result; |
| 3980 | } | 3980 | } |
| | 3981 | |
| | 3982 | fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| | 3983 | if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; |
| | 3984 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 3985 | const ty = self.air.typeOf(ty_op.operand); |
| | 3986 | const result_ty = self.air.typeOfIndex(inst); |
| | 3987 | |
| | 3988 | if (ty.zigTypeTag() == .Vector) { |
| | 3989 | return self.fail("TODO: `@ctz` for vectors", .{}); |
| | 3990 | } |
| | 3991 | |
| | 3992 | const operand = try self.resolveInst(ty_op.operand); |
| | 3993 | const int_info = ty.intInfo(self.target); |
| | 3994 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| | 3995 | return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits}); |
| | 3996 | }; |
| | 3997 | |
| | 3998 | switch (wasm_bits) { |
| | 3999 | 32 => { |
| | 4000 | if (wasm_bits != int_info.bits) { |
| | 4001 | const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits); |
| | 4002 | const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or"); |
| | 4003 | try self.emitWValue(bin_op); |
| | 4004 | } else try self.emitWValue(operand); |
| | 4005 | try self.addTag(.i32_ctz); |
| | 4006 | }, |
| | 4007 | 64 => { |
| | 4008 | if (wasm_bits != int_info.bits) { |
| | 4009 | const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits); |
| | 4010 | const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or"); |
| | 4011 | try self.emitWValue(bin_op); |
| | 4012 | } else try self.emitWValue(operand); |
| | 4013 | try self.addTag(.i64_ctz); |
| | 4014 | }, |
| | 4015 | else => unreachable, |
| | 4016 | } |
| | 4017 | |
| | 4018 | const result = try self.allocLocal(result_ty); |
| | 4019 | try self.addLabel(.local_set, result.local); |
| | 4020 | return result; |
| | 4021 | } |