From: Tom Tromey <[email protected]>

For a gnat-llvm debuginfo patch, it was convenient to be able to
inspect the expressions created during back-annotation.  This patch
adds a new generic Visit procedure that can be implemented to allow
such inspection.  List_GCC_Expression is reimplemented in terms of
this procedure as a proof of concept.

gcc/ada/ChangeLog:

        * repinfo.adb (Visit): New procedure.
        (List_GCC_Expression): Rewrite.
        * repinfo.ads (Visit): New generic procedure.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/repinfo.adb | 388 +++++++++++++++++++++++++-------------------
 gcc/ada/repinfo.ads |  32 ++++
 2 files changed, 249 insertions(+), 171 deletions(-)

diff --git a/gcc/ada/repinfo.adb b/gcc/ada/repinfo.adb
index a8cb126d192..14c29305690 100644
--- a/gcc/ada/repinfo.adb
+++ b/gcc/ada/repinfo.adb
@@ -283,6 +283,64 @@ package body Repinfo is
       return U >= Uint_0;
    end Is_Static_SO_Ref;
 
+   -----------
+   -- Visit --
+   -----------
+
+   procedure Visit (Expr : Node_Ref_Or_Val) is
+   begin
+      pragma Assert (Present (Expr));
+      if Expr >= 0 then
+         Visit_Constant (Expr);
+         return;
+      end if;
+
+      declare
+         Node : Exp_Node renames Rep_Table.Table (-UI_To_Int (Expr));
+      begin
+         case Node.Expr is
+            when Cond_Expr =>
+               Visit_Cond_Expr (Node.Op1, Node.Op2, Node.Op3);
+
+            when Plus_Expr
+                 | Minus_Expr
+                 | Mult_Expr
+                 | Trunc_Div_Expr
+                 | Ceil_Div_Expr
+                 | Floor_Div_Expr
+                 | Trunc_Mod_Expr
+                 | Ceil_Mod_Expr
+                 | Floor_Mod_Expr
+                 | Exact_Div_Expr
+                 | Min_Expr
+                 | Max_Expr
+                 | Truth_And_Expr
+                 | Truth_Or_Expr
+                 | Truth_Xor_Expr
+                 | Lt_Expr
+                 | Le_Expr
+                 | Gt_Expr
+                 | Ge_Expr
+                 | Eq_Expr
+                 | Ne_Expr
+                 | Bit_And_Expr
+              =>
+               Visit_Binop (Node.Expr, Node.Op1, Node.Op2);
+
+            when Negate_Expr
+                 | Abs_Expr
+                 | Truth_Not_Expr =>
+               Visit_Unop (Node.Expr, Node.Op1);
+
+            when Discrim_Val =>
+               Visit_Discriminant (Node.Op1);
+
+            when Dynamic_Val =>
+               Visit_Variable (Node.Op1);
+         end case;
+      end;
+   end Visit;
+
    ---------
    -- lgx --
    ---------
@@ -581,189 +639,177 @@ package body Repinfo is
 
    procedure List_GCC_Expression (U : Node_Ref_Or_Val) is
 
-      procedure Print_Expr (Val : Node_Ref_Or_Val);
-      --  Internal recursive procedure to print expression
+      procedure Unop (Code : TCode; Op : Node_Ref_Or_Val);
+      procedure Binop (Code : TCode; Lhs : Node_Ref_Or_Val;
+                      Rhs : Node_Ref_Or_Val);
+      procedure Cond_Expr (Test : Node_Ref_Or_Val;
+                          Lhs : Node_Ref_Or_Val;
+                          Rhs : Node_Ref_Or_Val);
+      procedure Const (Val : Node_Ref_Or_Val);
+      procedure Discriminant (Val : Node_Ref_Or_Val);
+      procedure Variable (Val : Node_Ref_Or_Val);
 
