zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 411d225ad97accaeda6882acbb56d1115d03cd54 (tree)
parent 4f3930dbe27b40ef42bb327482d7f0283f8b331b
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Fri, 20 Feb 2026 21:22:15 +0000

sema: add add_sat, sub_sat, int_from_bool; more unit tests

Implement three new ZIR instruction handlers:
- ZIR_INST_ADD_SAT / ZIR_INST_SUB_SAT: saturating arithmetic, same
  pattern as existing wrapping ops (zirArithmetic + bin_op AIR)
- ZIR_INST_INT_FROM_BOOL: @intFromBool, emits bitcast to u1
  (ported from src/Sema.zig zirIntFromBool)

Add semaTypeOf entries for AIR_INST_ADD_SAT / AIR_INST_SUB_SAT.

Add 10 new sema_test.zig unit tests: intFromBool, add_sat, sub_sat,
bit_or, bit_and, f16 add, f64 mul, intcast with computed dest type,
and multiple exported functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mstage0/sema.c | 30++++++++++++++++++++++++++++++
Mstage0/sema_test.zig | 47+++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -524,6 +524,8 @@ static TypeIndex semaTypeOf(Sema* sema, AirInstRef ref) { case AIR_INST_SUB_WRAP: case AIR_INST_MUL: case AIR_INST_MUL_WRAP: + case AIR_INST_ADD_SAT: + case AIR_INST_SUB_SAT: case AIR_INST_BIT_AND: case AIR_INST_BIT_OR: case AIR_INST_XOR: @@ -720,6 +722,19 @@ static AirInstRef zirBoolNot(Sema* sema, SemaBlock* block, uint32_t inst) { return blockAddInst(block, AIR_INST_NOT, data); } +// zirIntFromBool: handle int_from_bool ZIR instruction (@intFromBool). +// Ported from src/Sema.zig zirIntFromBool. +// Emits AIR_INST_BITCAST to u1. +static AirInstRef zirIntFromBool(Sema* sema, SemaBlock* block, uint32_t inst) { + ZirInstRef operand_ref = sema->code.inst_datas[inst].un_node.operand; + AirInstRef operand = resolveInst(sema, operand_ref); + AirInstData data; + memset(&data, 0, sizeof(data)); + data.ty_op.ty_ref = AIR_REF_FROM_IP(IP_INDEX_U1_TYPE); + data.ty_op.operand = operand; + return blockAddInst(block, AIR_INST_BITCAST, data); +} + // smallestUnsignedBits: compute the number of bits needed to represent max. // Ported from src/Type.zig smallestUnsignedBits. static uint16_t smallestUnsignedBits(uint16_t max) { @@ -3189,6 +3204,16 @@ static bool analyzeBodyInner( zirArithmetic(sema, block, inst, AIR_INST_MUL_WRAP)); i++; continue; + case ZIR_INST_ADD_SAT: + instMapPut(&sema->inst_map, inst, + zirArithmetic(sema, block, inst, AIR_INST_ADD_SAT)); + i++; + continue; + case ZIR_INST_SUB_SAT: + instMapPut(&sema->inst_map, inst, + zirArithmetic(sema, block, inst, AIR_INST_SUB_SAT)); + i++; + continue; // Comparisons: same binary pattern as arithmetic. case ZIR_INST_CMP_LT: @@ -3341,6 +3366,11 @@ static bool analyzeBodyInner( zirBoolNot(sema, block, inst)); i++; continue; + case ZIR_INST_INT_FROM_BOOL: + instMapPut(&sema->inst_map, inst, + zirIntFromBool(sema, block, inst)); + i++; + continue; case ZIR_INST_NEGATE_WRAP: instMapPut(&sema->inst_map, inst, zirNegateWrap(sema, block, inst)); diff --git a/stage0/sema_test.zig b/stage0/sema_test.zig @@ -1019,3 +1019,50 @@ test "sema air: same-file inline call with two args" { \\} ); } + +test "sema air: intFromBool" { + try semaAirRawCheck("export fn f(x: bool) u32 { return @intFromBool(x); }"); +} + +test "sema air: add_sat" { + try semaAirRawCheck("export fn f(x: u32, y: u32) u32 { return x +| y; }"); +} + +test "sema air: sub_sat" { + try semaAirRawCheck("export fn f(x: u32, y: u32) u32 { return x -| y; }"); +} + +test "sema air: bit_or" { + try semaAirRawCheck("export fn f(x: u32, y: u32) u32 { return x | y; }"); +} + +test "sema air: bit_and" { + try semaAirRawCheck("export fn f(x: u32, y: u32) u32 { return x & y; }"); +} + +test "sema air: f16 add" { + try semaAirRawCheck("export fn f(x: f16, y: f16) f16 { return x + y; }"); +} + +test "sema air: f64 mul" { + try semaAirRawCheck("export fn f(x: f64, y: f64) f64 { return x * y; }"); +} + +test "sema air: intcast computed dest type" { + try semaAirRawCheck( + \\export fn f(x: u16) u32 { + \\ return @intCast(x); + \\} + ); +} + +test "sema air: multiple return paths" { + try semaAirRawCheck( + \\export fn f(x: u32) u32 { + \\ return x + 1; + \\} + \\export fn g(x: u32) u32 { + \\ return x * 2; + \\} + ); +}