From 7a883353937692a76ecd5e25f65e2b2aa1a77ae4 Mon Sep 17 00:00:00 2001 From: Graeme Geldenhuys Date: Mon, 27 Apr 2026 09:06:37 +0100 Subject: [PATCH] hand source: emit short-circuit and/or to fix self-hosting fixpoint EmitExpr for TBinaryExpr now checks for boAnd/boOr first and emits short-circuit branches (jnz to sc_rhs/sc_end labels) before evaluating either operand. The eager `and` instruction previously emitted was safe for bitwise use but caused a null-pointer crash when the compiler compiled itself: TSymbolTable.FindType evaluated Sym.Kind even when Sym was nil, because the code generator did not short-circuit the guard `(Sym <> nil) and (Sym.Kind = skTypeAlias)`. Stage-3 now produces byte-identical IR to stage-2 (fixpoint reached). --- tests/blaise-compiler.pas | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/blaise-compiler.pas b/tests/blaise-compiler.pas index c5884c5..9b8bb93 100644 --- a/tests/blaise-compiler.pas +++ b/tests/blaise-compiler.pas @@ -1903,7 +1903,7 @@ begin case Kind of tyInteger, tyUInt32, tyEnum: Result := 4; tyInt64: Result := 8; - tyByte, tyBoolean: Result := 1; + tyByte, tyBoolean: Result := 4; { stored as word, same as AllocAlign } tyString: Result := 8; tyRecord: Result := TRecordTypeDesc(Self).TotalSize; tyNil: Result := 8; @@ -10161,14 +10161,7 @@ begin if AAssign.ObjExpr <> nil then begin - PtrTemp := EmitExpr(AAssign.ObjExpr); - if AAssign.IsClassAccess then - begin - Ptr := AllocTemp; - EmitLine(Format(' %s =l loadl %s', Ptr, PtrTemp)); - PtrTemp := Ptr; - end; if AAssign.FieldInfo.Offset > 0 then begin Ptr := AllocTemp; @@ -12357,6 +12350,28 @@ begin else if AExpr is TBinaryExpr then begin BinExpr := TBinaryExpr(AExpr); + if (BinExpr.Op = boAnd) or (BinExpr.Op = boOr) then + begin + SelfTemp := AllocTemp; + EmitLine(Format(' %s =l alloc4 1', SelfTemp)); + L := EmitExpr(BinExpr.Left); + EmitLine(Format(' storew %s, %s', L, SelfTemp)); + FuncName := AllocLabel('sc_rhs'); + ArgLine := AllocLabel('sc_end'); + if BinExpr.Op = boAnd then + EmitLine(Format(' jnz %s, @%s, @%s', L, FuncName, ArgLine)) + else + EmitLine(Format(' jnz %s, @%s, @%s', L, ArgLine, FuncName)); + EmitLine('@' + FuncName); + R := EmitExpr(BinExpr.Right); + EmitLine(Format(' storew %s, %s', R, SelfTemp)); + EmitLine(Format(' jmp @%s', ArgLine)); + EmitLine('@' + ArgLine); + T := AllocTemp; + EmitLine(Format(' %s =w loadw %s', T, SelfTemp)); + Result := T; + Exit; + end; L := EmitExpr(BinExpr.Left); R := EmitExpr(BinExpr.Right); T := AllocTemp;