-      ----------------
-      -- Print_Expr --
-      ----------------
+      procedure Print_It is new Visit (Visit_Unop => Unop,
+                                       Visit_Binop => Binop,
+                                       Visit_Cond_Expr => Cond_Expr,
+                                       Visit_Constant => Const,
+                                       Visit_Discriminant => Discriminant,
+                                       Visit_Variable => Variable);
 
-      procedure Print_Expr (Val : Node_Ref_Or_Val) is
+      procedure Unop (Code : TCode; Op : Node_Ref_Or_Val) is
+         procedure Emit (S : String);
+         procedure Emit (S : String) is
+         begin
+            if List_Representation_Info_To_JSON then
+               Write_Str ("{ ""code"": """);
+               if S (S'Last) = ' ' then
+                  Write_Str (S (S'First .. S'Last - 1));
+               else
+                  Write_Str (S);
+               end if;
+               Write_Str (""", ""operands"": [ ");
+               Print_It (Op);
+               Write_Str (" ] }");
+            else
+               Write_Str (S);
+               Print_It (Op);
+            end if;
+         end Emit;
       begin
-         if Val >= 0 then
-            UI_Write (Val, Decimal);
+         case Code is
+            when Negate_Expr =>
+               Emit ("-");
+            when Abs_Expr =>
+               Emit ("abs ");
+            when Truth_Not_Expr =>
+               Emit ("not ");
+            when Discrim_Val =>
+               Emit ("#");
+            when Dynamic_Val =>
+               Emit ("var");
+            when others =>
+               Emit ("ERROR");
+         end case;
+      end Unop;
 
+      procedure Binop (Code : TCode; Lhs : Node_Ref_Or_Val;
+                      Rhs : Node_Ref_Or_Val)
+      is
+         procedure Emit (S : String);
+         procedure Emit (S : String) is
+         begin
+            if List_Representation_Info_To_JSON then
+               Write_Str ("{ ""code"": """);
+               Write_Str (S (S'First + 1 .. S'Last - 1));
+               Write_Str (""", ""operands"": [ ");
+               Print_It (Lhs);
+               Write_Str (", ");
+               Print_It (Rhs);
+               Write_Str (" ] }");
+            else
+               Write_Char ('(');
+               Print_It (Lhs);
+               Write_Str (S);
+               Print_It (Rhs);
+               Write_Char (')');
+            end if;
+         end Emit;
+
+      begin
+         case Code is
+            when Plus_Expr =>
+               Emit (" + ");
+            when Minus_Expr =>
+               Emit (" - ");
+            when Mult_Expr =>
+               Emit (" * ");
+            when Trunc_Div_Expr =>
+               Emit (" /t ");
+            when Ceil_Div_Expr =>
+               Emit (" /c ");
+            when Floor_Div_Expr =>
+               Emit (" /f ");
+            when Trunc_Mod_Expr =>
+               Emit (" modt ");
+            when Ceil_Mod_Expr =>
+               Emit (" modc ");
+            when Floor_Mod_Expr =>
+               Emit (" modf ");
+            when Exact_Div_Expr =>
+               Emit (" /e ");
+            when Min_Expr =>
+               Emit (" min ");
+            when Max_Expr =>
+               Emit (" max ");
+            when Truth_And_Expr =>
+               Emit (" and ");
+            when Truth_Or_Expr =>
+               Emit (" or ");
+            when Truth_Xor_Expr =>
+               Emit (" xor ");
+            when Lt_Expr =>
+               Emit (" < ");
+            when Le_Expr =>
+               Emit (" <= ");
+            when Gt_Expr =>
+               Emit (" > ");
+            when Ge_Expr =>
+               Emit (" >= ");
+            when Eq_Expr =>
+               Emit (" == ");
+            when Ne_Expr =>
+               Emit (" != ");
+            when Bit_And_Expr =>
+               Emit (" & ");
+            when others =>
+               Emit ("ERROR");
+         end case;
+      end Binop;
+
+      procedure Cond_Expr (Test : Node_Ref_Or_Val;
+                           Lhs : Node_Ref_Or_Val;
+                           Rhs : Node_Ref_Or_Val) is
+      begin
+         if List_Representation_Info_To_JSON then
+            Write_Str ("{ ""code"": ""?<>""");
+            Write_Str (", ""operands"": [ ");
+            Print_It (Test);
+            Write_Str (", ");
+            Print_It (Lhs);
+            Write_Str (", ");
+            Print_It (Rhs);
+            Write_Str (" ] }");
          else
-            declare
-               Node : Exp_Node renames Rep_Table.Table (-UI_To_Int (Val));
-
-               procedure Unop (S : String);
-               --  Output text for unary operator with S being operator name
-
-               procedure Binop (S : String);
-               --  Output text for binary operator with S being operator name
-
-               ----------
-               -- Unop --
-               ----------
-
-               procedure Unop (S : String) is
-               begin
-                  if List_Representation_Info_To_JSON then
-                     Write_Str ("{ ""code"": """);
-                     if S (S'Last) = ' ' then
-                        Write_Str (S (S'First .. S'Last - 1));
-                     else
-                        Write_Str (S);
-                     end if;
-                     Write_Str (""", ""operands"": [ ");
-                     Print_Expr (Node.Op1);
-                     Write_Str (" ] }");
-                  else
-                     Write_Str (S);
-                     Print_Expr (Node.Op1);
-                  end if;
-               end Unop;
-
-               -----------
-               -- Binop --
-               -----------
-
-               procedure Binop (S : String) is
-               begin
-                  if List_Representation_Info_To_JSON then
-                     Write_Str ("{ ""code"": """);
-                     Write_Str (S (S'First + 1 .. S'Last - 1));
-                     Write_Str (""", ""operands"": [ ");
-                     Print_Expr (Node.Op1);
-                     Write_Str (", ");
-                     Print_Expr (Node.Op2);
-                     Write_Str (" ] }");
-                  else
-                     Write_Char ('(');
-                     Print_Expr (Node.Op1);
-                     Write_Str (S);
-                     Print_Expr (Node.Op2);
-                     Write_Char (')');
-                  end if;
-               end Binop;
-
-            --  Start of processing for Print_Expr
-
-            begin
-               case Node.Expr is
-                  when Cond_Expr =>
-                     if List_Representation_Info_To_JSON then
-                        Write_Str ("{ ""code"": ""?<>""");
-                        Write_Str (", ""operands"": [ ");
-                        Print_Expr (Node.Op1);
-                        Write_Str (", ");
-                        Print_Expr (Node.Op2);
-                        Write_Str (", ");
-                        Print_Expr (Node.Op3);
-                        Write_Str (" ] }");
-                     else
-                        Write_Str ("(if ");
-                        Print_Expr (Node.Op1);
-                        Write_Str (" then ");
-                        Print_Expr (Node.Op2);
-                        Write_Str (" else ");
-                        Print_Expr (Node.Op3);
-                        Write_Str (")");
-                     end if;
-
-                  when Plus_Expr =>
-                     Binop (" + ");
-
-                  when Minus_Expr =>
-                     Binop (" - ");
-
-                  when Mult_Expr =>
-                     Binop (" * ");
-
-                  when Trunc_Div_Expr =>
-                     Binop (" /t ");
-
-                  when Ceil_Div_Expr =>
-                     Binop (" /c ");
-
-                  when Floor_Div_Expr =>
-                     Binop (" /f ");
-
-                  when Trunc_Mod_Expr =>
-                     Binop (" modt ");
-
-                  when Ceil_Mod_Expr =>
-                     Binop (" modc ");
-
-                  when Floor_Mod_Expr =>
-                     Binop (" modf ");
-
-                  when Exact_Div_Expr =>
-                     Binop (" /e ");
-
-                  when Negate_Expr =>
-                     Unop ("-");
-
-                  when Min_Expr =>
-                     Binop (" min ");
-
-                  when Max_Expr =>
-                     Binop (" max ");
-
-                  when Abs_Expr =>
-                     Unop ("abs ");
-
-                  when Truth_And_Expr =>
-                     Binop (" and ");
-
-                  when Truth_Or_Expr =>
-                     Binop (" or ");
-
-                  when Truth_Xor_Expr =>
-                     Binop (" xor ");
-
-                  when Truth_Not_Expr =>
-                     Unop ("not ");
-
-                  when Lt_Expr =>
-                     Binop (" < ");
-
-                  when Le_Expr =>
-                     Binop (" <= ");
-
-                  when Gt_Expr =>
-                     Binop (" > ");
-
-                  when Ge_Expr =>
-                     Binop (" >= ");
-
-                  when Eq_Expr =>
-                     Binop (" == ");
-
-                  when Ne_Expr =>
-                     Binop (" != ");
-
-                  when Bit_And_Expr =>
-                     Binop (" & ");
-
-                  when Discrim_Val =>
-                     Unop ("#");
-
-                  when Dynamic_Val =>
-                     Unop ("var");
-               end case;
-            end;
+            Write_Str ("(if ");
+            Print_It (Test);
+            Write_Str (" then ");
+            Print_It (Lhs);
+            Write_Str (" else ");
+            Print_It (Rhs);
+            Write_Str (")");
          end if;
-      end Print_Expr;
+      end Cond_Expr;
 
-   --  Start of processing for List_GCC_Expression
+      procedure Const (Val : Node_Ref_Or_Val) is
+      begin
+         UI_Write (Val, Decimal);
+      end Const;
+
+      procedure Discriminant (Val : Node_Ref_Or_Val) is
+      begin
+         Unop (Discrim_Val, Val);
+      end Discriminant;
+
+      procedure Variable (Val : Node_Ref_Or_Val) is
+      begin
+         Unop (Dynamic_Val, Val);
+      end Variable;
 
    begin
       if No (U) then
          Write_Unknown_Val;
       else
-         Print_Expr (U);
+         Print_It (U);
       end if;
    end List_GCC_Expression;
 
diff --git a/gcc/ada/repinfo.ads b/gcc/ada/repinfo.ads
index 98ba98375f3..597e8b98762 100644
--- a/gcc/ada/repinfo.ads
+++ b/gcc/ada/repinfo.ads
@@ -345,6 +345,38 @@ package Repinfo is
    --  and entity id values and the back end makes Get_Dynamic_SO_Ref
    --  calls to retrieve them.
 
+   generic
+      with procedure Visit_Unop (Code : TCode; Op : Node_Ref_Or_Val);
+      --  Visit a unary operation. The opcode and argument are passed
+      --  in.
+
+      with procedure Visit_Binop (Code : TCode; Lhs : Node_Ref_Or_Val;
+                                  Rhs : Node_Ref_Or_Val);
+      --  Visit a binary operation. The opcode and the arguments are
+      --  passed in.
+
+      with procedure Visit_Cond_Expr (Test : Node_Ref_Or_Val;
+                                      Lhs : Node_Ref_Or_Val;
+                                      Rhs : Node_Ref_Or_Val);
+      --  Visit a conditional operation. The arguments are passed in
+      --  (the opcode is always Cond_Expr).
+
+      with procedure Visit_Constant (Val : Node_Ref_Or_Val);
+      --  Visit a constant operand. The constant is passed in.
+
+      with procedure Visit_Discriminant (Val : Node_Ref_Or_Val);
+      --  Visit a discriminant. The discriminant number is passed in.
+
+      with procedure Visit_Variable (Val : Node_Ref_Or_Val);
+      --  Visit a variable reference. The variable's index (see
+      --  Dynamic_Val) is passed in.
+
+   procedure Visit (Expr : Node_Ref_Or_Val);
+   --  A way to walk over a back annotation expression. The user
+   --  provides callbacks which are called with the operands and (when
+   --  needed) the code. Users can recurse on the operands by calling
+   --  Visit again.
+
    ------------------------------
    -- External tools Interface --
    ------------------------------
-- 
2.51.0

Reply via email to