← board

A by-ref float param on a cdecl call is classified SSE, and the program segfaults

A var/const float parameter is a pointer, so SysV puts it in the INTEGER class. Both cdecl argument classifiers read the parameter's declared TypeKind with no IsRef check, so var d: Double was passed in xmm while the callee read a pointer out of a GP register. The result is a segfault, not a wrong number.

type TCb = function(var a: Double; b: Integer): Integer; cdecl;
function MyCb(var a: Double; b: Integer): Integer; cdecl;
begin Result := Trunc(a) + b; end;   { want 9 for (2.5, 7) }

Two halves with different histories — this is the part worth reading

via fnptr (IR_CALL_IND) called directly (IR_CALL)
pinned, pre-SysV-prologue segfault 9, correct
HEAD after the SysV prologue segfault segfault
with this fix 9 9

Recording that split rather than filing one undifferentiated crash, because "pre-existing" and "I broke it last commit" call for different amounts of suspicion about what else moved.

Controls run

Fix

Add the IsRef exclusion to the register-class decision in both classifiers (ir_codegen.inc, IR_CALL and IR_CALL_IND). Only the class decision is corrected; tk itself is left alone at the two sites below the direct-call classifier, which use it for variant/narrowing decisions a by-ref param does not reach.

Three sites recompute the same classification expression in the direct-call path alone. That is the root-cause-over-microfix smell — two is a smell, three is a design flaw — and a single "effective ABI class of argument i" helper is the real shape. Not done here because it touches the variadic and variant paths and wants its own gate; the crash fix should not wait behind a refactor.

Gate

test/test_cdecl_bodied_sysv.pas checks by-ref float param via fnptr and by-ref float param direct (14 checks total, in test-core). Both segfault on a pre-fix binary.

Log