Previously zirCoercePtrElemTy was a no-op (returned value unchanged).
Now it resolves the pointer type from the LHS, extracts the element
type, and coerces the RHS value to that element type.
Handles the .one pointer case from Sema.zig: if the element type is
known and is not anyopaque/void, coerce the value. Preserves no-op
behavior for other pointer sizes or unresolvable types.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Previously, zirOptionalPayload only handled comptime optional
unwrapping. Runtime optional values (AIR instructions) returned
void instead of emitting proper AIR code.
Add runtime path: if operand is a runtime AIR instruction with
optional type, get the payload child type and emit
AIR_INST_OPTIONAL_PAYLOAD with ty_op layout.
Also add AIR_INST_OPTIONAL_PAYLOAD to semaTypeOf ty_op group.
Ported from Sema.zig zirOptionalPayload runtime path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When coercing comptime_int to bool, produce the correct bool constant
(IP_INDEX_BOOL_TRUE/FALSE) instead of trying to create an IP_KEY_INT
entry with bool type (which wouldn't match the pre-interned bool constants).
Ported from Sema.zig coerce comptime_int → bool path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are comptime-known floats (IP_KEY_FLOAT),
comparison operations now fold to bool constants at compile time.
- zirCmp: adds float fold before integer fold for LT/LTE/GT/GTE
- zirCmpEq: adds float fold before integer fold for EQ/NEQ
Ported from Sema.zig cmpNumeric → compareScalars for comptime floats.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Fixes a case where comptime_int + concrete_float would not fold at
comptime: after coercion, both become float IP entries, but the
pre-coercion float check had already passed without folding.
Added a second float fold check after resolvePeerTypes+coerce, so
mixed comptime_int/float operations fold correctly.
Ported from Sema.zig analyzeArithmetic which calls resolveValue on
the coerced operands.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both @min/@max operands are comptime-known floats (IP_KEY_FLOAT),
fold the result at compile time. Result type is the wider of the two
float types, or comptime_float if both are comptime_float.
Ported from Sema.zig analyzeMinMax → Value.numberMin/Max.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are comptime-known float values (IP_KEY_FLOAT),
compute the division result at compile time and return the folded
float value. Matches Sema.zig zirDiv → arith.div() for comptime
float operands.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are comptime-known floats (IP_KEY_FLOAT entries,
including comptime_float and concrete float types), fold the result
at comptime instead of emitting a runtime AIR instruction.
Ported from Sema.zig analyzeArithmetic: resolveValue(casted_lhs/rhs)
path which evaluates comptime values via arith.add/sub/mul.
Handles ADD, SUB, MUL variants (including wrap/sat) for both
comptime_float × comptime_float and concrete float × float. Result
type is the wider of the two float types.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When semaCoerce encounters comptime_int → concrete float (or
comptime_float), it was incorrectly calling semaCoerceIntRef which
produces an IP_KEY_INT entry with a float type — wrong.
Fix by detecting the float target first: convert the integer value
to a double and intern an IP_KEY_FLOAT entry. This matches Sema.zig
coerce comptime_int → float path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When both operands are concrete float types (e.g. f32 + f64),
resolvePeerTypes returned the lhs type regardless of width.
Ported from Sema.zig peer_resolve_float strategy: return the
wider float type.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
zirNegate and zirNegateWrap: extend the float detection to include
IP_INDEX_COMPTIME_FLOAT_TYPE. Previously floatBits() returned 0 for
comptime_float, causing negate to fall through to integer path.
This fixes -(comptime_float) and -(comptime_float) wrap.
zirAbs: similarly extend float check to include comptime_float so
@abs on comptime_float values is properly folded at comptime.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The comptime equality check compared only lo/hi magnitude fields,
ignoring is_negative. This meant (-5) == 5 would return true.
Fix by also checking lhs_neg == rhs_neg. Zero is never negative
(internComptimeInt already clears neg for zero values), so this
handles the -0 == 0 edge case correctly.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The comptime folding path in zirCmp used unsigned comparison of
the magnitude fields (lo/hi), ignoring the is_negative sign flag.
This gave wrong results for mixed-sign comparisons like (-5) < 3.
Replace with a proper signed 128-bit comparison that:
- If signs differ: negative < positive
- Both non-negative: compare magnitudes in ascending order
- Both negative: compare magnitudes in descending order (larger mag = smaller value)
Also derive equality separately for LTE/GTE cases.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
zirAbs now folds @abs for comptime_int operands: absolute value is
simply clearing the is_negative flag. This matches Sema.zig which
treats comptime_int like float/comptime_float (result_ty = operand_ty)
and calls maybeConstantUnaryMath(Value.abs).
Also fold @abs for comptime-known typed signed integers: since the
result type is already unsigned, we just intern the magnitude (lo/hi)
with the unsigned result type and is_negative=false.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
zirBoolBr: after analyzing the RHS body, if the result is
comptime-known and equals the short-circuit value (true for or,
false for and), fold the whole expression to the comptime result.
This matches Sema.zig lines 18167-18173.
zirTypeofBuiltin: set want_safety=false on the typeof block, matching
Sema.zig line 17941 which explicitly disables safety in typeof blocks.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Several comptime folding paths in sema.c ignored the is_negative flag
of sign-magnitude InternPool integers:
- internComptimeInt: add `neg` parameter (was hardcoded false).
- analyzeArithmetic: implement sign-aware add/sub/mul via addSignedMag128
helper. add(a,b) handles mixed signs by subtracting smaller magnitude;
sub(a,b) = add(a,-b); mul result_neg = lhs_neg XOR rhs_neg.
- zirDiv: pass correct sign to result (lhs_neg != rhs_neg).
- zirShl/zirShr: preserve lhs sign through comptime shift.
- zirMinMax: use isComptimeIntWide (128-bit) instead of isComptimeInt
(64-bit) and implement full 128-bit signed comparison.
- semaTypeOf: add DIV_FLOOR, DIV_EXACT, DIV_FLOAT_OPTIMIZED, MOD, REM
to the bin_op type-from-lhs group.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Simplify the 128-bit case in zirByteSwap comptime folding:
- r_lo byte b ← val_hi byte (7-b)
- r_hi byte b ← val_lo byte (7-b)
Previous code had a dead `src < 8` check (always false).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add the float-to-integer coercion path: convert the float value to an
integer (truncating toward zero) and intern it with the target type.
Previously, comptime_float coercion to integer types was silently
ignored, returning the original float ref unchanged.
Also restructure the comptime_float case to explicitly separate
float→float from float→int paths.
Matches src/Sema.zig coerce: getCoerced(val, dst_ty) for float→int.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known integer operands (64-bit case), compute the quotient
at comptime instead of emitting AIR. Matches src/Sema.zig zirDiv: arith.div
for comptime-known values.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known float operands, compute -val at comptime instead of
emitting AIR_INST_NEG. Matches src/Sema.zig zirNegate: arith.negateFloat
for comptime values, preserving negative zero semantics.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known float operands, compute abs(val) at comptime
instead of emitting AIR. Matches src/Sema.zig zirAbs: maybeConstantUnaryMath
with Value.abs. Also extends to comptime_float type.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For comptime-known integer operands with bit-aligned widths, compute
the byte-swapped value at comptime rather than emitting AIR.
Matches src/Sema.zig zirByteSwap: arith.byteSwap() comptime path.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
For float operands, create IP_KEY_FLOAT(0.0) instead of IP_KEY_INT(0).
The previous code created an int zero with a float type, which is an
invalid IP entry. Matches src/Sema.zig zirNegateWrap: pt.intValue()
returns the appropriate zero for the scalar type.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Match upstream Sema.zig zirBitwise structure: resolve peer types and
coerce operands FIRST, then attempt comptime folding on the coerced
values. This ensures typed IP entries (e.g. u16(3)) are created as
side effects of coercion, matching Zig's IP entry sequence.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Implement runtime while/for loop handling:
- Reserve block_inst (outer) + loop_inst (inner) in advance
- Analyze loop body in loop_block
- If body ends noreturn: copy instructions to child_block (no repeat)
- Otherwise: add repeat instruction, set up loop_inst body in air_extra
- Resolve outer block via label merges (handles break-from-loop)
Matches src/Sema.zig zirLoop decomposition.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Use resolveZirTypeRef instead of returning void for instruction refs
in the single-instruction return type body case. This handles ptr_type,
int_type, array_type, etc. Matches upstream's resolveType call in zirFunc.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The coerce calls create IP side effects; comparison uses captured
lhs_lo/rhs_lo values. Use (void)semaCoerce() to make intent explicit.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
These ty_op instructions were missing from the semaTypeOf dispatch,
needed for the float negation path added in zirNegate.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add zirIntCast() and zirTruncate() as named entry points matching
src/Sema.zig's decomposition. Rename shared implementation to
analyzeTyOpCast(). Update dispatch and call sites.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Matches upstream Sema.zig which has zirBitNot → analyzeBitNot
two-function decomposition. Pure extraction, no behavioral change.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Extend skip_dedup_end to full preamble items_len (not just
preamble_memoized_end) so CC sub-type entries created by
ensureCcMemoizedStateC are in the skip range
- Set preamble_cc_start AFTER CC union creation so main analysis
creates fresh CC union via skip_dedup
- Clear all 15 CC-phase builtins (not just 5) for main shard re-resolution
- Reset cc_memoized_resolved so ensureCcMemoizedStateC re-runs in main
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Port Sema.zig analyzeArithmetic coercion: coerce both operands to
result_ty when result is not comptime_int, creating typed intermediate
IP entries that match the Zig compiler's output.
- Fix zirTypeofLog2IntType and zirShl to use ipIntern (dedup) instead
of ipForceIntern, matching Zig's pt.intType which deduplicates via
the global pool.
- Add cc_memoized_resolved / ensureCcMemoizedStateC for the CC phase of
builtin resolution (builtins 0-14), analogous to PerThread's CC stage.
- Add preamble_skip_ptr_nav flag to defer AS/CC ptr_nav creation to
main analysis, matching Zig's sharded IP where preamble and main
shards use different nav IDs.
- Extend ct_struct_vals.fields from 4 to 8 entries and store const char*
name instead of string_bytes index, enabling zirFieldValComptime to
access TypeInfo fields by name.
- Advance num_passing from 87 to 100.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two fixes for test 86 (inline_fn_with_plus_eq_call_inside_two_conditionals):
1. Skip duplicate func_type/func_decl in zirFunc when ensureNavValUpToDate
has already resolved the nav. Previously, ensureNavValUpToDate created
entries with ipForceIntern (no hash table) and zirFunc re-created them
with ipIntern (can't find existing), causing duplicates.
2. Defer non-generic body analysis from semaAnalyzeCall to match Zig's
ensureFuncBodyAnalysisQueued ordering. Callee body analysis is queued
and processed after the current function body completes, ensuring IP
entry ordering matches the Zig compiler's work queue semantics.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. `dev == .bootstrap` does not include wasm backend, no use.
2. different optimize modes _of the compiler_ (_not_ target) _should_
not emit a different AIR. Thus if we want to `zig build test-zig0
-Doptimize=ReleaseFast`, we most often mean to compile the test
executable under this mode, but not `air_gen`, which will only emit
the AIR for comparison.
zirEnumLiteral was storing simpleStringHash(name) — a djb2 hash — as the
enum_literal IP key field. Upstream Zig stores a NullTerminatedString index
(getOrPutString). All three read sites treat the field as a string table
index and dereference it into ip->string_bytes, so the hash value caused
silent out-of-bounds reads whenever enum_literal coercion, callconv, or
signedness parsing were exercised.
Replace simpleStringHash with ipGetOrPutString, matching upstream exactly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use ipIntern (not ipForceIntern) for func_instance so that multiple
calls to the same generic function with the same comptime args share
one IP entry. Fixes the two-generic-calls test case where Zig produces
one func_instance but C was producing two.
Bumps num_passing from 85 to 86.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port IP_KEY_FUNC_INSTANCE from upstream InternPool.getFuncInstance.
When a generic non-inline function is called, create a monomorphized
func_type (runtime params only) and a func_instance entry referencing
the generic owner's func_decl. This matches the Zig compiler's IP
entry sequence for generic instantiations.
Bumps num_passing from 84 to 85.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refactor to match upstream Sema.zig structure where zirCall handles
callee resolution and analyzeCall handles the actual call analysis.
The new semaAnalyzeCall function takes a CalleeResolution struct that
bundles cross-module state. No functional changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Generic functions (with comptime, anytype, or anytype_comptime params)
should not be compiled as standalone function bodies — they're resolved
via monomorphization when called with concrete types. Ported from
upstream: generic functions are excluded from analysis roots.
Detect comptime params by scanning the param body in the ZIR for
ZIR_INST_PARAM_COMPTIME, ZIR_INST_PARAM_ANYTYPE_COMPTIME, or
ZIR_INST_PARAM_ANYTYPE instruction tags.
Next blocker: test 84 (inline_fn_with_generic_call_inside_conditional)
has a monomorphization naming mismatch: C generates normalize__anon_503
while Zig generates normalize__anon_507. The IP index gap of 4 needs
investigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix non-inline function call to reuse the callee's existing func_decl
IP entry instead of creating a new one with func_inst as owner_nav.
Ported from upstream Sema.zig analyzeCall: func_val references the
resolved callee function, not a newly-created entry.
The callee is looked up by name in the file namespace. If the nav's
resolved_type already points to a func_decl (IP_KEY_FUNC), it's used
directly. Otherwise, the func_type from resolved_type is used to
construct and deduplicate the func_decl key.
Also fixes the coercion dedup fix from the previous commit: switched
semaCoerceIntRef from ipForceIntern to ipIntern now that skip_dedup
handles cross-shard separation.
Tests 80-83 now pass (call_inside_runtime_conditional, multi_func_call,
runtime_conditional_with_early_return, field_access_chain).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>