diff options
Diffstat (limited to 'ortho/mcode/ortho_code-exprs.adb')
-rw-r--r-- | ortho/mcode/ortho_code-exprs.adb | 1656 |
1 files changed, 1656 insertions, 0 deletions
diff --git a/ortho/mcode/ortho_code-exprs.adb b/ortho/mcode/ortho_code-exprs.adb new file mode 100644 index 0000000..b8da44c --- /dev/null +++ b/ortho/mcode/ortho_code-exprs.adb @@ -0,0 +1,1656 @@ +-- Mcode back-end for ortho - Expressions and control handling. +-- Copyright (C) 2006 Tristan Gingold +-- +-- GHDL is free software; you can redistribute it and/or modify it under +-- the terms of the GNU General Public License as published by the Free +-- Software Foundation; either version 2, or (at your option) any later +-- version. +-- +-- GHDL is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or +-- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +-- for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with GCC; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with Ada.Text_IO; +with Ada.Unchecked_Deallocation; +with GNAT.Table; +with Ortho_Code.Types; use Ortho_Code.Types; +with Ortho_Code.Consts; use Ortho_Code.Consts; +with Ortho_Code.Decls; use Ortho_Code.Decls; +with Ortho_Code.Debug; use Ortho_Code.Debug; +with Ortho_Code.Abi; +with Ortho_Code.Disps; +with Ortho_Code.Opts; +with Ortho_Code.Flags; + +package body Ortho_Code.Exprs is + + type Enode_Pad is mod 256; + + type Enode_Common is record + Kind : OE_Kind; -- about 1 byte (6 bits) + Reg : O_Reg; -- 1 byte + Mode : Mode_Type; -- 4 bits + Ref : Boolean; + Flag1 : Boolean; + Flag2 : Boolean; + Flag3 : Boolean; + Pad : Enode_Pad; + Arg1 : O_Enode; + Arg2 : O_Enode; + Info : Int32; + end record; + pragma Pack (Enode_Common); + for Enode_Common'Size use 4*32; + for Enode_Common'Alignment use 4; + + package Enodes is new GNAT.Table + (Table_Component_Type => Enode_Common, + Table_Index_Type => O_Enode, + Table_Low_Bound => 2, + Table_Initial => 1024, + Table_Increment => 100); + + function Get_Expr_Kind (Enode : O_Enode) return OE_Kind is + begin + return Enodes.Table (Enode).Kind; + end Get_Expr_Kind; + + function Get_Expr_Mode (Enode : O_Enode) return Mode_Type is + begin + return Enodes.Table (Enode).Mode; + end Get_Expr_Mode; + + function Get_Enode_Type (Enode : O_Enode) return O_Tnode is + begin + return O_Tnode (Enodes.Table (Enode).Info); + end Get_Enode_Type; + + function Get_Expr_Reg (Enode : O_Enode) return O_Reg is + begin + return Enodes.Table (Enode).Reg; + end Get_Expr_Reg; + + procedure Set_Expr_Reg (Enode : O_Enode; Reg : O_Reg) is + begin + Enodes.Table (Enode).Reg := Reg; + end Set_Expr_Reg; + + function Get_Expr_Operand (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg1; + end Get_Expr_Operand; + + procedure Set_Expr_Operand (Enode : O_Enode; Val : O_Enode) is + begin + Enodes.Table (Enode).Arg1 := Val; + end Set_Expr_Operand; + + function Get_Expr_Left (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg1; + end Get_Expr_Left; + + function Get_Expr_Right (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg2; + end Get_Expr_Right; + + procedure Set_Expr_Left (Enode : O_Enode; Val : O_Enode) is + begin + Enodes.Table (Enode).Arg1 := Val; + end Set_Expr_Left; + + procedure Set_Expr_Right (Enode : O_Enode; Val : O_Enode) is + begin + Enodes.Table (Enode).Arg2 := Val; + end Set_Expr_Right; + + function Get_Expr_Low (Cst : O_Enode) return Uns32 is + begin + return To_Uns32 (Int32 (Enodes.Table (Cst).Arg1)); + end Get_Expr_Low; + + function Get_Expr_High (Cst : O_Enode) return Uns32 is + begin + return To_Uns32 (Int32 (Enodes.Table (Cst).Arg2)); + end Get_Expr_High; + + function Get_Assign_Target (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg2; + end Get_Assign_Target; + + procedure Set_Assign_Target (Enode : O_Enode; Targ : O_Enode) is + begin + Enodes.Table (Enode).Arg2 := Targ; + end Set_Assign_Target; + + function Get_Expr_Lit (Lit : O_Enode) return O_Cnode is + begin + return O_Cnode (Enodes.Table (Lit).Arg1); + end Get_Expr_Lit; + + function Get_Conv_Type (Enode : O_Enode) return O_Tnode is + begin + return O_Tnode (Enodes.Table (Enode).Arg2); + end Get_Conv_Type; + + -- Leave node corresponding to the entry. + function Get_Entry_Leave (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg1; + end Get_Entry_Leave; + + procedure Set_Entry_Leave (Enode : O_Enode; Leave : O_Enode) is + begin + Enodes.Table (Enode).Arg1 := Leave; + end Set_Entry_Leave; + + function Get_Jump_Label (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg2; + end Get_Jump_Label; + + procedure Set_Jump_Label (Enode : O_Enode; Label : O_Enode) is + begin + Enodes.Table (Enode).Arg2 := Label; + end Set_Jump_Label; + + function Get_Addr_Object (Enode : O_Enode) return O_Dnode is + begin + return O_Dnode (Enodes.Table (Enode).Arg1); + end Get_Addr_Object; + + function Get_Addrl_Frame (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg2; + end Get_Addrl_Frame; + + procedure Set_Addrl_Frame (Enode : O_Enode; Frame : O_Enode) is + begin + Enodes.Table (Enode).Arg2 := Frame; + end Set_Addrl_Frame; + + function Get_Call_Subprg (Enode : O_Enode) return O_Dnode is + begin + return O_Dnode (Enodes.Table (Enode).Arg1); + end Get_Call_Subprg; + + function Get_Arg_Link (Enode : O_Enode) return O_Enode is + begin + return Enodes.Table (Enode).Arg2; + end Get_Arg_Link; + + function Get_Block_Decls (Blk : O_Enode) return O_Dnode is + begin + return O_Dnode (Enodes.Table (Blk).Arg2); + end Get_Block_Decls; + + function Get_Block_Parent (Blk : O_Enode) return O_Enode is + begin + return Enodes.Table (Blk).Arg1; + end Get_Block_Parent; + + function Get_Block_Has_Alloca (Blk : O_Enode) return Boolean is + begin + return Enodes.Table (Blk).Flag1; + end Get_Block_Has_Alloca; + + procedure Set_Block_Has_Alloca (Blk : O_Enode; Flag : Boolean) is + begin + Enodes.Table (Blk).Flag1 := Flag; + end Set_Block_Has_Alloca; + + function Get_End_Beg (Blk : O_Enode) return O_Enode is + begin + return Enodes.Table (Blk).Arg1; + end Get_End_Beg; + + function Get_Label_Info (Label : O_Enode) return Int32 is + begin + return Int32 (Enodes.Table (Label).Arg2); + end Get_Label_Info; + + procedure Set_Label_Info (Label : O_Enode; Info : Int32) is + begin + Enodes.Table (Label).Arg2 := O_Enode (Info); + end Set_Label_Info; + + function Get_Label_Block (Label : O_Enode) return O_Enode is + begin + return Enodes.Table (Label).Arg1; + end Get_Label_Block; + + function Get_Spill_Info (Spill : O_Enode) return Int32 is + begin + return Int32 (Enodes.Table (Spill).Arg2); + end Get_Spill_Info; + + procedure Set_Spill_Info (Spill : O_Enode; Info : Int32) is + begin + Enodes.Table (Spill).Arg2 := O_Enode (Info); + end Set_Spill_Info; + + -- Get the statement link. + function Get_Stmt_Link (Stmt : O_Enode) return O_Enode is + begin + return O_Enode (Enodes.Table (Stmt).Info); + end Get_Stmt_Link; + + procedure Set_Stmt_Link (Stmt : O_Enode; Next : O_Enode) is + begin + Enodes.Table (Stmt).Info := Int32 (Next); + end Set_Stmt_Link; + + function Get_BB_Next (Stmt : O_Enode) return O_Enode is + begin + return Enodes.Table (Stmt).Arg1; + end Get_BB_Next; + + procedure Set_BB_Next (Stmt : O_Enode; Next : O_Enode) is + begin + Enodes.Table (Stmt).Arg1 := Next; + end Set_BB_Next; + + function Get_BB_Number (Stmt : O_Enode) return Int32 is + begin + return Int32 (Enodes.Table (Stmt).Arg2); + end Get_BB_Number; + + procedure Set_Case_Branch (C : O_Enode; Branch : O_Enode) is + begin + Enodes.Table (C).Arg2 := Branch; + end Set_Case_Branch; + + procedure Set_Case_Branch_Choice (Branch : O_Enode; Choice : O_Enode) is + begin + Enodes.Table (Branch).Arg1 := Choice; + end Set_Case_Branch_Choice; + + function Get_Case_Branch_Choice (Branch : O_Enode) return O_Enode is + begin + return Enodes.Table (Branch).Arg1; + end Get_Case_Branch_Choice; + + procedure Set_Case_Choice_Link (Choice : O_Enode; N_Choice : O_Enode) is + begin + Enodes.Table (Choice).Info := Int32 (N_Choice); + end Set_Case_Choice_Link; + + function Get_Case_Choice_Link (Choice : O_Enode) return O_Enode is + begin + return O_Enode (Enodes.Table (Choice).Info); + end Get_Case_Choice_Link; + + function Get_Ref_Field (Ref : O_Enode) return O_Fnode is + begin + return O_Fnode (Enodes.Table (Ref).Arg2); + end Get_Ref_Field; + + function Get_Ref_Index (Ref : O_Enode) return O_Enode is + begin + return Enodes.Table (Ref).Arg2; + end Get_Ref_Index; + + function Get_Expr_Line_Number (Stmt : O_Enode) return Int32 is + begin + return Int32 (Enodes.Table (Stmt).Arg1); + end Get_Expr_Line_Number; + + function Get_Intrinsic_Operation (Stmt : O_Enode) return Int32 is + begin + return Int32 (Enodes.Table (Stmt).Arg1); + end Get_Intrinsic_Operation; + + Last_Stmt : O_Enode := O_Enode_Null; + + procedure Link_Stmt (Stmt : O_Enode) is + begin + if Last_Stmt = O_Enode_Null then + raise Program_Error; + end if; + Set_Stmt_Link (Last_Stmt, Stmt); + Last_Stmt := Stmt; + end Link_Stmt; + + function New_Enode (Kind : OE_Kind; + Rtype : O_Tnode; + Arg1 : O_Enode; + Arg2 : O_Enode) return O_Enode + is + Mode : Mode_Type; + begin + Mode := Get_Type_Mode (Rtype); + Enodes.Append (Enode_Common'(Kind => Kind, + Reg => 0, + Mode => Mode, + Ref => False, + Flag1 => False, + Flag2 => False, + Flag3 => False, + Pad => 0, + Arg1 => Arg1, + Arg2 => Arg2, + Info => Int32 (Rtype))); + return Enodes.Last; + end New_Enode; + + function New_Enode (Kind : OE_Kind; + Mode : Mode_Type; + Rtype : O_Tnode; + Arg1 : O_Enode; + Arg2 : O_Enode) return O_Enode + is + begin + Enodes.Append (Enode_Common'(Kind => Kind, + Reg => 0, + Mode => Mode, + Ref => False, + Flag1 => False, + Flag2 => False, + Flag3 => False, + Pad => 0, + Arg1 => Arg1, + Arg2 => Arg2, + Info => Int32 (Rtype))); + return Enodes.Last; + end New_Enode; + + procedure New_Enode_Stmt (Kind : OE_Kind; Arg1 : O_Enode; Arg2 : O_Enode) + is + begin + Enodes.Append (Enode_Common'(Kind => Kind, + Reg => 0, + Mode => Mode_Nil, + Ref => False, + Flag1 => False, + Flag2 => False, + Flag3 => False, + Pad => 0, + Arg1 => Arg1, + Arg2 => Arg2, + Info => 0)); + Link_Stmt (Enodes.Last); + end New_Enode_Stmt; + + procedure New_Enode_Stmt + (Kind : OE_Kind; Mode : Mode_Type; Arg1 : O_Enode; Arg2 : O_Enode) + is + begin + Enodes.Append (Enode_Common'(Kind => Kind, + Reg => 0, + Mode => Mode, + Ref => False, + Flag1 => False, + Flag2 => False, + Flag3 => False, + Pad => 0, + Arg1 => Arg1, + Arg2 => Arg2, + Info => 0)); + Link_Stmt (Enodes.Last); + end New_Enode_Stmt; + + Bb_Num : Int32 := 0; + Last_Bb : O_Enode := O_Enode_Null; + + procedure Create_BB is + begin + New_Enode_Stmt (OE_BB, Mode_Nil, O_Enode_Null, O_Enode (Bb_Num)); + if Last_Bb /= O_Enode_Null then + Set_BB_Next (Last_Bb, Enodes.Last); + end if; + Last_Bb := Enodes.Last; + Bb_Num := Bb_Num + 1; + end Create_BB; + + procedure Start_BB is + begin + if Flags.Flag_Opt_BB then + Create_BB; + end if; + end Start_BB; + pragma Inline (Start_BB); + + procedure Check_Ref (E : O_Enode) is + begin + if Enodes.Table (E).Ref then + raise Syntax_Error; + end if; + Enodes.Table (E).Ref := True; + end Check_Ref; + + procedure Check_Ref (E : O_Lnode) is + begin + Check_Ref (O_Enode (E)); + end Check_Ref; + + procedure Check_Value_Type (Val : O_Enode; Vtype : O_Tnode) is + begin + if Get_Enode_Type (Val) /= Vtype then + raise Syntax_Error; + end if; + end Check_Value_Type; + + function New_Const_U32 (Val : Uns32; Vtype : O_Tnode) return O_Enode + is + begin + return New_Enode (OE_Const, Vtype, + O_Enode (To_Int32 (Val)), O_Enode_Null); + end New_Const_U32; + + Last_Decl : O_Dnode := 2; + Cur_Block : O_Enode := O_Enode_Null; + + procedure Start_Declare_Stmt + is + Res : O_Enode; + begin + New_Enode_Stmt (OE_Beg, Cur_Block, O_Enode_Null); + Res := Enodes.Last; + Enodes.Table (Res).Arg2 := O_Enode + (Ortho_Code.Decls.Start_Declare_Stmt); + Cur_Block := Res; + end Start_Declare_Stmt; + + function New_Stack (Rtype : O_Tnode) return O_Enode is + begin + return New_Enode (OE_Get_Stack, Rtype, O_Enode_Null, O_Enode_Null); + end New_Stack; + + procedure New_Stack_Restore (Blk : O_Enode) + is + Save_Asgn : O_Enode; + Save_Var : O_Dnode; + begin + Save_Asgn := Get_Stmt_Link (Blk); + Save_Var := Get_Addr_Object (Get_Assign_Target (Save_Asgn)); + New_Enode_Stmt (OE_Set_Stack, New_Value (New_Obj (Save_Var)), + O_Enode_Null); + end New_Stack_Restore; + + procedure Finish_Declare_Stmt + is + Parent : O_Dnode; + begin + if Get_Block_Has_Alloca (Cur_Block) then + New_Stack_Restore (Cur_Block); + end if; + New_Enode_Stmt (OE_End, Cur_Block, O_Enode_Null); + Cur_Block := Get_Block_Parent (Cur_Block); + if Cur_Block = O_Enode_Null then + Parent := O_Dnode_Null; + else + Parent := Get_Block_Decls (Cur_Block); + end if; + Ortho_Code.Decls.Finish_Declare_Stmt (Parent); + end Finish_Declare_Stmt; + + function New_Label return O_Enode is + begin + return New_Enode (OE_Label, Mode_Nil, O_Tnode_Null, + Cur_Block, O_Enode_Null); + end New_Label; + + procedure Start_Subprogram_Body (Func : O_Dnode) + is + Start : O_Enode; + D_Body : O_Dnode; + Data : Subprogram_Data_Acc; + begin + if Cur_Subprg = null then + Abi.Start_Body (Func); + end if; + + Start := New_Enode (OE_Entry, Mode_Nil, O_Tnode_Null, + Last_Stmt, O_Enode_Null); + D_Body := Decls.Start_Subprogram_Body (Func, Start); + + -- Create the corresponding decl. + Enodes.Table (Start).Arg2 := O_Enode (D_Body); + + -- Create the data record. + Data := new Subprogram_Data'(Parent => Cur_Subprg, + First_Child => null, + Last_Child => null, + Brother => null, + Depth => Get_Decl_Depth (Func), + D_Decl => Func, + E_Entry => Start, + D_Body => D_Body, + Exit_Label => O_Enode_Null, + Last_Stmt => O_Enode_Null, + Stack_Max => 0); + + if not Flag_Debug_Hli then + Data.Exit_Label := New_Label; + end if; + + -- Link the record. + if Cur_Subprg = null then + -- A top-level subprogram. + if First_Subprg = null then + First_Subprg := Data; + else + Last_Subprg.Brother := Data; + end if; + Last_Subprg := Data; + else + -- A nested subprogram. + if Cur_Subprg.First_Child = null then + Cur_Subprg.First_Child := Data; + else + Cur_Subprg.Last_Child.Brother := Data; + end if; + Cur_Subprg.Last_Child := Data; + + -- Also save last_stmt. + Cur_Subprg.Last_Stmt := Last_Stmt; + end if; + + Cur_Subprg := Data; + Last_Stmt := Start; + + Start_Declare_Stmt; + + -- Create a basic block for the beginning of the subprogram. + Start_BB; + + -- Disp declarations. + if Cur_Subprg.Parent = null then + if Ortho_Code.Debug.Flag_Debug_Body + or Ortho_Code.Debug.Flag_Debug_Code + then + while Last_Decl <= D_Body loop + case Get_Decl_Kind (Last_Decl) is + when OD_Block => + -- Skip blocks. + Disp_Decl (1, Last_Decl); + Last_Decl := Get_Block_Last (Last_Decl) + 1; + when others => + Disp_Decl (1, Last_Decl); + Last_Decl := Last_Decl + 1; + end case; + end loop; + end if; + end if; + end Start_Subprogram_Body; + + procedure Finish_Subprogram_Body + is + Parent : Subprogram_Data_Acc; + begin + Finish_Declare_Stmt; + + -- Create a new basic block for the epilog. + Start_BB; + + if not Flag_Debug_Hli then + Link_Stmt (Cur_Subprg.Exit_Label); + end if; + + New_Enode_Stmt (OE_Leave, O_Enode_Null, O_Enode_Null); + + -- Save last statement. + Cur_Subprg.Last_Stmt := Enodes.Last; + -- Set Leave of Entry. + Set_Entry_Leave (Cur_Subprg.E_Entry, Enodes.Last); + + Decls.Finish_Subprogram_Body; + + Parent := Cur_Subprg.Parent; + + if Flags.Flag_Optimize then + Opts.Optimize_Subprg (Cur_Subprg); + end if; + + if Parent = null then + -- This is a top-level subprogram. + if Ortho_Code.Debug.Flag_Disp_Code then + Disps.Disp_Subprg (Cur_Subprg); + end if; + if Ortho_Code.Debug.Flag_Dump_Code then + Disp_Subprg_Body (1, Cur_Subprg.E_Entry); + end if; + if not Ortho_Code.Debug.Flag_Debug_Dump then + Abi.Finish_Body (Cur_Subprg); + end if; + end if; + + -- Restore Cur_Subprg. + Cur_Subprg := Parent; + + -- Restore Last_Stmt. + if Cur_Subprg = null then + Last_Stmt := O_Enode_Null; + else + Last_Stmt := Cur_Subprg.Last_Stmt; + end if; + end Finish_Subprogram_Body; + + function Get_Inner_Alloca (Label : O_Enode) return O_Enode + is + Res : O_Enode := O_Enode_Null; + Blk : O_Enode; + Last_Blk : O_Enode := Get_Label_Block (Label); + begin + Blk := Cur_Block; + while Blk /= Last_Blk loop + if Get_Block_Has_Alloca (Blk) then + Res := Blk; + end if; + Blk := Get_Block_Parent (Blk); + end loop; + return Res; + end Get_Inner_Alloca; + + procedure Emit_Jmp (Code : OE_Kind; Expr : O_Enode; Label : O_Enode) + is + begin + -- Discard jump after jump. + if Code /= OE_Jump or else Get_Expr_Kind (Last_Stmt) /= OE_Jump then + New_Enode_Stmt (Code, Expr, Label); + end if; + end Emit_Jmp; + + + -- If there is stack allocated memory to be freed, free it. + -- Then jump to LABEL. + procedure New_Allocb_Jump (Label : O_Enode) + is + Inner_Alloca : O_Enode; + begin + Inner_Alloca := Get_Inner_Alloca (Label); + if Inner_Alloca /= O_Enode_Null then + New_Stack_Restore (Inner_Alloca); + end if; + Emit_Jmp (OE_Jump, O_Enode_Null, Label); + end New_Allocb_Jump; + + function New_Lit (Lit : O_Cnode) return O_Enode + is + L_Type : O_Tnode; + H, L : Uns32; + begin + L_Type := Get_Const_Type (Lit); + if Flag_Debug_Hli then + return New_Enode (OE_Lit, L_Type, O_Enode (Lit), O_Enode_Null); + else + case Get_Const_Kind (Lit) is + when OC_Signed + | OC_Unsigned + | OC_Float + | OC_Null + | OC_Lit => + Get_Const_Bytes (Lit, H, L); + return New_Enode + (OE_Const, L_Type, + O_Enode (To_Int32 (L)), O_Enode (To_Int32 (H))); + when OC_Address + | OC_Subprg_Address => + return New_Enode (OE_Addrg, L_Type, + O_Enode (Get_Const_Decl (Lit)), O_Enode_Null); + when OC_Array + | OC_Record + | OC_Sizeof => + raise Syntax_Error; + end case; + end if; + end New_Lit; + + function Get_Static_Chain (Depth : O_Depth) return O_Enode + is + Cur_Depth : O_Depth := Cur_Subprg.Depth; + Subprg : Subprogram_Data_Acc; + Res : O_Enode; + begin + if Depth = Cur_Depth then + return New_Enode (OE_Get_Frame, Abi.Mode_Ptr, O_Tnode_Ptr, + O_Enode_Null, O_Enode_Null); + else + Subprg := Cur_Subprg; + Res := O_Enode_Null; + loop + Res := New_Enode (OE_Addrl, Abi.Mode_Ptr, O_Tnode_Ptr, + O_Enode (Subprg.D_Decl + 1), Res); + Res := New_Enode (OE_Indir, O_Tnode_Ptr, Res, O_Enode_Null); + Cur_Depth := Cur_Depth - 1; + if Cur_Depth = Depth then + return Res; + end if; + Subprg := Subprg.Parent; + end loop; + end if; + end Get_Static_Chain; + + function New_Obj (Obj : O_Dnode) return O_Lnode + is + O_Type : O_Tnode; + Kind : OE_Kind; + Chain : O_Enode; + Depth : O_Depth; + begin + O_Type := Get_Decl_Type (Obj); + case Get_Decl_Kind (Obj) is + when OD_Local + | OD_Interface => + Kind := OE_Addrl; + -- Local declarations are 1 deeper than their subprogram. + Depth := Get_Decl_Depth (Obj) - 1; + if Depth /= Cur_Subprg.Depth then + Chain := Get_Static_Chain (Depth); + else + Chain := O_Enode_Null; + end if; + when OD_Var + | OD_Const => + Kind := OE_Addrg; + Chain := O_Enode_Null; + when others => + raise Program_Error; + end case; + return O_Lnode (New_Enode (Kind, Abi.Mode_Ptr, O_Type, + O_Enode (Obj), Chain)); + end New_Obj; + + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode + is + L_Type : O_Tnode; + begin + L_Type := Get_Enode_Type (Left); + if Flag_Debug_Assert then + if L_Type /= Get_Enode_Type (Right) then + raise Syntax_Error; + end if; + if Get_Type_Mode (L_Type) = Mode_Blk then + raise Syntax_Error; + end if; + Check_Ref (Left); + Check_Ref (Right); + end if; + + return New_Enode (OE_Kind'Val (ON_Op_Kind'Pos (Kind)), + L_Type, Left, Right); + end New_Dyadic_Op; + + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode + is + O_Type : O_Tnode; + begin + O_Type := Get_Enode_Type (Operand); + + if Flag_Debug_Assert then + if Get_Type_Mode (O_Type) = Mode_Blk then + raise Syntax_Error; + end if; + Check_Ref (Operand); + end if; + + return New_Enode (OE_Kind'Val (ON_Op_Kind'Pos (Kind)), O_Type, + Operand, O_Enode_Null); + end New_Monadic_Op; + + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) + return O_Enode + is + Res : O_Enode; + begin + if Flag_Debug_Assert then + if Get_Enode_Type (Left) /= Get_Enode_Type (Right) then + raise Syntax_Error; + end if; + if Get_Expr_Mode (Left) = Mode_Blk then + raise Syntax_Error; + end if; + if Get_Type_Kind (Ntype) /= OT_Boolean then + raise Syntax_Error; + end if; + Check_Ref (Left); + Check_Ref (Right); + end if; + + Res := New_Enode (OE_Kind'Val (ON_Op_Kind'Pos (Kind)), Ntype, + Left, Right); + if Flag_Debug_Hli then + return New_Enode (OE_Typed, Ntype, Res, O_Enode (Ntype)); + else + return Res; + end if; + end New_Compare_Op; + + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Enode is + begin + return New_Const_U32 (Get_Type_Size (Atype), Rtype); + end New_Sizeof; + + function New_Offsetof (Field : O_Fnode; Rtype : O_Tnode) return O_Enode is + begin + return New_Const_U32 (Get_Field_Offset (Field), Rtype); + end New_Offsetof; + + function Is_Pow2 (V : Uns32) return Boolean is + begin + return (V and -V) = V; + end Is_Pow2; + + function Extract_Pow2 (V : Uns32) return Uns32 is + begin + for I in Natural range 0 .. 31 loop + if V = Shift_Left (1, I) then + return Uns32 (I); + end if; + end loop; + raise Program_Error; + end Extract_Pow2; + + function New_Index_Slice_Element + (Arr : O_Lnode; Index : O_Enode; Res_Type : O_Tnode) + return O_Lnode + is + El_Type : O_Tnode; + In_Type : O_Tnode; + Sz : O_Enode; + El_Size : Uns32; + begin + El_Type := Get_Type_Array_Element (Get_Enode_Type (O_Enode (Arr))); + In_Type := Get_Enode_Type (Index); + + if Flag_Debug_Assert then + Check_Ref (Index); + Check_Ref (Arr); + end if; + + -- result := arr + index * sizeof (element). + El_Size := Get_Type_Size (El_Type); + if El_Size = 1 then + Sz := Index; + elsif Get_Expr_Kind (Index) = OE_Const then + -- FIXME: may recycle previous index? + Sz := New_Const_U32 (Get_Expr_Low (Index) * El_Size, In_Type); + else + if Is_Pow2 (El_Size) then + Sz := New_Const_U32 (Extract_Pow2 (El_Size), In_Type); + Sz := New_Enode (OE_Shl, In_Type, Index, Sz); + else + Sz := New_Const_U32 (El_Size, In_Type); + Sz := New_Enode (OE_Mul, In_Type, Index, Sz); + end if; + end if; + return O_Lnode (New_Enode (OE_Add, Abi.Mode_Ptr, Res_Type, + O_Enode (Arr), Sz)); + end New_Index_Slice_Element; + + function New_Hli_Index_Slice + (Kind : OE_Kind; Res_Type : O_Tnode; Arr : O_Lnode; Index : O_Enode) + return O_Lnode + is + begin + if Flag_Debug_Assert then + Check_Ref (Index); + Check_Ref (Arr); + end if; + return O_Lnode (New_Enode (Kind, Res_Type, O_Enode (Arr), Index)); + end New_Hli_Index_Slice; + + -- Get an element of an array. + -- INDEX must be of the type of the array index. + function New_Indexed_Element (Arr : O_Lnode; Index : O_Enode) + return O_Lnode + is + El_Type : O_Tnode; + begin + El_Type := Get_Type_Array_Element (Get_Enode_Type (O_Enode (Arr))); + + if Flag_Debug_Hli then + return New_Hli_Index_Slice (OE_Index_Ref, El_Type, Arr, Index); + else + return New_Index_Slice_Element (Arr, Index, El_Type); + end if; + end New_Indexed_Element; + + -- Get a slice of an array; this is equivalent to a conversion between + -- an array or an array subtype and an array subtype. + -- RES_TYPE must be an array_sub_type whose base type is the same as the + -- base type of ARR. + -- INDEX must be of the type of the array index. + function New_Slice (Arr : O_Lnode; Res_Type : O_Tnode; Index : O_Enode) + return O_Lnode + is + begin + if Flag_Debug_Hli then + return New_Hli_Index_Slice (OE_Slice_Ref, Res_Type, Arr, Index); + else + return New_Index_Slice_Element (Arr, Index, Res_Type); + end if; + end New_Slice; + + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode + is + Offset : Uns32; + Off : O_Enode; + Res_Type : O_Tnode; + begin + if Flag_Debug_Assert then + Check_Ref (Rec); + end if; + + Res_Type := Get_Field_Type (El); + if Flag_Debug_Hli then + return O_Lnode (New_Enode (OE_Record_Ref, Res_Type, + O_Enode (Rec), O_Enode (El))); + else + Offset := Get_Field_Offset (El); + if Offset = 0 then + return O_Lnode (New_Enode (OE_Conv_Ptr, Abi.Mode_Ptr, Res_Type, + O_Enode (Rec), O_Enode (Res_Type))); + else + Off := New_Enode (OE_Const, Mode_U32, O_Tnode_Null, + O_Enode (Offset), O_Enode_Null); + + return O_Lnode (New_Enode (OE_Add, Abi.Mode_Ptr, Res_Type, + O_Enode (Rec), Off)); + end if; + end if; + end New_Selected_Element; + + function New_Access_Element (Acc : O_Enode) return O_Lnode + is + Acc_Type : O_Tnode; + Res_Type : O_Tnode; + begin + Acc_Type := Get_Enode_Type (Acc); + + if Flag_Debug_Assert then + if Get_Type_Kind (Acc_Type) /= OT_Access then + raise Syntax_Error; + end if; + Check_Ref (Acc); + end if; + + Res_Type := Get_Type_Access_Type (Acc_Type); + if Flag_Debug_Hli then + return O_Lnode (New_Enode (OE_Access_Ref, Abi.Mode_Ptr, Res_Type, + Acc, O_Enode_Null)); + else + return O_Lnode (New_Enode (OE_Conv_Ptr, Abi.Mode_Ptr, Res_Type, + Acc, O_Enode (Res_Type))); + end if; + end New_Access_Element; + + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode is + begin + if Flag_Debug_Assert then + Check_Ref (Val); + end if; + + return New_Enode (OE_Conv, Rtype, Val, O_Enode (Rtype)); + end New_Convert_Ov; + + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode is + begin + if Flag_Debug_Assert then + if Get_Type_Kind (Atype) /= OT_Access then + raise Syntax_Error; + end if; + Check_Ref (Lvalue); + end if; + + return New_Enode (OE_Conv_Ptr, Abi.Mode_Ptr, Atype, + O_Enode (Lvalue), O_Enode (Atype)); + end New_Unchecked_Address; + + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode is + begin + if Flag_Debug_Assert then + if Get_Type_Kind (Atype) /= OT_Access then + raise Syntax_Error; + end if; + Check_Ref (Lvalue); + end if; + + return New_Enode (OE_Conv_Ptr, Abi.Mode_Ptr, Atype, + O_Enode (Lvalue), O_Enode (Atype)); + end New_Address; + + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Enode is + begin + raise Program_Error; + return O_Enode_Null; + end New_Subprogram_Address; + + function New_Value (Lvalue : O_Lnode) return O_Enode + is + V_Type : O_Tnode; + begin + V_Type := Get_Enode_Type (O_Enode (Lvalue)); + + if Flag_Debug_Assert then + Check_Ref (Lvalue); + end if; + + return New_Enode (OE_Indir, V_Type, O_Enode (Lvalue), O_Enode_Null); + end New_Value; + + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode + is + Save_Var : O_Dnode; + Stmt : O_Enode; + begin + if Flag_Debug_Assert then + Check_Ref (Size); + if Get_Type_Kind (Rtype) /= OT_Access then + raise Syntax_Error; + end if; + if Get_Type_Kind (Get_Enode_Type (Size)) /= OT_Unsigned then + raise Syntax_Error; + end if; + end if; + + if not Get_Block_Has_Alloca (Cur_Block) then + Set_Block_Has_Alloca (Cur_Block, True); + -- Add a decl. + New_Var_Decl (Save_Var, O_Ident_Nul, O_Storage_Local, Rtype); + -- Add insn to save stack ptr. + Stmt := New_Enode (OE_Asgn, Rtype, + New_Stack (Rtype), + O_Enode (New_Obj (Save_Var))); + if Cur_Block = Last_Stmt then + Set_Stmt_Link (Last_Stmt, Stmt); + Last_Stmt := Stmt; + else + Set_Stmt_Link (Stmt, Get_Stmt_Link (Cur_Block)); + Set_Stmt_Link (Cur_Block, Stmt); + end if; + end if; + + return New_Enode (OE_Alloca, Rtype, Size, O_Enode (Rtype)); + end New_Alloca; + + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode) + is + Depth : O_Depth; + Arg : O_Enode; + First_Inter : O_Dnode; + begin + First_Inter := Get_Subprg_Interfaces (Subprg); + if Get_Decl_Storage (Subprg) = O_Storage_Local then + Depth := Get_Decl_Depth (Subprg); + Arg := New_Enode (OE_Arg, Abi.Mode_Ptr, O_Tnode_Ptr, + Get_Static_Chain (Depth - 1), O_Enode_Null); + First_Inter := Get_Interface_Chain (First_Inter); + else + Arg := O_Enode_Null; + end if; + Assocs := (Subprg => Subprg, + First_Arg => Arg, + Last_Arg => Arg, + Next_Inter => First_Inter); + end Start_Association; + + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode) + is + V_Type : O_Tnode; + Mode : Mode_Type; + N_Mode : Mode_Type; + Res : O_Enode; + begin + V_Type := Get_Enode_Type (Val); + + if Flag_Debug_Assert then + if Assocs.Next_Inter = O_Dnode_Null then + -- More assocs than interfaces. + raise Syntax_Error; + end if; + Check_Value_Type (Val, Get_Decl_Type (Assocs.Next_Inter)); + Check_Ref (Val); + end if; + + -- Follow the C convention call: no parameters shorter than int. + Mode := Get_Type_Mode (V_Type); + case Mode is + when Mode_B2 + | Mode_U8 + | Mode_U16 => + N_Mode := Mode_U32; + when Mode_I8 + | Mode_I16 => + N_Mode := Mode_I32; + when Mode_P32 + | Mode_U32 + | Mode_I32 + | Mode_U64 + | Mode_I64 + | Mode_P64 + | Mode_F32 + | Mode_F64 => + N_Mode := Mode; + when Mode_Blk + | Mode_Nil + | Mode_X1 => + raise Program_Error; + end case; + if N_Mode /= Mode and not Flag_Debug_Hli then + Res := New_Enode (OE_Conv, N_Mode, V_Type, Val, O_Enode (V_Type)); + else + Res := Val; + end if; + Res := New_Enode (OE_Arg, N_Mode, V_Type, Res, O_Enode_Null); + if Assocs.Last_Arg /= O_Enode_Null then + Enodes.Table (Assocs.Last_Arg).Arg2 := Res; + else + Assocs.First_Arg := Res; + end if; + Assocs.Last_Arg := Res; + Assocs.Next_Inter := Get_Interface_Chain (Assocs.Next_Inter); + end New_Association; + + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode + is + F_Type : O_Tnode; + begin + if Flag_Debug_Assert then + if Assocs.Next_Inter /= O_Dnode_Null then + -- Not enough assocs. + raise Syntax_Error; + end if; + end if; + + F_Type := Get_Decl_Type (Assocs.Subprg); + return New_Enode (OE_Call, F_Type, + O_Enode (Assocs.Subprg), Assocs.First_Arg); + end New_Function_Call; + + procedure New_Procedure_Call (Assocs : in out O_Assoc_List) is + begin + if Flag_Debug_Assert then + if Assocs.Next_Inter /= O_Dnode_Null then + -- Not enough assocs. + raise Syntax_Error; + end if; + end if; + New_Enode_Stmt (OE_Call, O_Enode (Assocs.Subprg), Assocs.First_Arg); + end New_Procedure_Call; + + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode) + is + V_Type : O_Tnode; + begin + V_Type := Get_Enode_Type (Value); + + if Flag_Debug_Assert then + Check_Value_Type (Value, Get_Enode_Type (O_Enode (Target))); + Check_Ref (Value); + Check_Ref (Target); + end if; + + New_Enode_Stmt (OE_Asgn, Get_Type_Mode (V_Type), + Value, O_Enode (Target)); + end New_Assign_Stmt; + + procedure New_Return_Stmt (Value : O_Enode) + is + V_Type : O_Tnode; + begin + V_Type := Get_Enode_Type (Value); + + if Flag_Debug_Assert then + Check_Ref (Value); + Check_Value_Type (Value, Get_Decl_Type (Cur_Subprg.D_Decl)); + end if; + + New_Enode_Stmt (OE_Ret, Get_Type_Mode (V_Type), Value, O_Enode_Null); + if not Flag_Debug_Hli then + New_Allocb_Jump (Cur_Subprg.Exit_Label); + end if; + end New_Return_Stmt; + + procedure New_Return_Stmt is + begin + if Flag_Debug_Assert then + if Get_Decl_Kind (Cur_Subprg.D_Decl) /= OD_Procedure then + raise Syntax_Error; + end if; + end if; + + if not Flag_Debug_Hli then + New_Allocb_Jump (Cur_Subprg.Exit_Label); + else + New_Enode_Stmt (OE_Ret, Mode_Nil, O_Enode_Null, O_Enode_Null); + end if; + end New_Return_Stmt; + + + procedure Start_If_Stmt (Block : out O_If_Block; Cond : O_Enode) is + begin + if Flag_Debug_Assert then + if Get_Expr_Mode (Cond) /= Mode_B2 then + -- COND must be a boolean. + raise Syntax_Error; + end if; + Check_Ref (Cond); + end if; + + if Flag_Debug_Hli then + New_Enode_Stmt (OE_If, Cond, O_Enode_Null); + Block := (Label_End => O_Enode_Null, + Label_Next => Last_Stmt); + else + Block := (Label_End => O_Enode_Null, + Label_Next => New_Label); + Emit_Jmp (OE_Jump_F, Cond, Block.Label_Next); + Start_BB; + end if; + end Start_If_Stmt; + + procedure New_Elsif_Stmt (Block : in out O_If_Block; Cond : O_Enode) is + begin + if Flag_Debug_Assert then + if Get_Expr_Mode (Cond) /= Mode_B2 then + -- COND must be a boolean. + raise Syntax_Error; + end if; + Check_Ref (Cond); + end if; + + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Elsif, Cond, O_Enode_Null); + Block.Label_Next := Last_Stmt; + else + if Block.Label_End = O_Enode_Null then + Block.Label_End := New_Label; + end if; + Emit_Jmp (OE_Jump, O_Enode_Null, Block.Label_End); + Start_BB; + Link_Stmt (Block.Label_Next); + Block.Label_Next := New_Label; + Emit_Jmp (OE_Jump_F, Cond, Block.Label_Next); + Start_BB; + end if; + end New_Elsif_Stmt; + + procedure New_Else_Stmt (Block : in out O_If_Block) is + begin + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Elsif, O_Enode_Null, O_Enode_Null); + else + if Block.Label_End = O_Enode_Null then + Block.Label_End := New_Label; + end if; + Emit_Jmp (OE_Jump, O_Enode_Null, Block.Label_End); + Start_BB; + Link_Stmt (Block.Label_Next); + Block.Label_Next := O_Enode_Null; + end if; + end New_Else_Stmt; + + procedure Finish_If_Stmt (Block : in out O_If_Block) is + begin + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Endif, O_Enode_Null, O_Enode_Null); + else + -- Create a badic-block after the IF. + Start_BB; + if Block.Label_Next /= O_Enode_Null then + Link_Stmt (Block.Label_Next); + end if; + if Block.Label_End /= O_Enode_Null then + Link_Stmt (Block.Label_End); + end if; + end if; + end Finish_If_Stmt; + + procedure Start_Loop_Stmt (Label : out O_Snode) is + begin + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Loop, O_Enode_Null, O_Enode_Null); + Label := (Label_Start => Last_Stmt, + Label_End => O_Enode_Null); + else + -- Create a basic-block at the beginning of the loop. + Start_BB; + Label.Label_Start := New_Label; + Link_Stmt (Label.Label_Start); + Label.Label_End := New_Label; + end if; + end Start_Loop_Stmt; + + procedure Finish_Loop_Stmt (Label : in out O_Snode) + is + begin + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Eloop, Label.Label_Start, O_Enode_Null); + else + Emit_Jmp (OE_Jump, O_Enode_Null, Label.Label_Start); + Start_BB; + Link_Stmt (Label.Label_End); + end if; + end Finish_Loop_Stmt; + + + procedure New_Exit_Stmt (L : O_Snode) + is + begin + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Exit, O_Enode_Null, L.Label_Start); + else + New_Allocb_Jump (L.Label_End); + end if; + end New_Exit_Stmt; + + procedure New_Next_Stmt (L : O_Snode) + is + begin + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Next, O_Enode_Null, L.Label_Start); + else + New_Allocb_Jump (L.Label_Start); + end if; + end New_Next_Stmt; + + procedure Start_Case_Stmt (Block : out O_Case_Block; Value : O_Enode) + is + V_Type : O_Tnode; + Mode : Mode_Type; + Start : O_Enode; + begin + V_Type := Get_Enode_Type (Value); + Mode := Get_Type_Mode (V_Type); + + if Flag_Debug_Assert then + Check_Ref (Value); + case Mode is + when Mode_U8 .. Mode_U64 + | Mode_I8 .. Mode_I64 + | Mode_B2 => + null; + when others => + raise Syntax_Error; + end case; + end if; + + New_Enode_Stmt (OE_Case, Mode, Value, O_Enode_Null); + Start := Enodes.Last; + if Flag_Debug_Hli then + Block := (Expr => Start, + Expr_Type => V_Type, + Last_Node => O_Enode_Null, + Label_End => O_Enode_Null, + Label_Branch => Start); + else + Block := (Expr => Start, + Expr_Type => V_Type, + Last_Node => Start, + Label_End => New_Label, + Label_Branch => O_Enode_Null); + end if; + end Start_Case_Stmt; + + procedure Start_Choice (Block : in out O_Case_Block) + is + B : O_Enode; + begin + if Flag_Debug_Hli then + B := New_Enode (OE_Case_Branch, Mode_Nil, O_Tnode_Null, + O_Enode_Null, O_Enode_Null); + Link_Stmt (B); + -- Link it. + Set_Case_Branch (Block.Label_Branch, B); + Block.Label_Branch := B; + else + -- Jump to the end of the case statement. + -- If there is already a branch open, this is ok + -- (do not fall-through). + -- If there is no branch open, then this is the default choice + -- (nothing to do). + Emit_Jmp (OE_Jump, O_Enode_Null, Block.Label_End); + + -- Create a label for the code of this branch. + Block.Label_Branch := New_Label; + end if; + end Start_Choice; + + procedure Insert_Choice_Stmt (Block : in out O_Case_Block; Stmt : O_Enode) + is + Prev : O_Enode; + begin + Prev := Get_Stmt_Link (Block.Last_Node); + Set_Stmt_Link (Block.Last_Node, Stmt); + Block.Last_Node := Stmt; + if Prev = O_Enode_Null then + Last_Stmt := Stmt; + else + Set_Stmt_Link (Stmt, Prev); + end if; + end Insert_Choice_Stmt; + + procedure Emit_Choice_Jmp (Block : in out O_Case_Block; + Code : OE_Kind; Expr : O_Enode; Label : O_Enode) + is + Jmp : O_Enode; + begin + Jmp := New_Enode (Code, Mode_Nil, O_Tnode_Null, Expr, Label); + Insert_Choice_Stmt (Block, Jmp); + end Emit_Choice_Jmp; + + -- Create a node containing the value of the case expression. + function New_Case_Expr (Block : O_Case_Block) return O_Enode is + begin + return New_Enode (OE_Case_Expr, Block.Expr_Type, + Block.Expr, O_Enode_Null); + end New_Case_Expr; + + procedure New_Hli_Choice (Block : in out O_Case_Block; + Hi, Lo : O_Enode) + is + Res : O_Enode; + begin + Res := New_Enode (OE_Case_Choice, Mode_Nil, O_Tnode_Null, Hi, Lo); + if Block.Label_End = O_Enode_Null then + Set_Case_Branch_Choice (Block.Label_Branch, Res); + else + Set_Case_Choice_Link (Block.Label_End, Res); + end if; + Block.Label_End := Res; + end New_Hli_Choice; + + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode) + is + Res : O_Enode; + begin + if Flag_Debug_Hli then + New_Hli_Choice (Block, New_Lit (Expr), O_Enode_Null); + else + Res := New_Enode (OE_Eq, Mode_B2, O_Tnode_Null, + New_Case_Expr (Block), New_Lit (Expr)); + Emit_Choice_Jmp (Block, OE_Jump_T, Res, Block.Label_Branch); + end if; + end New_Expr_Choice; + + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode) + is + E1 : O_Enode; + E2 : O_Enode; + Label : O_Enode; + begin + if Flag_Debug_Hli then + New_Hli_Choice (Block, New_Lit (Low), New_Lit (High)); + else + -- Internal label. + Label := New_Label; + E1 := New_Enode (OE_Lt, Mode_B2, O_Tnode_Null, + New_Case_Expr (Block), New_Lit (Low)); + Emit_Choice_Jmp (Block, OE_Jump_T, E1, Label); + E2 := New_Enode (OE_Le, Mode_B2, O_Tnode_Null, + New_Case_Expr (Block), New_Lit (High)); + Emit_Choice_Jmp (Block, OE_Jump_T, E2, Block.Label_Branch); + Insert_Choice_Stmt (Block, Label); + end if; + end New_Range_Choice; + + procedure New_Default_Choice (Block : in out O_Case_Block) is + begin + if Flag_Debug_Hli then + New_Hli_Choice (Block, O_Enode_Null, O_Enode_Null); + else + -- Jump to the code. + Emit_Choice_Jmp (Block, OE_Jump, O_Enode_Null, Block.Label_Branch); + end if; + end New_Default_Choice; + + procedure Finish_Choice (Block : in out O_Case_Block) is + begin + if Flag_Debug_Hli then + Block.Label_End := O_Enode_Null; + else + -- Put the label of the branch. + Start_BB; + Link_Stmt (Block.Label_Branch); + end if; + end Finish_Choice; + + procedure Finish_Case_Stmt (Block : in out O_Case_Block) is + begin + if Flag_Debug_Hli then + New_Enode_Stmt (OE_Case_End, O_Enode_Null, O_Enode_Null); + else + -- Jump to the end of the case statement. + -- Note: this is not required, since the next instruction is the + -- label. + -- Emit_Jmp (OE_Jump, O_Enode_Null, Block.Label_End); + + -- Put the label of the end of the case. + Start_BB; + Link_Stmt (Block.Label_End); + Block.Label_End := O_Enode_Null; + end if; + end Finish_Case_Stmt; + + procedure New_Debug_Line_Stmt (Line : Natural) is + begin + New_Enode_Stmt (OE_Line, O_Enode (Line), O_Enode_Null); + end New_Debug_Line_Stmt; + + procedure Disp_Enode (Indent : Natural; N : O_Enode) + is + use Ada.Text_IO; + use Ortho_Code.Debug; + use Ortho_Code.Debug.Int32_IO; + begin + Set_Col (Count (Indent)); + Put (Int32 (N), 0); + Set_Col (Count (Indent + 7)); + Disp_Mode (Get_Expr_Mode (N)); + Put (" "); + Put (OE_Kind'Image (Get_Expr_Kind (N))); + Set_Col (Count (Indent + 25)); +-- Put (Abi.Image_Insn (Get_Expr_Insn (N))); +-- Put (" "); + Put (Abi.Image_Reg (Get_Expr_Reg (N))); + Put (" "); + Put (Int32 (Enodes.Table (N).Arg1), 7); + Put (Int32 (Enodes.Table (N).Arg2), 7); + Put (Enodes.Table (N).Info, 7); + New_Line; + end Disp_Enode; + + procedure Disp_Subprg_Body (Indent : Natural; Subprg : O_Enode) + is + N : O_Enode; + N_Indent : Natural; + begin + N := Subprg; + if Get_Expr_Kind (N) /= OE_Entry then + raise Program_Error; + end if; + -- Display the entry. + Disp_Enode (Indent, N); + -- Display the subprogram, binding. + N_Indent := Indent;-- + 1; + N := N + 1; + loop + case Get_Expr_Kind (N) is + when OE_Entry => + N := Get_Entry_Leave (N) + 1; + when OE_Leave => + Disp_Enode (Indent, N); + exit; + when others => + Disp_Enode (N_Indent, N); + case Get_Expr_Kind (N) is + when OE_Beg => + Disp_Block (N_Indent + 2, + O_Dnode (Enodes.Table (N).Arg2)); + N_Indent := N_Indent + 1; + when OE_End => + N_Indent := N_Indent - 1; + when others => + null; + end case; + N := N + 1; + end case; + end loop; + end Disp_Subprg_Body; + + procedure Disp_All_Enode is + begin + for I in Enodes.First .. Enodes.Last loop + Disp_Enode (1, I); + end loop; + end Disp_All_Enode; + + Max_Enode : O_Enode := O_Enode_Null; + + procedure Mark (M : out Mark_Type) is + begin + M.Enode := Enodes.Last; + end Mark; + + procedure Release (M : Mark_Type) is + begin + Max_Enode := O_Enode'Max (Max_Enode, Enodes.Last); + Enodes.Set_Last (M.Enode); + end Release; + + procedure Disp_Stats + is + use Ada.Text_IO; + begin + Max_Enode := O_Enode'Max (Max_Enode, Enodes.Last); + Put ("Number of Enodes:" & O_Enode'Image (Enodes.Last)); + Put (", max:" & O_Enode'Image (Max_Enode)); + New_Line; + end Disp_Stats; + + procedure Free_Subprogram_Data (Data : in out Subprogram_Data_Acc) + is + procedure Free is new Ada.Unchecked_Deallocation + (Subprogram_Data, Subprogram_Data_Acc); + Ch, N_Ch : Subprogram_Data_Acc; + begin + Ch := Data.First_Child; + while Ch /= null loop + N_Ch := Ch.Brother; + Free_Subprogram_Data (Ch); + Ch := N_Ch; + end loop; + Free (Data); + end Free_Subprogram_Data; + + procedure Finish is + begin + Enodes.Free; + Free_Subprogram_Data (First_Subprg); + end Finish; +end Ortho_Code.Exprs; |