mirror of
https://github.com/ziglang/zig.git
synced 2025-12-30 18:13:19 +00:00
AstGen: implement overflow arithmetic builtins
This commit is contained in:
parent
8cf0ef2779
commit
5a3045b5de
@ -1407,6 +1407,11 @@ fn blockExprStmts(
|
||||
.fence,
|
||||
.ret_addr,
|
||||
.builtin_src,
|
||||
.add_with_overflow,
|
||||
.sub_with_overflow,
|
||||
.mul_with_overflow,
|
||||
.shl_with_overflow,
|
||||
.log2_int_type,
|
||||
=> break :b false,
|
||||
|
||||
// ZIR instructions that are always either `noreturn` or `void`.
|
||||
@ -4910,7 +4915,32 @@ fn builtinCall(
|
||||
.return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node),
|
||||
.src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node),
|
||||
|
||||
.add_with_overflow,
|
||||
.add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow),
|
||||
.sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow),
|
||||
.mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow),
|
||||
.shl_with_overflow => {
|
||||
const int_type = try typeExpr(gz, scope, params[0]);
|
||||
const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]);
|
||||
const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
|
||||
.ptr_type_simple = .{
|
||||
.is_allowzero = false,
|
||||
.is_mutable = true,
|
||||
.is_volatile = false,
|
||||
.size = .One,
|
||||
.elem_type = int_type,
|
||||
},
|
||||
} });
|
||||
const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]);
|
||||
const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, params[2]);
|
||||
const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]);
|
||||
const result = try gz.addPlNode(.shl_with_overflow, node, Zir.Inst.OverflowArithmetic{
|
||||
.lhs = lhs,
|
||||
.rhs = rhs,
|
||||
.ptr = ptr,
|
||||
});
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
},
|
||||
|
||||
.align_cast,
|
||||
.align_of,
|
||||
.atomic_load,
|
||||
@ -4948,7 +4978,6 @@ fn builtinCall(
|
||||
.wasm_memory_size,
|
||||
.wasm_memory_grow,
|
||||
.mod,
|
||||
.mul_with_overflow,
|
||||
.panic,
|
||||
.pop_count,
|
||||
.ptr_cast,
|
||||
@ -4958,7 +4987,6 @@ fn builtinCall(
|
||||
.set_float_mode,
|
||||
.set_runtime_safety,
|
||||
.shl_exact,
|
||||
.shl_with_overflow,
|
||||
.shr_exact,
|
||||
.shuffle,
|
||||
.splat,
|
||||
@ -4976,7 +5004,6 @@ fn builtinCall(
|
||||
.ceil,
|
||||
.trunc,
|
||||
.round,
|
||||
.sub_with_overflow,
|
||||
.tag_name,
|
||||
.truncate,
|
||||
.Type,
|
||||
@ -4993,6 +5020,35 @@ fn builtinCall(
|
||||
}
|
||||
}
|
||||
|
||||
fn overflowArithmetic(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
node: ast.Node.Index,
|
||||
params: []const ast.Node.Index,
|
||||
tag: Zir.Inst.Tag,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const int_type = try typeExpr(gz, scope, params[0]);
|
||||
const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
|
||||
.ptr_type_simple = .{
|
||||
.is_allowzero = false,
|
||||
.is_mutable = true,
|
||||
.is_volatile = false,
|
||||
.size = .One,
|
||||
.elem_type = int_type,
|
||||
},
|
||||
} });
|
||||
const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]);
|
||||
const rhs = try expr(gz, scope, .{ .ty = int_type }, params[2]);
|
||||
const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]);
|
||||
const result = try gz.addPlNode(tag, node, Zir.Inst.OverflowArithmetic{
|
||||
.lhs = lhs,
|
||||
.rhs = rhs,
|
||||
.ptr = ptr,
|
||||
});
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
}
|
||||
|
||||
fn callExpr(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
|
||||
39
src/Sema.zig
39
src/Sema.zig
@ -133,8 +133,6 @@ pub fn analyzeBody(
|
||||
map[inst] = switch (tags[inst]) {
|
||||
.elided => continue,
|
||||
|
||||
.add => try sema.zirArithmetic(block, inst),
|
||||
.addwrap => try sema.zirArithmetic(block, inst),
|
||||
.alloc => try sema.zirAlloc(block, inst),
|
||||
.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
|
||||
.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
|
||||
@ -173,7 +171,6 @@ pub fn analyzeBody(
|
||||
.decl_ref => try sema.zirDeclRef(block, inst),
|
||||
.decl_val => try sema.zirDeclVal(block, inst),
|
||||
.load => try sema.zirLoad(block, inst),
|
||||
.div => try sema.zirArithmetic(block, inst),
|
||||
.elem_ptr => try sema.zirElemPtr(block, inst),
|
||||
.elem_ptr_node => try sema.zirElemPtrNode(block, inst),
|
||||
.elem_val => try sema.zirElemVal(block, inst),
|
||||
@ -217,9 +214,6 @@ pub fn analyzeBody(
|
||||
.is_null_ptr => try sema.zirIsNullPtr(block, inst, false),
|
||||
.loop => try sema.zirLoop(block, inst),
|
||||
.merge_error_sets => try sema.zirMergeErrorSets(block, inst),
|
||||
.mod_rem => try sema.zirArithmetic(block, inst),
|
||||
.mul => try sema.zirArithmetic(block, inst),
|
||||
.mulwrap => try sema.zirArithmetic(block, inst),
|
||||
.negate => try sema.zirNegate(block, inst, .sub),
|
||||
.negate_wrap => try sema.zirNegate(block, inst, .subwrap),
|
||||
.optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
|
||||
@ -241,8 +235,6 @@ pub fn analyzeBody(
|
||||
.slice_sentinel => try sema.zirSliceSentinel(block, inst),
|
||||
.slice_start => try sema.zirSliceStart(block, inst),
|
||||
.str => try sema.zirStr(block, inst),
|
||||
.sub => try sema.zirArithmetic(block, inst),
|
||||
.subwrap => try sema.zirArithmetic(block, inst),
|
||||
.switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
|
||||
.switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
|
||||
.switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
|
||||
@ -271,6 +263,7 @@ pub fn analyzeBody(
|
||||
.typeof => try sema.zirTypeof(block, inst),
|
||||
.typeof_elem => try sema.zirTypeofElem(block, inst),
|
||||
.typeof_peer => try sema.zirTypeofPeer(block, inst),
|
||||
.log2_int_type => try sema.zirLog2IntType(block, inst),
|
||||
.xor => try sema.zirBitwise(block, inst, .xor),
|
||||
.struct_init_empty => try sema.zirStructInitEmpty(block, inst),
|
||||
.struct_init => try sema.zirStructInit(block, inst),
|
||||
@ -284,6 +277,20 @@ pub fn analyzeBody(
|
||||
.union_decl => try sema.zirUnionDecl(block, inst),
|
||||
.opaque_decl => try sema.zirOpaqueDecl(block, inst),
|
||||
|
||||
.add => try sema.zirArithmetic(block, inst),
|
||||
.addwrap => try sema.zirArithmetic(block, inst),
|
||||
.div => try sema.zirArithmetic(block, inst),
|
||||
.mod_rem => try sema.zirArithmetic(block, inst),
|
||||
.mul => try sema.zirArithmetic(block, inst),
|
||||
.mulwrap => try sema.zirArithmetic(block, inst),
|
||||
.sub => try sema.zirArithmetic(block, inst),
|
||||
.subwrap => try sema.zirArithmetic(block, inst),
|
||||
|
||||
.add_with_overflow => try sema.zirOverflowArithmetic(block, inst),
|
||||
.sub_with_overflow => try sema.zirOverflowArithmetic(block, inst),
|
||||
.mul_with_overflow => try sema.zirOverflowArithmetic(block, inst),
|
||||
.shl_with_overflow => try sema.zirOverflowArithmetic(block, inst),
|
||||
|
||||
// Instructions that we know to *always* be noreturn based solely on their tag.
|
||||
// These functions match the return type of analyzeBody so that we can
|
||||
// tail call them here.
|
||||
@ -4048,6 +4055,16 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
|
||||
return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
|
||||
}
|
||||
|
||||
fn zirOverflowArithmetic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
|
||||
|
||||
return sema.mod.fail(&block.base, src, "TODO implement Sema.zirOverflowArithmetic", .{});
|
||||
}
|
||||
|
||||
fn analyzeArithmetic(
|
||||
sema: *Sema,
|
||||
block: *Scope.Block,
|
||||
@ -4402,6 +4419,12 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
|
||||
return sema.mod.constType(sema.arena, src, elem_ty);
|
||||
}
|
||||
|
||||
fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src = inst_data.src();
|
||||
return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{});
|
||||
}
|
||||
|
||||
fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
41
src/Zir.zig
41
src/Zir.zig
@ -573,6 +573,9 @@ pub const Inst = struct {
|
||||
/// of one or more params.
|
||||
/// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
|
||||
typeof_peer,
|
||||
/// Given an integer type, returns the integer type for the RHS of a shift operation.
|
||||
/// Uses the `un_node` field.
|
||||
log2_int_type,
|
||||
/// Asserts control-flow will not reach this instruction (`unreachable`).
|
||||
/// Uses the `unreachable` union field.
|
||||
@"unreachable",
|
||||
@ -729,6 +732,14 @@ pub const Inst = struct {
|
||||
ret_addr,
|
||||
/// Implements the `@src` builtin. Uses `un_node`.
|
||||
builtin_src,
|
||||
/// Implements the `@addWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
|
||||
add_with_overflow,
|
||||
/// Implements the `@subWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
|
||||
sub_with_overflow,
|
||||
/// Implements the `@mulWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
|
||||
mul_with_overflow,
|
||||
/// Implements the `@shlWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
|
||||
shl_with_overflow,
|
||||
|
||||
/// Returns whether the instruction is one of the control flow "noreturn" types.
|
||||
/// Function calls do not count.
|
||||
@ -865,6 +876,7 @@ pub const Inst = struct {
|
||||
.slice_sentinel,
|
||||
.import,
|
||||
.typeof_peer,
|
||||
.log2_int_type,
|
||||
.resolve_inferred_alloc,
|
||||
.set_eval_branch_quota,
|
||||
.compile_log,
|
||||
@ -900,6 +912,10 @@ pub const Inst = struct {
|
||||
.fence,
|
||||
.ret_addr,
|
||||
.builtin_src,
|
||||
.add_with_overflow,
|
||||
.sub_with_overflow,
|
||||
.mul_with_overflow,
|
||||
.shl_with_overflow,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@ -1657,6 +1673,12 @@ pub const Inst = struct {
|
||||
name_start: u32,
|
||||
};
|
||||
|
||||
pub const OverflowArithmetic = struct {
|
||||
lhs: Ref,
|
||||
rhs: Ref,
|
||||
ptr: Ref,
|
||||
};
|
||||
|
||||
/// Trailing: `CompileErrors.Item` for each `items_len`.
|
||||
pub const CompileErrors = struct {
|
||||
items_len: u32,
|
||||
@ -1762,6 +1784,7 @@ const Writer = struct {
|
||||
.type_info,
|
||||
.size_of,
|
||||
.bit_size_of,
|
||||
.log2_int_type,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.ref,
|
||||
@ -1804,6 +1827,12 @@ const Writer = struct {
|
||||
.field_type,
|
||||
=> try self.writePlNode(stream, inst),
|
||||
|
||||
.add_with_overflow,
|
||||
.sub_with_overflow,
|
||||
.mul_with_overflow,
|
||||
.shl_with_overflow,
|
||||
=> try self.writePlNodeOverflowArithmetic(stream, inst),
|
||||
|
||||
.add,
|
||||
.addwrap,
|
||||
.array_cat,
|
||||
@ -2061,6 +2090,18 @@ const Writer = struct {
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writePlNodeOverflowArithmetic(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = self.code.extraData(Inst.OverflowArithmetic, inst_data.payload_index).data;
|
||||
try self.writeInstRef(stream, extra.lhs);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.rhs);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.ptr);
|
||||
try stream.writeAll(") ");
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = self.code.extraData(Inst.Call, inst_data.payload_index);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user