| ... | @@ -2669,8 +2669,14 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner | ... | @@ -2669,8 +2669,14 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner |
| 2669 | .signed => return func.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), | 2669 | .signed => return func.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), |
| 2670 | .unsigned => return func.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), | 2670 | .unsigned => return func.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), |
| 2671 | }, | 2671 | }, |
| 2672 | .rem => return func.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), | 2672 | .rem => switch (int_info.signedness) { |
| 2673 | .shr => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), | 2673 | .signed => return func.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), |
| | 2674 | .unsigned => return func.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), |
| | 2675 | }, |
| | 2676 | .shr => switch (int_info.signedness) { |
| | 2677 | .signed => return func.callIntrinsic("__ashrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), |
| | 2678 | .unsigned => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), |
| | 2679 | }, |
| 2674 | .shl => return func.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), | 2680 | .shl => return func.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), |
| 2675 | .@"and", .@"or", .xor => { | 2681 | .@"and", .@"or", .xor => { |
| 2676 | const result = try func.allocStack(ty); | 2682 | const result = try func.allocStack(ty); |
| ... | @@ -6055,14 +6061,14 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6055,14 +6061,14 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6055 | | 6061 | |
| 6056 | const lhs = try func.resolveInst(extra.lhs); | 6062 | const lhs = try func.resolveInst(extra.lhs); |
| 6057 | const rhs = try func.resolveInst(extra.rhs); | 6063 | const rhs = try func.resolveInst(extra.rhs); |
| 6058 | const lhs_ty = func.typeOf(extra.lhs); | 6064 | const ty = func.typeOf(extra.lhs); |
| 6059 | const rhs_ty = func.typeOf(extra.rhs); | 6065 | const rhs_ty = func.typeOf(extra.rhs); |
| 6060 | | 6066 | |
| 6061 | if (lhs_ty.zigTypeTag(mod) == .Vector) { | 6067 | if (ty.zigTypeTag(mod) == .Vector) { |
| 6062 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); | 6068 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); |
| 6063 | } | 6069 | } |
| 6064 | | 6070 | |
| 6065 | const int_info = lhs_ty.intInfo(mod); | 6071 | const int_info = ty.intInfo(mod); |
| 6066 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 6072 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6067 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); | 6073 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 6068 | }; | 6074 | }; |
| ... | @@ -6070,32 +6076,28 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6070,32 +6076,28 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6070 | // Ensure rhs is coerced to lhs as they must have the same WebAssembly types | 6076 | // Ensure rhs is coerced to lhs as they must have the same WebAssembly types |
| 6071 | // before we can perform any binary operation. | 6077 | // before we can perform any binary operation. |
| 6072 | const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(mod).bits).?; | 6078 | const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(mod).bits).?; |
| 6073 | const rhs_final = if (wasm_bits != rhs_wasm_bits) blk: { | 6079 | // If wasm_bits == 128, compiler-rt expects i32 for shift |
| 6074 | const rhs_casted = try func.intcast(rhs, rhs_ty, lhs_ty); | 6080 | const rhs_final = if (wasm_bits != rhs_wasm_bits and wasm_bits == 64) blk: { |
| 6075 | break :blk try rhs_casted.toLocal(func, lhs_ty); | 6081 | const rhs_casted = try func.intcast(rhs, rhs_ty, ty); |
| | 6082 | break :blk try rhs_casted.toLocal(func, ty); |
| 6076 | } else rhs; | 6083 | } else rhs; |
| 6077 | | 6084 | |
| 6078 | var shl = try (try func.binOp(lhs, rhs_final, lhs_ty, .shl)).toLocal(func, lhs_ty); | 6085 | var shl = try (try func.wrapBinOp(lhs, rhs_final, ty, .shl)).toLocal(func, ty); |
| 6079 | defer shl.free(func); | 6086 | defer shl.free(func); |
| 6080 | var result = if (wasm_bits != int_info.bits) blk: { | | |
| 6081 | break :blk try (try func.wrapOperand(shl, lhs_ty)).toLocal(func, lhs_ty); | | |
| 6082 | } else shl; | | |
| 6083 | defer result.free(func); // it's a no-op to free the same local twice (when wasm_bits == int_info.bits) | | |
| 6084 | | 6087 | |
| 6085 | const overflow_bit = blk: { | 6088 | const overflow_bit = blk: { |
| 6086 | try func.emitWValue(lhs); | 6089 | const shr = try func.binOp(shl, rhs_final, ty, .shr); |
| 6087 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); | 6090 | break :blk try func.cmp(shr, lhs, ty, .neq); |
| 6088 | break :blk try func.cmp(.stack, shr, lhs_ty, .neq); | | |
| 6089 | }; | 6091 | }; |
| 6090 | var overflow_local = try overflow_bit.toLocal(func, Type.u1); | 6092 | var overflow_local = try overflow_bit.toLocal(func, Type.u1); |
| 6091 | defer overflow_local.free(func); | 6093 | defer overflow_local.free(func); |
| 6092 | | 6094 | |
| 6093 | const result_ptr = try func.allocStack(func.typeOfIndex(inst)); | 6095 | const result = try func.allocStack(func.typeOfIndex(inst)); |
| 6094 | try func.store(result_ptr, result, lhs_ty, 0); | 6096 | const offset: u32 = @intCast(ty.abiSize(pt)); |
| 6095 | const offset = @as(u32, @intCast(lhs_ty.abiSize(pt))); | 6097 | try func.store(result, shl, ty, 0); |
| 6096 | try func.store(result_ptr, overflow_local, Type.u1, offset); | 6098 | try func.store(result, overflow_local, Type.u1, offset); |
| 6097 | | 6099 | |
| 6098 | return func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); | 6100 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); |
| 6099 | } | 6101 | } |
| 6100 | | 6102 | |
| 6101 | fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6103 | fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |