From f3d635b6683ba4a53f82ae8087b1cf78552abac5 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 18 Dec 2021 04:42:13 +0100 Subject: stage2: @addWithOverflow --- src/codegen/llvm.zig | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 58239fdaea..d12dad2403 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1714,6 +1714,8 @@ pub const FuncGen = struct { .max => try self.airMax(inst), .slice => try self.airSlice(inst), + .add_with_overflow => try self.airAddWithOverflow(inst), + .bit_and, .bool_and => try self.airAnd(inst), .bit_or, .bool_or => try self.airOr(inst), .xor => try self.airXor(inst), @@ -3133,6 +3135,38 @@ pub const FuncGen = struct { } } + fn airAddWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + if (self.liveness.isUnused(inst)) + return null; + + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const extra = self.air.extraData(Air.Bin, pl_op.payload).data; + + const ptr = try self.resolveInst(pl_op.operand); + const lhs = try self.resolveInst(extra.lhs); + const rhs = try self.resolveInst(extra.rhs); + + const ptr_ty = self.air.typeOf(pl_op.operand); + const lhs_ty = self.air.typeOf(extra.lhs); + + const intrinsic_name: []const u8 = if (lhs_ty.isSignedInt()) + "llvm.sadd.with.overflow" + else + "llvm.uadd.with.overflow"; + + const llvm_lhs_ty = try self.dg.llvmType(lhs_ty); + + const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty}); + const result_struct = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, ""); + + const result = self.builder.buildExtractValue(result_struct, 0, ""); + const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); + + self.store(ptr, ptr_ty, result, .NotAtomic); + + return overflow_bit; + } + fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; @@ -3511,7 +3545,7 @@ pub const FuncGen = struct { fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { _ = inst; - const llvm_fn = self.getIntrinsic("llvm.debugtrap"); + const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{}); _ = self.builder.buildCall(llvm_fn, undefined, 0, .C, .Auto, ""); return null; } @@ -3946,13 +3980,10 @@ pub const FuncGen = struct { return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, ""); } - fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value { + fn getIntrinsic(self: *FuncGen, name: []const u8, types: []*const llvm.Type) *const llvm.Value { const id = llvm.lookupIntrinsicID(name.ptr, name.len); assert(id != 0); - // TODO: add support for overload intrinsics by passing the prefix of the intrinsic - // to `lookupIntrinsicID` and then passing the correct types to - // `getIntrinsicDeclaration` - return self.llvmModule().getIntrinsicDeclaration(id, null, 0); + return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len); } fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) ?*const llvm.Value { -- cgit v1.2.3 From ddd2ef822f99979d3ea61583a91ab236942e6367 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 18 Dec 2021 06:11:46 +0100 Subject: stage2: @returnAddress() --- src/Air.zig | 4 ++++ src/Liveness.zig | 1 + src/Sema.zig | 6 +++++- src/arch/aarch64/CodeGen.zig | 5 +++++ src/arch/arm/CodeGen.zig | 5 +++++ src/arch/riscv64/CodeGen.zig | 5 +++++ src/arch/x86_64/CodeGen.zig | 5 +++++ src/codegen/c.zig | 5 +++++ src/codegen/llvm.zig | 10 ++++++++++ src/print_air.zig | 1 + 10 files changed, 46 insertions(+), 1 deletion(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Air.zig b/src/Air.zig index 72e281d03e..9e4a61b9a2 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -195,6 +195,9 @@ pub const Inst = struct { /// Lowers to a hardware trap instruction, or the next best thing. /// Result type is always void. breakpoint, + /// Yields the return address of the current function. + /// Uses the `no_op` field. + ret_addr, /// Function call. /// Result type is the return type of the function being called. /// Uses the `pl_op` field with the `Call` payload. operand is the callee. @@ -785,6 +788,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .ptrtoint, .slice_len, + .ret_addr, => return Type.initTag(.usize), .bool_to_int => return Type.initTag(.u1), diff --git a/src/Liveness.zig b/src/Liveness.zig index a7128e2cc2..160a2e97d3 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -281,6 +281,7 @@ fn analyzeInst( .dbg_stmt, .unreach, .fence, + .ret_addr, => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), .not, diff --git a/src/Sema.zig b/src/Sema.zig index 9b9371c856..03ee58dc06 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8739,8 +8739,12 @@ fn zirRetAddr( block: *Block, extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { + const tracy = trace(@src()); + defer tracy.end(); + const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; - return sema.fail(block, src, "TODO: implement Sema.zirRetAddr", .{}); + try sema.requireRuntimeBlock(block, src); + return try block.addNoOp(.ret_addr); } fn zirBuiltinSrc( diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index fda673631d..1c6d54485b 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -547,6 +547,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .block => try self.airBlock(inst), .br => try self.airBr(inst), .breakpoint => try self.airBreakpoint(), + .ret_addr => try self.airRetAddr(), .fence => try self.airFence(), .call => try self.airCall(inst), .cond_br => try self.airCondBr(inst), @@ -1416,6 +1417,10 @@ fn airBreakpoint(self: *Self) !void { return self.finishAirBookkeeping(); } +fn airRetAddr(self: *Self) !void { + return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch}); +} + fn airFence(self: *Self) !void { return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch}); //return self.finishAirBookkeeping(); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index bcc1b927e7..0039d78434 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -545,6 +545,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .block => try self.airBlock(inst), .br => try self.airBr(inst), .breakpoint => try self.airBreakpoint(), + .ret_addr => try self.airRetAddr(), .fence => try self.airFence(), .call => try self.airCall(inst), .cond_br => try self.airCondBr(inst), @@ -1850,6 +1851,10 @@ fn airBreakpoint(self: *Self) !void { return self.finishAirBookkeeping(); } +fn airRetAddr(self: *Self) !void { + return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch}); +} + fn airFence(self: *Self) !void { return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch}); //return self.finishAirBookkeeping(); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 1d67ad0abf..51703681e9 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -526,6 +526,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .block => try self.airBlock(inst), .br => try self.airBr(inst), .breakpoint => try self.airBreakpoint(), + .ret_addr => try self.airRetAddr(), .fence => try self.airFence(), .call => try self.airCall(inst), .cond_br => try self.airCondBr(inst), @@ -1354,6 +1355,10 @@ fn airBreakpoint(self: *Self) !void { return self.finishAirBookkeeping(); } +fn airRetAddr(self: *Self) !void { + return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch}); +} + fn airFence(self: *Self) !void { return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch}); //return self.finishAirBookkeeping(); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 8fadcdd5f5..3b40293527 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -579,6 +579,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .block => try self.airBlock(inst), .br => try self.airBr(inst), .breakpoint => try self.airBreakpoint(), + .ret_addr => try self.airRetAddr(), .fence => try self.airFence(), .call => try self.airCall(inst), .cond_br => try self.airCondBr(inst), @@ -1839,6 +1840,10 @@ fn airBreakpoint(self: *Self) !void { return self.finishAirBookkeeping(); } +fn airRetAddr(self: *Self) !void { + return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch}); +} + fn airFence(self: *Self) !void { return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch}); //return self.finishAirBookkeeping(); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index b086d15b48..070aa0a238 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1125,6 +1125,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .arg => airArg(f), .breakpoint => try airBreakpoint(f), + .ret_addr => try airRetAddr(f), .unreach => try airUnreach(f), .fence => try airFence(f, inst), @@ -2191,6 +2192,10 @@ fn airBreakpoint(f: *Function) !CValue { return CValue.none; } +fn airRetAddr(f: *Function) !CValue { + return f.fail("TODO implement codegen for airRetAddr", .{}); +} + fn airFence(f: *Function, inst: Air.Inst.Index) !CValue { const atomic_order = f.air.instructions.items(.data)[inst].fence; const writer = f.object.writer(); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index d12dad2403..0a2b12dd1e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1747,6 +1747,7 @@ pub const FuncGen = struct { .br => try self.airBr(inst), .switch_br => try self.airSwitchBr(inst), .breakpoint => try self.airBreakpoint(inst), + .ret_addr => try self.airRetAddr(inst), .call => try self.airCall(inst), .cond_br => try self.airCondBr(inst), .intcast => try self.airIntCast(inst), @@ -3550,6 +3551,15 @@ pub const FuncGen = struct { return null; } + fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + _ = inst; + const i32_zero = self.context.intType(32).constNull(); + const usize_llvm_ty = try self.dg.llvmType(Type.usize); + const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{}); + const ptr_val = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{i32_zero}, 1, .Fast, .Auto, ""); + return self.builder.buildPtrToInt(ptr_val, usize_llvm_ty, ""); + } + fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { const atomic_order = self.air.instructions.items(.data)[inst].fence; const llvm_memory_order = toLlvmAtomicOrdering(atomic_order); diff --git a/src/print_air.zig b/src/print_air.zig index e11826c874..17af7ebf62 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -159,6 +159,7 @@ const Writer = struct { .breakpoint, .unreach, + .ret_addr, => try w.writeNoOp(s, inst), .const_ty, -- cgit v1.2.3 From c47ed0c912d2f445710fe4486fa071dd63601989 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 20 Dec 2021 02:06:09 +0100 Subject: stage2: @mulWithOverflow --- src/Air.zig | 10 +++++++- src/Liveness.zig | 2 +- src/Sema.zig | 56 +++++++++++++++++++++++++++++++++++++++---- src/arch/aarch64/CodeGen.zig | 6 +++++ src/arch/arm/CodeGen.zig | 6 +++++ src/arch/riscv64/CodeGen.zig | 6 +++++ src/arch/x86_64/CodeGen.zig | 6 +++++ src/codegen/c.zig | 7 ++++++ src/codegen/llvm.zig | 15 +++++++----- src/print_air.zig | 7 ++++-- src/value.zig | 48 +++++++++++++++++++++++++------------ test/behavior/math.zig | 24 +++++++++++++++++++ test/behavior/math_stage1.zig | 8 ------- 13 files changed, 164 insertions(+), 37 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Air.zig b/src/Air.zig index 9e4a61b9a2..5d54be7392 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -141,6 +141,12 @@ pub const Inst = struct { /// of the operation. /// Uses the `pl_op` field with payload `Bin`. add_with_overflow, + /// Integer multiplication with overflow. Both operands are guaranteed to be the same type, + /// and the result is bool. The wrapped value is written to the pointer given by the in + /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types + /// of the operation. + /// Uses the `pl_op` field with payload `Bin`. + mul_with_overflow, /// Allocates stack local memory. /// Uses the `ty` field. alloc, @@ -815,7 +821,9 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { return ptr_ty.elemType(); }, - .add_with_overflow => return Type.initTag(.bool), + .add_with_overflow, + .mul_with_overflow, + => return Type.initTag(.bool), } } diff --git a/src/Liveness.zig b/src/Liveness.zig index 160a2e97d3..6859f64660 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -382,7 +382,7 @@ fn analyzeInst( const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data; return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none }); }, - .memset, .memcpy, .add_with_overflow => { + .memset, .memcpy, .add_with_overflow, .mul_with_overflow => { const pl_op = inst_datas[inst].pl_op; const extra = a.air.extraData(Air.Bin, pl_op.payload).data; return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs }); diff --git a/src/Sema.zig b/src/Sema.zig index 03ee58dc06..38183d1052 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7343,8 +7343,8 @@ fn zirOverflowArithmetic( overflowed: enum { yes, no, undef }, wrapped: Air.Inst.Ref, } = result: { - const air_tag: Air.Inst.Tag = switch (zir_tag) { - .add_with_overflow => blk: { + switch (zir_tag) { + .add_with_overflow => { // If either of the arguments is zero, `false` is returned and the other is stored // to the result, even if it is undefined.. // Otherwise, if either of the argument is undefined, undefined is returned. @@ -7377,14 +7377,62 @@ fn zirOverflowArithmetic( } } } + }, + .mul_with_overflow => { + // If either of the arguments is zero, the result is zero and no overflow occured. + // If either of the arguments is one, the result is the other and no overflow occured. + // Otherwise, if either of the arguments is undefined, both results are undefined. + + if (maybe_lhs_val) |lhs_val| { + if (!lhs_val.isUndef()) { + if (lhs_val.compareWithZero(.eq)) { + break :result .{ .overflowed = .no, .wrapped = lhs }; + } else if (lhs_val.compare(.eq, Value.one, dest_ty)) { + break :result .{ .overflowed = .no, .wrapped = rhs }; + } + } + } - break :blk .add_with_overflow; + if (maybe_rhs_val) |rhs_val| { + if (!rhs_val.isUndef()) { + if (rhs_val.compareWithZero(.eq)) { + break :result .{ .overflowed = .no, .wrapped = rhs }; + } else if (rhs_val.compare(.eq, Value.one, dest_ty)) { + break :result .{ .overflowed = .no, .wrapped = lhs }; + } + } + } + + if (maybe_lhs_val) |lhs_val| { + if (maybe_rhs_val) |rhs_val| { + if (lhs_val.isUndef() or rhs_val.isUndef()) { + break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) }; + } + + const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target); + const inst = try sema.addConstant( + dest_ty, + result.wrapped_result, + ); + + if (result.overflowed) { + break :result .{ .overflowed = .yes, .wrapped = inst }; + } else { + break :result .{ .overflowed = .no, .wrapped = inst }; + } + } + } }, .sub_with_overflow, - .mul_with_overflow, .shl_with_overflow, => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}), else => unreachable, + } + + const air_tag: Air.Inst.Tag = switch (zir_tag) { + .add_with_overflow => .add_with_overflow, + .mul_with_overflow => .mul_with_overflow, + else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}), }; try sema.requireRuntimeBlock(block, src); diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 1c6d54485b..e34475f1ee 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -522,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -976,6 +977,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airDiv(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 0039d78434..779ce52036 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -520,6 +520,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -1006,6 +1007,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airDiv(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 51703681e9..c8f7173b1c 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -501,6 +501,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -921,6 +922,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airDiv(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 3b40293527..fe8d8b55f7 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -554,6 +554,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -1035,6 +1036,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airDiv(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 070aa0a238..f6a3105760 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1157,6 +1157,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .shl_sat => try airSatOp(f, inst, "shls_"), .add_with_overflow => try airAddWithOverflow(f, inst), + .mul_with_overflow => try airMulWithOverflow(f, inst), .min => try airMinMax(f, inst, "<"), .max => try airMinMax(f, inst, ">"), @@ -1873,6 +1874,12 @@ fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { return f.fail("TODO add with overflow", .{}); } +fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { + _ = f; + _ = inst; + return f.fail("TODO mul with overflow", .{}); +} + fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 0a2b12dd1e..209e3fb4de 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1714,7 +1714,8 @@ pub const FuncGen = struct { .max => try self.airMax(inst), .slice => try self.airSlice(inst), - .add_with_overflow => try self.airAddWithOverflow(inst), + .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"), + .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"), .bit_and, .bool_and => try self.airAnd(inst), .bit_or, .bool_or => try self.airOr(inst), @@ -3136,7 +3137,12 @@ pub const FuncGen = struct { } } - fn airAddWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + fn airOverflow( + self: *FuncGen, + inst: Air.Inst.Index, + signed_intrinsic: []const u8, + unsigned_intrinsic: []const u8, + ) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; @@ -3150,10 +3156,7 @@ pub const FuncGen = struct { const ptr_ty = self.air.typeOf(pl_op.operand); const lhs_ty = self.air.typeOf(extra.lhs); - const intrinsic_name: []const u8 = if (lhs_ty.isSignedInt()) - "llvm.sadd.with.overflow" - else - "llvm.uadd.with.overflow"; + const intrinsic_name = if (lhs_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic; const llvm_lhs_ty = try self.dg.llvmType(lhs_ty); diff --git a/src/print_air.zig b/src/print_air.zig index 17af7ebf62..2204d16bd6 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -229,7 +229,10 @@ const Writer = struct { .atomic_rmw => try w.writeAtomicRmw(s, inst), .memcpy => try w.writeMemcpy(s, inst), .memset => try w.writeMemset(s, inst), - .add_with_overflow => try w.writeAddWithOverflow(s, inst), + + .add_with_overflow, + .mul_with_overflow, + => try w.writeOverflow(s, inst), } } @@ -350,7 +353,7 @@ const Writer = struct { try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) }); } - fn writeAddWithOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const pl_op = w.air.instructions.items(.data)[inst].pl_op; const extra = w.air.extraData(Air.Bin, pl_op.payload).data; diff --git a/src/value.zig b/src/value.zig index 085883f7af..19546ed8b9 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2130,20 +2130,13 @@ pub const Value = extern union { return fromBigInt(arena, result_bigint.toConst()); } - /// Supports both floats and ints; handles undefined. - pub fn numberMulWrap( + pub fn intMulWithOverflow( lhs: Value, rhs: Value, ty: Type, arena: Allocator, target: Target, - ) !Value { - if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); - - if (ty.isAnyFloat()) { - return floatMul(lhs, rhs, ty, arena); - } - + ) !OverflowArithmeticResult { const info = ty.intInfo(target); var lhs_space: Value.BigIntSpace = undefined; @@ -2152,16 +2145,42 @@ pub const Value = extern union { const rhs_bigint = rhs.toBigInt(&rhs_space); const limbs = try arena.alloc( std.math.big.Limb, - std.math.big.int.calcTwosCompLimbCount(info.bits), + lhs_bigint.limbs.len + rhs_bigint.limbs.len, ); var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; var limbs_buffer = try arena.alloc( std.math.big.Limb, - std.math.big.int.calcMulWrapLimbsBufferLen(info.bits, lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1), + std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1), ); - defer arena.free(limbs_buffer); - result_bigint.mulWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits, limbs_buffer, arena); - return fromBigInt(arena, result_bigint.toConst()); + result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena); + + const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits); + if (overflowed) { + result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); + } + + return OverflowArithmeticResult{ + .overflowed = overflowed, + .wrapped_result = try fromBigInt(arena, result_bigint.toConst()), + }; + } + + /// Supports both floats and ints; handles undefined. + pub fn numberMulWrap( + lhs: Value, + rhs: Value, + ty: Type, + arena: Allocator, + target: Target, + ) !Value { + if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); + + if (ty.isAnyFloat()) { + return floatMul(lhs, rhs, ty, arena); + } + + const overflow_result = try intMulWithOverflow(lhs, rhs, ty, arena, target); + return overflow_result.wrapped_result; } /// Supports integers only; asserts neither operand is undefined. @@ -2194,7 +2213,6 @@ pub const Value = extern union { std.math.big.Limb, std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1), ); - defer arena.free(limbs_buffer); result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena); result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits); return fromBigInt(arena, result_bigint.toConst()); diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 2cd67854af..963fe3f0d5 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -451,6 +451,14 @@ test "@addWithOverflow" { try expect(result == 94); try expect(!@addWithOverflow(u8, 100, 150, &result)); try expect(result == 250); + + var a: u8 = 200; + var b: u8 = 99; + try expect(@addWithOverflow(u8, a, b, &result)); + try expect(result == 43); + b = 55; + try expect(!@addWithOverflow(u8, a, b, &result)); + try expect(result == 255); } test "small int addition" { @@ -471,3 +479,19 @@ test "small int addition" { try expect(result == 0); } + +test "@mulWithOverflow" { + var result: u8 = undefined; + try expect(@mulWithOverflow(u8, 86, 3, &result)); + try expect(result == 2); + try expect(!@mulWithOverflow(u8, 85, 3, &result)); + try expect(result == 255); + + var a: u8 = 123; + var b: u8 = 2; + try expect(!@mulWithOverflow(u8, a, b, &result)); + try expect(result == 246); + b = 4; + try expect(@mulWithOverflow(u8, a, b, &result)); + try expect(result == 236); +} diff --git a/test/behavior/math_stage1.zig b/test/behavior/math_stage1.zig index 63ff2cdec0..381f89634b 100644 --- a/test/behavior/math_stage1.zig +++ b/test/behavior/math_stage1.zig @@ -6,14 +6,6 @@ const maxInt = std.math.maxInt; const minInt = std.math.minInt; const mem = std.mem; -test "@mulWithOverflow" { - var result: u8 = undefined; - try expect(@mulWithOverflow(u8, 86, 3, &result)); - try expect(result == 2); - try expect(!@mulWithOverflow(u8, 85, 3, &result)); - try expect(result == 255); -} - test "@subWithOverflow" { var result: u8 = undefined; try expect(@subWithOverflow(u8, 1, 2, &result)); -- cgit v1.2.3 From 58d67a6718d5d0673389fa19f5bb20812b4bb22a Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 20 Dec 2021 03:58:19 +0100 Subject: stage2: make anyopaque sized While this is technically incorrect, proper handling of anyopaque, as well as regular opaque, is probably best left until pointers to zero-sized types having no bits is abolished. --- src/codegen/llvm.zig | 28 ++++++++++++++++------------ src/type.zig | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 209e3fb4de..07fe138786 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -761,21 +761,25 @@ pub const DeclGen = struct { dg.context.intType(8); return llvm_elem_ty.pointerType(llvm_addrspace); }, - .Opaque => { - const gop = try dg.object.type_map.getOrPut(gpa, t); - if (gop.found_existing) return gop.value_ptr.*; + .Opaque => switch (t.tag()) { + .@"opaque" => { + const gop = try dg.object.type_map.getOrPut(gpa, t); + if (gop.found_existing) return gop.value_ptr.*; - // The Type memory is ephemeral; since we want to store a longer-lived - // reference, we need to copy it here. - gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); + // The Type memory is ephemeral; since we want to store a longer-lived + // reference, we need to copy it here. + gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); - const opaque_obj = t.castTag(.@"opaque").?.data; - const name = try opaque_obj.getFullyQualifiedName(gpa); - defer gpa.free(name); + const opaque_obj = t.castTag(.@"opaque").?.data; + const name = try opaque_obj.getFullyQualifiedName(gpa); + defer gpa.free(name); - const llvm_struct_ty = dg.context.structCreateNamed(name); - gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls - return llvm_struct_ty; + const llvm_struct_ty = dg.context.structCreateNamed(name); + gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls + return llvm_struct_ty; + }, + .anyopaque => return dg.context.intType(8), + else => unreachable, }, .Array => { const elem_type = try dg.llvmType(t.childType()); diff --git a/src/type.zig b/src/type.zig index a81bd3ed32..fb16a4d0f1 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1575,6 +1575,7 @@ pub const Type = extern union { .extern_options, .@"anyframe", .anyframe_T, + .anyopaque, .@"opaque", .single_const_pointer, .single_mut_pointer, @@ -1654,7 +1655,6 @@ pub const Type = extern union { return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits(); }, - .anyopaque, .void, .type, .comptime_int, -- cgit v1.2.3 From 964dbeb82623515b8392c8c7cb9317246812174e Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 20 Dec 2021 21:53:40 +0100 Subject: stage2: @subWithOverflow --- src/Air.zig | 7 +++++++ src/Liveness.zig | 7 ++++++- src/Sema.zig | 44 ++++++++++++++++++++++--------------------- src/arch/aarch64/CodeGen.zig | 6 ++++++ src/arch/arm/CodeGen.zig | 6 ++++++ src/arch/riscv64/CodeGen.zig | 6 ++++++ src/arch/x86_64/CodeGen.zig | 6 ++++++ src/codegen/c.zig | 7 +++++++ src/codegen/llvm.zig | 1 + src/print_air.zig | 1 + test/behavior/math.zig | 16 ++++++++++++++++ test/behavior/math_stage1.zig | 8 -------- 12 files changed, 85 insertions(+), 30 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Air.zig b/src/Air.zig index 5d54be7392..912e70daed 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -141,6 +141,12 @@ pub const Inst = struct { /// of the operation. /// Uses the `pl_op` field with payload `Bin`. add_with_overflow, + /// Integer subtraction with overflow. Both operands are guaranteed to be the same type, + /// and the result is bool. The wrapped value is written to the pointer given by the in + /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types + /// of the operation. + /// Uses the `pl_op` field with payload `Bin`. + sub_with_overflow, /// Integer multiplication with overflow. Both operands are guaranteed to be the same type, /// and the result is bool. The wrapped value is written to the pointer given by the in /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types @@ -822,6 +828,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { }, .add_with_overflow, + .sub_with_overflow, .mul_with_overflow, => return Type.initTag(.bool), } diff --git a/src/Liveness.zig b/src/Liveness.zig index 6859f64660..ad0ce7ffb9 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -382,7 +382,12 @@ fn analyzeInst( const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data; return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none }); }, - .memset, .memcpy, .add_with_overflow, .mul_with_overflow => { + .memset, + .memcpy, + .add_with_overflow, + .sub_with_overflow, + .mul_with_overflow, + => { const pl_op = inst_datas[inst].pl_op; const extra = a.air.extraData(Air.Bin, pl_op.payload).data; return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs }); diff --git a/src/Sema.zig b/src/Sema.zig index 38183d1052..2eb661503e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7365,16 +7365,27 @@ fn zirOverflowArithmetic( } const result = try lhs_val.intAddWithOverflow(rhs_val, dest_ty, sema.arena, target); - const inst = try sema.addConstant( - dest_ty, - result.wrapped_result, - ); - - if (result.overflowed) { - break :result .{ .overflowed = .yes, .wrapped = inst }; - } else { - break :result .{ .overflowed = .no, .wrapped = inst }; + const inst = try sema.addConstant(dest_ty, result.wrapped_result); + break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst }; + } + } + }, + .sub_with_overflow => { + // If the rhs is zero, then the result is lhs and no overflow occured. + // Otherwise, if either result is undefined, both results are undefined. + if (maybe_rhs_val) |rhs_val| { + if (rhs_val.isUndef()) { + break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) }; + } else if (rhs_val.compareWithZero(.eq)) { + break :result .{ .overflowed = .no, .wrapped = lhs }; + } else if (maybe_lhs_val) |lhs_val| { + if (lhs_val.isUndef()) { + break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) }; } + + const result = try lhs_val.intSubWithOverflow(rhs_val, dest_ty, sema.arena, target); + const inst = try sema.addConstant(dest_ty, result.wrapped_result); + break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst }; } } }, @@ -7382,7 +7393,6 @@ fn zirOverflowArithmetic( // If either of the arguments is zero, the result is zero and no overflow occured. // If either of the arguments is one, the result is the other and no overflow occured. // Otherwise, if either of the arguments is undefined, both results are undefined. - if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef()) { if (lhs_val.compareWithZero(.eq)) { @@ -7410,20 +7420,11 @@ fn zirOverflowArithmetic( } const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target); - const inst = try sema.addConstant( - dest_ty, - result.wrapped_result, - ); - - if (result.overflowed) { - break :result .{ .overflowed = .yes, .wrapped = inst }; - } else { - break :result .{ .overflowed = .no, .wrapped = inst }; - } + const inst = try sema.addConstant(dest_ty, result.wrapped_result); + break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst }; } } }, - .sub_with_overflow, .shl_with_overflow, => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}), else => unreachable, @@ -7432,6 +7433,7 @@ fn zirOverflowArithmetic( const air_tag: Air.Inst.Tag = switch (zir_tag) { .add_with_overflow => .add_with_overflow, .mul_with_overflow => .mul_with_overflow, + .sub_with_overflow => .sub_with_overflow, else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}), }; diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index e34475f1ee..b381116a51 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -522,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -977,6 +978,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 779ce52036..f887810d9a 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -520,6 +520,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -1007,6 +1008,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index c8f7173b1c..56904206ab 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -501,6 +501,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -922,6 +923,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index fe8d8b55f7..be26372031 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -554,6 +554,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice => try self.airSlice(inst), .add_with_overflow => try self.airAddWithOverflow(inst), + .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -1036,6 +1037,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); } +fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); +} + fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index f6a3105760..68b700db17 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1157,6 +1157,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .shl_sat => try airSatOp(f, inst, "shls_"), .add_with_overflow => try airAddWithOverflow(f, inst), + .sub_with_overflow => try airSubWithOverflow(f, inst), .mul_with_overflow => try airMulWithOverflow(f, inst), .min => try airMinMax(f, inst, "<"), @@ -1874,6 +1875,12 @@ fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { return f.fail("TODO add with overflow", .{}); } +fn airSubWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { + _ = f; + _ = inst; + return f.fail("TODO sub with overflow", .{}); +} + fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { _ = f; _ = inst; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 07fe138786..4089a39cb3 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1719,6 +1719,7 @@ pub const FuncGen = struct { .slice => try self.airSlice(inst), .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"), + .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"), .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"), .bit_and, .bool_and => try self.airAnd(inst), diff --git a/src/print_air.zig b/src/print_air.zig index 2204d16bd6..d6bfaac4bc 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -231,6 +231,7 @@ const Writer = struct { .memset => try w.writeMemset(s, inst), .add_with_overflow, + .sub_with_overflow, .mul_with_overflow, => try w.writeOverflow(s, inst), } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 963fe3f0d5..50a7267c93 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -495,3 +495,19 @@ test "@mulWithOverflow" { try expect(@mulWithOverflow(u8, a, b, &result)); try expect(result == 236); } + +test "@subWithOverflow" { + var result: u8 = undefined; + try expect(@subWithOverflow(u8, 1, 2, &result)); + try expect(result == 255); + try expect(!@subWithOverflow(u8, 1, 1, &result)); + try expect(result == 0); + + var a: u8 = 1; + var b: u8 = 2; + try expect(@subWithOverflow(u8, a, b, &result)); + try expect(result == 255); + b = 1; + try expect(!@subWithOverflow(u8, a, b, &result)); + try expect(result == 0); +} diff --git a/test/behavior/math_stage1.zig b/test/behavior/math_stage1.zig index 381f89634b..139593b9f5 100644 --- a/test/behavior/math_stage1.zig +++ b/test/behavior/math_stage1.zig @@ -6,14 +6,6 @@ const maxInt = std.math.maxInt; const minInt = std.math.minInt; const mem = std.mem; -test "@subWithOverflow" { - var result: u8 = undefined; - try expect(@subWithOverflow(u8, 1, 2, &result)); - try expect(result == 255); - try expect(!@subWithOverflow(u8, 1, 1, &result)); - try expect(result == 0); -} - test "@shlWithOverflow" { var result: u16 = undefined; try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); -- cgit v1.2.3 From e106e18d96595bdc4bc037e0b36900992a576160 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 21 Dec 2021 01:38:46 +0100 Subject: stage2: @shlWithOverflow --- src/Air.zig | 7 +++++++ src/Liveness.zig | 3 ++- src/Sema.zig | 47 +++++++++++++++++++++++++++++++++++-------- src/arch/aarch64/CodeGen.zig | 12 ++++++++--- src/arch/arm/CodeGen.zig | 12 ++++++++--- src/arch/riscv64/CodeGen.zig | 12 ++++++++--- src/arch/x86_64/CodeGen.zig | 12 ++++++++--- src/codegen/c.zig | 7 +++++++ src/codegen/llvm.zig | 36 +++++++++++++++++++++++++++++++++ src/print_air.zig | 1 + src/value.zig | 31 ++++++++++++++++++++++++++++ test/behavior/eval.zig | 16 +++++++++++++++ test/behavior/eval_stage1.zig | 16 --------------- test/behavior/math.zig | 28 ++++++++++++++++++++++++++ test/behavior/math_stage1.zig | 20 ------------------ 15 files changed, 203 insertions(+), 57 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Air.zig b/src/Air.zig index 912e70daed..0d660ff6ae 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -153,6 +153,12 @@ pub const Inst = struct { /// of the operation. /// Uses the `pl_op` field with payload `Bin`. mul_with_overflow, + /// Integer left-shift with overflow. Both operands are guaranteed to be the same type, + /// and the result is bool. The wrapped value is written to the pointer given by the in + /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types + /// of the operation. + /// Uses the `pl_op` field with payload `Bin`. + shl_with_overflow, /// Allocates stack local memory. /// Uses the `ty` field. alloc, @@ -830,6 +836,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .add_with_overflow, .sub_with_overflow, .mul_with_overflow, + .shl_with_overflow, => return Type.initTag(.bool), } } diff --git a/src/Liveness.zig b/src/Liveness.zig index ad0ce7ffb9..a9f7fffca4 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -387,7 +387,8 @@ fn analyzeInst( .add_with_overflow, .sub_with_overflow, .mul_with_overflow, - => { + .shl_with_overflow, + => { const pl_op = inst_datas[inst].pl_op; const extra = a.air.extraData(Air.Bin, pl_op.payload).data; return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs }); diff --git a/src/Sema.zig b/src/Sema.zig index 2eb661503e..2ac4d327b1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7425,8 +7425,32 @@ fn zirOverflowArithmetic( } } }, - .shl_with_overflow, - => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}), + .shl_with_overflow => { + // If lhs is zero, the result is zero and no overflow occurred. + // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. + // Oterhwise if either of the arguments is undefined, both results are undefined. + if (maybe_lhs_val) |lhs_val| { + if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) { + break :result .{ .overflowed = .no, .wrapped = lhs }; + } + } + if (maybe_rhs_val) |rhs_val| { + if (!rhs_val.isUndef() and rhs_val.compareWithZero(.eq)) { + break :result .{ .overflowed = .no, .wrapped = lhs }; + } + } + if (maybe_lhs_val) |lhs_val| { + if (maybe_rhs_val) |rhs_val| { + if (lhs_val.isUndef() or rhs_val.isUndef()) { + break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) }; + } + + const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, target); + const inst = try sema.addConstant(dest_ty, result.wrapped_result); + break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst }; + } + } + }, else => unreachable, } @@ -7434,7 +7458,8 @@ fn zirOverflowArithmetic( .add_with_overflow => .add_with_overflow, .mul_with_overflow => .mul_with_overflow, .sub_with_overflow => .sub_with_overflow, - else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}), + .shl_with_overflow => .shl_with_overflow, + else => unreachable, }; try sema.requireRuntimeBlock(block, src); @@ -9041,11 +9066,17 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi switch (operand.zigTypeTag()) { .ComptimeInt => return Air.Inst.Ref.comptime_int_type, .Int => { - var count: u16 = 0; - var s = operand.bitSize(sema.mod.getTarget()) - 1; - while (s != 0) : (s >>= 1) { - count += 1; - } + const bits = operand.bitSize(sema.mod.getTarget()); + const count = if (bits == 0) + 0 + else blk: { + var count: u16 = 0; + var s = bits - 1; + while (s != 0) : (s >>= 1) { + count += 1; + } + break :blk count; + }; const res = try Module.makeIntType(sema.arena, .unsigned, count); return sema.addType(res); }, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index b381116a51..0142e6abf8 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -524,6 +524,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .add_with_overflow => try self.airAddWithOverflow(inst), .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), + .shl_with_overflow => try self.airShlWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -975,17 +976,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); } fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); } fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); +} + +fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); } fn airDiv(self: *Self, inst: Air.Inst.Index) !void { diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index f887810d9a..9e43808d1f 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -522,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .add_with_overflow => try self.airAddWithOverflow(inst), .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), + .shl_with_overflow => try self.airShlWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -1005,17 +1006,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); } fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); } fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); +} + +fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); } fn airDiv(self: *Self, inst: Air.Inst.Index) !void { diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 56904206ab..3930e7364e 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -503,6 +503,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .add_with_overflow => try self.airAddWithOverflow(inst), .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), + .shl_with_overflow => try self.airShlWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -920,17 +921,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); } fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); } fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); +} + +fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); } fn airDiv(self: *Self, inst: Air.Inst.Index) !void { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index be26372031..9629280583 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -556,6 +556,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .add_with_overflow => try self.airAddWithOverflow(inst), .sub_with_overflow => try self.airSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), + .shl_with_overflow => try self.airShlWithOverflow(inst), .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), @@ -1034,17 +1035,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); } fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); } fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { _ = inst; - return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); +} + +fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); } fn airDiv(self: *Self, inst: Air.Inst.Index) !void { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 68b700db17..12ce813a0f 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1159,6 +1159,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .add_with_overflow => try airAddWithOverflow(f, inst), .sub_with_overflow => try airSubWithOverflow(f, inst), .mul_with_overflow => try airMulWithOverflow(f, inst), + .shl_with_overflow => try airShlWithOverflow(f, inst), .min => try airMinMax(f, inst, "<"), .max => try airMinMax(f, inst, ">"), @@ -1887,6 +1888,12 @@ fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { return f.fail("TODO mul with overflow", .{}); } +fn airShlWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { + _ = f; + _ = inst; + return f.fail("TODO shl with overflow", .{}); +} + fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 4089a39cb3..78848bee28 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1721,6 +1721,7 @@ pub const FuncGen = struct { .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"), .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"), .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"), + .shl_with_overflow => try self.airShlWithOverflow(inst), .bit_and, .bool_and => try self.airAnd(inst), .bit_or, .bool_or => try self.airOr(inst), @@ -3176,6 +3177,41 @@ pub const FuncGen = struct { return overflow_bit; } + fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + if (self.liveness.isUnused(inst)) + return null; + + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const extra = self.air.extraData(Air.Bin, pl_op.payload).data; + + const ptr = try self.resolveInst(pl_op.operand); + const lhs = try self.resolveInst(extra.lhs); + const rhs = try self.resolveInst(extra.rhs); + + const ptr_ty = self.air.typeOf(pl_op.operand); + const lhs_ty = self.air.typeOf(extra.lhs); + const rhs_ty = self.air.typeOf(extra.rhs); + + const tg = self.dg.module.getTarget(); + + const casted_rhs = if (rhs_ty.bitSize(tg) < lhs_ty.bitSize(tg)) + self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "") + else + rhs; + + const result = self.builder.buildShl(lhs, casted_rhs, ""); + const reconstructed = if (lhs_ty.isSignedInt()) + self.builder.buildAShr(result, casted_rhs, "") + else + self.builder.buildLShr(result, casted_rhs, ""); + + const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); + + self.store(ptr, ptr_ty, result, .NotAtomic); + + return overflow_bit; + } + fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; diff --git a/src/print_air.zig b/src/print_air.zig index d6bfaac4bc..b3a1be28f4 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -233,6 +233,7 @@ const Writer = struct { .add_with_overflow, .sub_with_overflow, .mul_with_overflow, + .shl_with_overflow, => try w.writeOverflow(s, inst), } } diff --git a/src/value.zig b/src/value.zig index 19546ed8b9..c105e3e742 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2548,6 +2548,37 @@ pub const Value = extern union { return fromBigInt(allocator, result_bigint.toConst()); } + pub fn shlWithOverflow( + lhs: Value, + rhs: Value, + ty: Type, + allocator: Allocator, + target: Target, + ) !OverflowArithmeticResult { + const info = ty.intInfo(target); + var lhs_space: Value.BigIntSpace = undefined; + const lhs_bigint = lhs.toBigInt(&lhs_space); + const shift = @intCast(usize, rhs.toUnsignedInt()); + const limbs = try allocator.alloc( + std.math.big.Limb, + lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, + ); + var result_bigint = BigIntMutable{ + .limbs = limbs, + .positive = undefined, + .len = undefined, + }; + result_bigint.shiftLeft(lhs_bigint, shift); + const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits); + if (overflowed) { + result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); + } + return OverflowArithmeticResult{ + .overflowed = overflowed, + .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()), + }; + } + pub fn shlSat( lhs: Value, rhs: Value, diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 84af3ecfbb..01d62f353f 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -451,3 +451,19 @@ test "comptime bitwise operators" { try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff); } } + +test "comptime shlWithOverflow" { + const ct_shifted: u64 = comptime amt: { + var amt = @as(u64, 0); + _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); + break :amt amt; + }; + + const rt_shifted: u64 = amt: { + var amt = @as(u64, 0); + _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); + break :amt amt; + }; + + try expect(ct_shifted == rt_shifted); +} diff --git a/test/behavior/eval_stage1.zig b/test/behavior/eval_stage1.zig index 348c685a26..8f7e7dbe0d 100644 --- a/test/behavior/eval_stage1.zig +++ b/test/behavior/eval_stage1.zig @@ -162,22 +162,6 @@ test "const ptr to comptime mutable data is not memoized" { } } -test "comptime shlWithOverflow" { - const ct_shifted: u64 = comptime amt: { - var amt = @as(u64, 0); - _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); - break :amt amt; - }; - - const rt_shifted: u64 = amt: { - var amt = @as(u64, 0); - _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); - break :amt amt; - }; - - try expect(ct_shifted == rt_shifted); -} - test "runtime 128 bit integer division" { var a: u128 = 152313999999999991610955792383; var b: u128 = 10000000000000000000; diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 50a7267c93..b3821f7732 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -511,3 +511,31 @@ test "@subWithOverflow" { try expect(!@subWithOverflow(u8, a, b, &result)); try expect(result == 0); } + +test "@shlWithOverflow" { + var result: u16 = undefined; + try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); + try expect(result == 0b0111111111111000); + try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); + try expect(result == 0b1011111111111100); + + var a: u16 = 0b0000_0000_0000_0011; + var b: u4 = 15; + try expect(@shlWithOverflow(u16, a, b, &result)); + try expect(result == 0b1000_0000_0000_0000); + b = 14; + try expect(!@shlWithOverflow(u16, a, b, &result)); + try expect(result == 0b1100_0000_0000_0000); +} + +test "overflow arithmetic with u0 values" { + var result: u0 = undefined; + try expect(!@addWithOverflow(u0, 0, 0, &result)); + try expect(result == 0); + try expect(!@subWithOverflow(u0, 0, 0, &result)); + try expect(result == 0); + try expect(!@mulWithOverflow(u0, 0, 0, &result)); + try expect(result == 0); + try expect(!@shlWithOverflow(u0, 0, 0, &result)); + try expect(result == 0); +} diff --git a/test/behavior/math_stage1.zig b/test/behavior/math_stage1.zig index 139593b9f5..2633f23aac 100644 --- a/test/behavior/math_stage1.zig +++ b/test/behavior/math_stage1.zig @@ -6,26 +6,6 @@ const maxInt = std.math.maxInt; const minInt = std.math.minInt; const mem = std.mem; -test "@shlWithOverflow" { - var result: u16 = undefined; - try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); - try expect(result == 0b0111111111111000); - try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); - try expect(result == 0b1011111111111100); -} - -test "overflow arithmetic with u0 values" { - var result: u0 = undefined; - try expect(!@addWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); - try expect(!@subWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); - try expect(!@mulWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); - try expect(!@shlWithOverflow(u0, 0, 0, &result)); - try expect(result == 0); -} - test "@clz vectors" { try testClzVectors(); comptime try testClzVectors(); -- cgit v1.2.3