Browse Source

fcl-passrc: process TBinaryExpr left lists without stack

mattias 4 years ago
parent
commit
d2eb00eaab

+ 48 - 0
compiler/packages/fcl-passrc/src/pasresolveeval.pas

@@ -1488,6 +1488,8 @@ function TResExprEvaluator.EvalBinaryExpr(Expr: TBinaryExpr;
   Flags: TResEvalFlags): TResEvalValue;
 var
   LeftValue, RightValue: TResEvalValue;
+  Left: TPasExpr;
+  SubBin: TBinaryExpr;
 begin
   Result:=nil;
   if (Expr.Kind=pekBinary) and (Expr.OpCode=eopSubIdent) then
@@ -1498,6 +1500,52 @@ begin
   LeftValue:=nil;
   RightValue:=nil;
   try
+    if Expr.OpCode=eopAdd then
+      begin
+      // handle multi adds without stack
+      Left:=Expr.left;
+      while Left.ClassType=TBinaryExpr do
+        begin
+        SubBin:=TBinaryExpr(Left);
+        if SubBin.OpCode<>eopAdd then break;
+        Left:=SubBin.left;
+        end;
+      LeftValue:=Eval(Left,Flags);
+      while LeftValue<>nil do
+        begin
+        SubBin:=TBinaryExpr(Left.Parent);
+        RightValue:=Eval(SubBin.right,Flags);
+        if RightValue=nil then exit;
+
+        if LeftValue.Kind=revkExternal then
+          begin
+          if [refConst,refConstExt]*Flags=[refConst] then
+            RaiseConstantExprExp(20210321205928,Expr.left);
+          Result:=LeftValue;
+          LeftValue:=nil;
+          exit;
+          end;
+        if RightValue.Kind=revkExternal then
+          begin
+          if [refConst,refConstExt]*Flags=[refConst] then
+            RaiseConstantExprExp(20210321205948,Expr.right);
+          Result:=RightValue;
+          RightValue:=nil;
+          exit;
+          end;
+
+        Result:=EvalBinaryAddExpr(SubBin,LeftValue,RightValue);
+        ReleaseEvalValue(LeftValue);
+        if SubBin=Expr then exit;
+
+        LeftValue:=Result;
+        Result:=nil;
+        Left:=SubBin;
+        end;
+
+      exit;
+      end;
+
     LeftValue:=Eval(Expr.left,Flags);
     if LeftValue=nil then exit;
     RightValue:=Eval(Expr.right,Flags);

+ 26 - 3
compiler/packages/fcl-passrc/src/pastree.pp

@@ -5869,7 +5869,6 @@ begin
   end;
 end;
 
-
 constructor TBinaryExpr.Create(AParent : TPasElement; xleft,xright:TPasExpr; AOpCode:TExprOpCode);
 begin
   inherited Create(AParent,pekBinary, AOpCode);
@@ -5889,9 +5888,33 @@ begin
 end;
 
 destructor TBinaryExpr.Destroy;
+var
+  El: TPasExpr;
+  SubBin: TBinaryExpr;
 begin
-  ReleaseAndNil(TPasElement(left){$IFDEF CheckPasTreeRefCount},'TBinaryExpr.left'{$ENDIF});
-  ReleaseAndNil(TPasElement(right){$IFDEF CheckPasTreeRefCount},'TBinaryExpr.right'{$ENDIF});
+  // handle left of binary chains without stack
+  El:=Left;
+  while El is TBinaryExpr do
+    begin
+    SubBin:=TBinaryExpr(El);
+    El:=SubBin.left;
+    if (El=nil) or (El.Parent<>SubBin) then
+      begin
+      El:=SubBin;
+      break;
+      end;
+    end;
+
+  repeat
+    if El=left then
+      SubBin:=Self
+    else
+      SubBin:=TBinaryExpr(El.Parent);
+    ReleaseAndNil(TPasElement(SubBin.left){$IFDEF CheckPasTreeRefCount},'TBinaryExpr.left'{$ENDIF});
+    ReleaseAndNil(TPasElement(SubBin.right){$IFDEF CheckPasTreeRefCount},'TBinaryExpr.left'{$ENDIF});
+    El:=SubBin;
+  until El=Self;
+
   inherited Destroy;
 end;
 

+ 25 - 2
compiler/packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -1711,6 +1711,8 @@ var
   Decl: TPasElement;
   ModScope: TPasModuleScope;
   Access: TResolvedRefAccess;
+  Bin: TBinaryExpr;
+  Left: TPasExpr;
 begin
   if El=nil then exit;
   // Note: expression itself is not marked, but it can reference identifiers
@@ -1792,8 +1794,29 @@ begin
     // ok
   else if C=TBinaryExpr then
     begin
-    UseExpr(TBinaryExpr(El).left);
-    UseExpr(TBinaryExpr(El).right);
+    Bin:=TBinaryExpr(El);
+    if Bin.OpCode=eopAdd then
+      begin
+      // handle multi add expressions without stack
+      Left:=Bin;
+      while Left.ClassType=TBinaryExpr do
+        begin
+        Bin:=TBinaryExpr(Left);
+        if Bin.OpCode<>eopAdd then break;
+        Left:=Bin.left;
+        end;
+      UseExpr(Left);
+      repeat
+        Bin:=TBinaryExpr(Left.Parent);
+        UseExpr(Bin.right);
+        Left:=Bin;
+      until Left=El;
+      end
+    else
+      begin
+      UseExpr(Bin.left);
+      UseExpr(Bin.right);
+      end;
     end
   else if C=TUnaryExpr then
     UseExpr(TUnaryExpr(El).Operand)