diff options
Diffstat (limited to 'src/ortho')
129 files changed, 42281 insertions, 0 deletions
diff --git a/src/ortho/Makefile.inc b/src/ortho/Makefile.inc new file mode 100644 index 000000000..597aaeff1 --- /dev/null +++ b/src/ortho/Makefile.inc @@ -0,0 +1,38 @@ +# Common -*- Makefile -*- for ortho implementations. +# Copyright (C) 2002, 2003, 2004, 2005 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. + +# Variable to be defined: +# SED: sed the stream editor +# ORTHO_BASENAME + +$(ortho_srcdir)/$(BE)/$(ORTHO_BASENAME).ads: \ + $(ortho_srcdir)/ortho_nodes.common.ads \ + $(ortho_srcdir)/$(BE)/$(ORTHO_BASENAME).private.ads + $(RM) -f $@ + echo "-- DO NOT MODIFY - this file was generated from:" > $@ + echo "-- ortho_nodes.common.ads and $(ORTHO_BASENAME).private.ads" \ + >> $@ + echo "--" >> $@ + $(SED) -e '/^private/,$$d' \ + < $(ortho_srcdir)/$(BE)/$(ORTHO_BASENAME).private.ads >> $@ + echo "-- Start of common part" >> $@ + $(SED) -e '1,/^package/d' -e '/^private/,$$d' < $< >> $@ + echo "-- End of common part" >> $@ + $(SED) -n -e '/^private/,$$p' \ + < $(ortho_srcdir)/$(BE)/$(ORTHO_BASENAME).private.ads >> $@ + chmod a-w $@ diff --git a/src/ortho/debug/Makefile b/src/ortho/debug/Makefile new file mode 100644 index 000000000..0c15111ef --- /dev/null +++ b/src/ortho/debug/Makefile @@ -0,0 +1,47 @@ +# -*- Makefile -*- for the ortho-code back-end +# Copyright (C) 2005 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. +BE=debug +ortho_srcdir=.. + +orthobe_srcdir=$(ortho_srcdir)/$(BE) + +GNATMAKE=gnatmake +CC=gcc +CFLAGS=-g +ALL_GNAT_FLAGS=-pipe -g -gnato -gnatwl -gnatf -gnaty3befhkmr -gnatwu +GNATMAKE_FLAGS=-m $(ALL_GNAT_FLAGS) $(GNAT_FLAGS) -aI$(ortho_srcdir) -aI$(orthobe_srcdir) -aI. +#LARGS=-largs -static +SED=sed + +all: $(ortho_exec) + + +$(ortho_exec): force $(ortho_srcdir)/$(BE)/ortho_debug.ads + gnatmake -o $@ $(GNATMAKE_FLAGS) ortho_debug-main -bargs -E $(LARGS) + +clean: + $(RM) -f *.o *.ali *~ b~*.ad? ortho_nodes-main + $(RM) ortho_debug.ads + +force: + +ORTHO_BASENAME=ortho_debug + +# Automatically build ortho_debug.ads from ortho_node.common.ads and +# ortho_debug.private.ads +include $(ortho_srcdir)/Makefile.inc diff --git a/src/ortho/debug/ortho_debug-disp.adb b/src/ortho/debug/ortho_debug-disp.adb new file mode 100644 index 000000000..2725668bb --- /dev/null +++ b/src/ortho/debug/ortho_debug-disp.adb @@ -0,0 +1,1064 @@ +-- Display the code from the ortho debug tree. +-- Copyright (C) 2005 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. + +package body Ortho_Debug.Disp is + Disp_All_Types : constant Boolean := False; + + package Formated_Output is + use Interfaces.C_Streams; + + type Disp_Context is limited private; + + procedure Init_Context (File : FILEs); + + -- Save the current context, and create a new one. + procedure Push_Context (File : FILEs; Prev_Ctx : out Disp_Context); + + -- Restore a previous context, saved by Push_Context. + procedure Pop_Context (Prev_Ctx : Disp_Context); + + procedure Put (Str : String); + + procedure Put_Line (Str : String); + + -- Add a tabulation. + -- Every new line will start at this tabulation. + procedure Add_Tab; + + -- Removed a tabulation. + -- The next new line will start at the previous tabulation. + procedure Rem_Tab; + + -- Flush the current output. + procedure Flush; + + -- Return TRUE if the ident level is nul. + function Is_Top return Boolean; + + procedure Put_Tab; + + procedure New_Line; + + procedure Put (C : Character); + + procedure Put_Trim (Str : String); + + procedure Set_Mark; + + -- Flush to disk. Only for debugging in case of crash. + procedure Flush_File; + pragma Unreferenced (Flush_File); + private + type Disp_Context is record + -- File where the info are written to. + File : FILEs; + -- Line number of the line to be written. + Lineno : Natural; + -- Buffer for the current line. + Line : String (1 .. 256); + -- Number of characters currently in the line. + Line_Len : Natural; + + -- Current tabulation. + Tab : Natural; + -- Tabulation to be used for the next line. + Next_Tab : Natural; + + Mark : Natural; + end record; + end Formated_Output; + + package body Formated_Output is + -- The current context. + Ctx : Disp_Context; + + procedure Init_Context (File : FILEs) is + begin + Ctx.File := File; + Ctx.Lineno := 1; + Ctx.Line_Len := 0; + Ctx.Tab := 0; + Ctx.Next_Tab := 0; + Ctx.Mark := 0; + end Init_Context; + + procedure Push_Context (File : FILEs; Prev_Ctx : out Disp_Context) + is + begin + Prev_Ctx := Ctx; + Init_Context (File); + end Push_Context; + + -- Restore a previous context, saved by Push_Context. + procedure Pop_Context (Prev_Ctx : Disp_Context) is + begin + Flush; + Ctx := Prev_Ctx; + end Pop_Context; + + procedure Flush + is + Status : size_t; + Res : int; + pragma Unreferenced (Status, Res); + begin + if Ctx.Line_Len > 0 then + Status := fwrite (Ctx.Line'Address, size_t (Ctx.Line_Len), 1, + Ctx.File); + Res := fputc (Character'Pos (ASCII.Lf), Ctx.File); + Ctx.Line_Len := 0; + end if; + Ctx.Mark := 0; + end Flush; + + function Is_Top return Boolean is + begin + return Ctx.Tab = 0; + end Is_Top; + + procedure Put_Tab + is + Tab : Natural := Ctx.Next_Tab; + Max_Tab : constant Natural := 40; + begin + if Tab > Max_Tab then + -- Limit indentation length, to limit line length. + Tab := Max_Tab; + end if; + + Ctx.Line (1 .. Tab) := (others => ' '); + Ctx.Line_Len := Tab; + Ctx.Next_Tab := Ctx.Tab + 2; + end Put_Tab; + + procedure Put (Str : String) is + Saved : String (1 .. 80); + Len : Natural; + begin + if Ctx.Line_Len + Str'Length >= 80 then + if Ctx.Mark > 0 then + Len := Ctx.Line_Len - Ctx.Mark + 1; + Saved (1 .. Len) := Ctx.Line (Ctx.Mark .. Ctx.Line_Len); + Ctx.Line_Len := Ctx.Mark - 1; + Flush; + Put_Tab; + Ctx.Line (Ctx.Line_Len + 1 .. Ctx.Line_Len + Len) := + Saved (1 .. Len); + Ctx.Line_Len := Ctx.Line_Len + Len; + else + Flush; + end if; + end if; + if Ctx.Line_Len = 0 then + Put_Tab; + end if; + Ctx.Line (Ctx.Line_Len + 1 .. Ctx.Line_Len + Str'Length) := Str; + Ctx.Line_Len := Ctx.Line_Len + Str'Length; + end Put; + + procedure Put_Trim (Str : String) is + begin + for I in Str'Range loop + if Str (I) /= ' ' then + Put (Str (I .. Str'Last)); + return; + end if; + end loop; + end Put_Trim; + + procedure Put_Line (Str : String) is + begin + Put (Str); + Flush; + Ctx.Next_Tab := Ctx.Tab; + end Put_Line; + + procedure New_Line + is + Status : int; + pragma Unreferenced (Status); + begin + if Ctx.Line_Len > 0 then + Flush; + else + Status := fputc (Character'Pos (ASCII.LF), Ctx.File); + end if; + Ctx.Next_Tab := Ctx.Tab; + end New_Line; + + procedure Put (C : Character) + is + S : constant String (1 .. 1) := (1 => C); + begin + Put (S); + end Put; + + -- Add a tabulation. + -- Every new line will start at this tabulation. + procedure Add_Tab is + begin + Ctx.Tab := Ctx.Tab + 2; + Ctx.Next_Tab := Ctx.Tab; + end Add_Tab; + + -- Removed a tabulation. + -- The next new line will start at the previous tabulation. + procedure Rem_Tab is + begin + Ctx.Tab := Ctx.Tab - 2; + Ctx.Next_Tab := Ctx.Tab; + end Rem_Tab; + + procedure Set_Mark is + begin + Ctx.Mark := Ctx.Line_Len; + end Set_Mark; + + procedure Flush_File is + Status : int; + pragma Unreferenced (Status); + begin + Flush; + Status := fflush (Ctx.File); + end Flush_File; + end Formated_Output; + + use Formated_Output; + + procedure Init_Context (File : Interfaces.C_Streams.FILEs) is + begin + Formated_Output.Init_Context (File); + end Init_Context; + + procedure Disp_Enode (E : O_Enode; Etype : O_Tnode); + procedure Disp_Lnode (Node : O_Lnode); + procedure Disp_Snode (First, Last : O_Snode); + procedure Disp_Dnode (Decl : O_Dnode); + procedure Disp_Tnode (Atype : O_Tnode; Full : Boolean); + + procedure Disp_Ident (Id : O_Ident) is + begin + Put (Get_String (Id)); + end Disp_Ident; + + procedure Disp_Tnode_Name (Atype : O_Tnode) is + begin + Disp_Tnode (Atype, False); + end Disp_Tnode_Name; + + procedure Disp_Dnode_Name (Decl : O_Dnode) is + begin + Disp_Ident (Decl.Name); + end Disp_Dnode_Name; + + procedure Disp_Loop_Name (Stmt : O_Snode) is + begin + Put ("loop" & Natural'Image (Stmt.Loop_Level)); + end Disp_Loop_Name; + + function Get_Enode_Name (Kind : OE_Kind) return String + is + begin + case Kind is +-- when OE_Boolean_Lit => +-- return "boolean_lit"; +-- when OE_Unsigned_Lit => +-- return "unsigned_lit"; +-- when OE_Signed_Lit => +-- return "signed lit"; +-- when OE_Float_Lit => +-- return "float lit"; +-- when OE_Null_Lit => +-- return "null lit"; +-- when OE_Enum_Lit => +-- return "enum lit"; + +-- when OE_Sizeof_Lit => +-- return "sizeof lit"; +-- when OE_Offsetof_Lit => +-- return "offsetof lit"; +-- when OE_Aggregate => +-- return "aggregate"; +-- when OE_Aggr_Element => +-- return "aggr_element"; +-- when OE_Union_Aggr => +-- return "union aggr"; + + when OE_Lit => + return "lit"; + when OE_Add_Ov => + return "+#"; + when OE_Sub_Ov => + return "-#"; + when OE_Mul_Ov => + return "*#"; + when OE_Div_Ov => + return "/#"; + when OE_Rem_Ov => + return "rem#"; + when OE_Mod_Ov => + return "mod#"; + when OE_Exp_Ov => + return "**#"; + + when OE_And => + return "and"; + when OE_Or => + return "or"; + when OE_Xor => + return "xor"; + when OE_And_Then => + return "and_then"; + when OE_Or_Else => + return "or_else"; + + when OE_Not => + return "not"; + when OE_Neg_Ov => + return "-"; + when OE_Abs_Ov => + return "abs"; + + when OE_Eq => + return "="; + when OE_Neq => + return "/="; + when OE_Le => + return "<="; + when OE_Lt => + return "<"; + when OE_Ge => + return ">="; + when OE_Gt => + return ">"; + + when OE_Function_Call => + return "function call"; + when OE_Convert_Ov => + return "convert_ov"; + when OE_Address => + return "address"; + when OE_Unchecked_Address => + return "unchecked_address"; +-- when OE_Subprogram_Address => +-- return "subprg_address"; + when OE_Alloca => + return "alloca"; + when OE_Value => + return "value"; + when OE_Nil => + return "??"; + end case; + end Get_Enode_Name; + + function Get_Lnode_Name (Kind : OL_Kind) return String + is + begin + case Kind is + when OL_Obj => + return "obj"; + when OL_Indexed_Element => + return "indexed_element"; + when OL_Slice => + return "slice"; + when OL_Selected_Element => + return "selected_element"; + when OL_Access_Element => + return "access_element"; +-- when OL_Param_Ref => +-- return "param_ref"; +-- when OL_Var_Ref => +-- return "var_ref"; +-- when OL_Const_Ref => +-- return "const_ref"; + end case; + end Get_Lnode_Name; + + pragma Unreferenced (Get_Lnode_Name); + + procedure Disp_Enode_Name (Kind : OE_Kind) is + begin + Put (Get_Enode_Name (Kind)); + end Disp_Enode_Name; + + procedure Disp_Assoc_List (Head : O_Anode) + is + El : O_Anode; + begin + El := Head; + Put ("("); + if El /= null then + loop + Disp_Enode (El.Actual, El.Formal.Dtype); + El := El.Next; + exit when El = null; + Put (", "); + end loop; + end if; + Put (")"); + end Disp_Assoc_List; + + function Image (Lit : Integer) return String + is + S : constant String := Integer'Image (Lit); + begin + if S (1) = ' ' then + return S (2 .. S'Length); + else + return S; + end if; + end Image; + + -- Disp STR as a literal for scalar type LIT_TYPE. + procedure Disp_Lit (Lit_Type : O_Tnode; Known : Boolean; Str : String) is + begin + if Known and not Disp_All_Types then + Put_Trim (Str); + else + Disp_Tnode_Name (Lit_Type); + Put ("'["); + Put_Trim (Str); + Put (']'); + end if; + end Disp_Lit; + + -- Display C. If CTYPE is set, this is the known type of C. + procedure Disp_Cnode (C : O_Cnode; Ctype : O_Tnode) + is + Known : constant Boolean := Ctype /= O_Tnode_Null; + begin + -- Sanity check. + if Known then + if Ctype /= C.Ctype then + raise Program_Error; + end if; + end if; + + case C.Kind is + when OC_Unsigned_Lit => + if False and then (C.U_Val >= Character'Pos(' ') + and C.U_Val <= Character'Pos ('~')) + then + Put ('''); + Put (Character'Val (C.U_Val)); + Put ('''); + else + Disp_Lit (C.Ctype, Known, Unsigned_64'Image (C.U_Val)); + end if; + when OC_Signed_Lit => + Disp_Lit (C.Ctype, Known, Integer_64'Image (C.S_Val)); + when OC_Float_Lit => + Disp_Lit (C.Ctype, Known, IEEE_Float_64'Image (C.F_Val)); + when OC_Boolean_Lit => + -- Always disp the type of boolean literals. + Disp_Lit (C.Ctype, False, Get_String (C.B_Id)); + when OC_Null_Lit => + -- Always disp the type of null literals. + Disp_Lit (C.Ctype, False, "null"); + when OC_Enum_Lit => + -- Always disp the type of enum literals. + Disp_Lit (C.Ctype, False, Get_String (C.E_Name)); + when OC_Sizeof_Lit => + Disp_Tnode_Name (C.Ctype); + Put ("'sizeof ("); + Disp_Tnode_Name (C.S_Type); + Put (")"); + when OC_Alignof_Lit => + Disp_Tnode_Name (C.Ctype); + Put ("'alignof ("); + Disp_Tnode_Name (C.S_Type); + Put (")"); + when OC_Offsetof_Lit => + Disp_Tnode_Name (C.Ctype); + Put ("'offsetof ("); + Disp_Tnode_Name (C.Off_Field.Parent); + Put ("."); + Disp_Ident (C.Off_Field.Ident); + Put (")"); + when OC_Aggregate => + declare + El : O_Cnode; + El_Type : O_Tnode; + Field : O_Fnode; + begin + Put ('{'); + El := C.Aggr_Els; + case C.Ctype.Kind is + when ON_Record_Type => + Field := C.Ctype.Elements; + El_Type := Field.Ftype; + when ON_Array_Sub_Type => + Field := null; + El_Type := C.Ctype.Base_Type.El_Type; + when others => + raise Program_Error; + end case; + if El /= null then + loop + Set_Mark; + if Field /= null then + if Disp_All_Types then + Put ('.'); + Disp_Ident (Field.Ident); + Put (" = "); + end if; + El_Type := Field.Ftype; + Field := Field.Next; + end if; + Disp_Cnode (El.Aggr_Value, El_Type); + El := El.Aggr_Next; + exit when El = null; + Put (", "); + end loop; + end if; + Put ('}'); + end; + when OC_Aggr_Element => + Disp_Cnode (C.Aggr_Value, Ctype); + when OC_Union_Aggr => + Put ('{'); + Put ('.'); + Disp_Ident (C.Uaggr_Field.Ident); + Put (" = "); + Disp_Cnode (C.Uaggr_Value, C.Uaggr_Field.Ftype); + Put ('}'); + when OC_Address => + Disp_Tnode_Name (C.Ctype); + Put ("'address ("); + Disp_Dnode_Name (C.Decl); + Put (")"); + when OC_Unchecked_Address => + Disp_Tnode_Name (C.Ctype); + Put ("'unchecked_address ("); + Disp_Dnode_Name (C.Decl); + Put (")"); + when OC_Subprogram_Address => + Disp_Tnode_Name (C.Ctype); + Put ("'subprg_addr ("); + Disp_Dnode_Name (C.Decl); + Put (")"); + end case; + end Disp_Cnode; + + -- Disp E whose expected type is ETYPE (may not be set). + procedure Disp_Enode (E : O_Enode; Etype : O_Tnode) + is + begin + case E.Kind is + when OE_Lit => + Disp_Cnode (E.Lit, Etype); + when OE_Dyadic_Expr_Kind => + Put ("("); + Disp_Enode (E.Left, O_Tnode_Null); + Put (' '); + Disp_Enode_Name (E.Kind); + Put (' '); + Disp_Enode (E.Right, E.Left.Rtype); + Put (')'); + when OE_Compare_Expr_Kind => + Disp_Tnode_Name (E.Rtype); + Put ("'("); + Disp_Enode (E.Left, O_Tnode_Null); + Put (' '); + Disp_Enode_Name (E.Kind); + Put (' '); + Disp_Enode (E.Right, E.Left.Rtype); + Put (')'); + when OE_Monadic_Expr_Kind => + Disp_Enode_Name (E.Kind); + if E.Kind /= OE_Neg_Ov then + Put (' '); + end if; + Disp_Enode (E.Operand, Etype); + when OE_Address => + Disp_Tnode_Name (E.Rtype); + Put ("'address ("); + Disp_Lnode (E.Lvalue); + Put (")"); + when OE_Unchecked_Address => + Disp_Tnode_Name (E.Rtype); + Put ("'unchecked_address ("); + Disp_Lnode (E.Lvalue); + Put (")"); + when OE_Convert_Ov => + Disp_Tnode_Name (E.Rtype); + Put ("'conv ("); + Disp_Enode (E.Conv, O_Tnode_Null); + Put (')'); + when OE_Function_Call => + Disp_Dnode_Name (E.Func); + Put (' '); + Disp_Assoc_List (E.Assoc); + when OE_Alloca => + Disp_Tnode_Name (E.Rtype); + Put ("'alloca ("); + Disp_Enode (E.A_Size, O_Tnode_Null); + Put (')'); + when OE_Value => + Disp_Lnode (E.Value); + when OE_Nil => + null; + end case; + end Disp_Enode; + + procedure Disp_Lnode (Node : O_Lnode) is + begin + case Node.Kind is + when OL_Obj => + Disp_Dnode_Name (Node.Obj); + when OL_Access_Element => + Disp_Enode (Node.Acc_Base, O_Tnode_Null); + Put (".all"); + when OL_Indexed_Element => + Disp_Lnode (Node.Array_Base); + Put ('['); + Disp_Enode (Node.Index, O_Tnode_Null); + Put (']'); + when OL_Slice => + Disp_Lnode (Node.Slice_Base); + Put ('['); + Disp_Enode (Node.Slice_Index, O_Tnode_Null); + Put ("...]"); + when OL_Selected_Element => + Disp_Lnode (Node.Rec_Base); + Put ('.'); + Disp_Ident (Node.Rec_El.Ident); +-- when OL_Var_Ref +-- | OL_Const_Ref +-- | OL_Param_Ref => +-- Disp_Dnode_Name (Node.Decl); + end case; + end Disp_Lnode; + + procedure Disp_Fnodes (First : O_Fnode) + is + El : O_Fnode; + begin + Add_Tab; + El := First; + while El /= null loop + Disp_Ident (El.Ident); + Put (": "); + Disp_Tnode (El.Ftype, False); + Put_Line ("; "); + El := El.Next; + end loop; + Rem_Tab; + end Disp_Fnodes; + + procedure Disp_Tnode (Atype : O_Tnode; Full : Boolean) is + begin + if not Full and Atype.Decl /= null then + Disp_Ident (Atype.Decl.Name); + return; + end if; + case Atype.Kind is + when ON_Boolean_Type => + Put ("boolean {"); + Disp_Ident (Atype.False_N.B_Id); + Put (", "); + Disp_Ident (Atype.True_N.B_Id); + Put ("}"); + when ON_Unsigned_Type => + Put ("unsigned ("); + Put_Trim (Natural'Image (Atype.Int_Size)); + Put (")"); + when ON_Signed_Type => + Put ("signed ("); + Put_Trim (Natural'Image (Atype.Int_Size)); + Put (")"); + when ON_Float_Type => + Put ("float"); + when ON_Enum_Type => + declare + El : O_Cnode; + begin + Put ("enum {"); + El := Atype.Literals; + while El /= O_Cnode_Null loop + Set_Mark; + Disp_Ident (El.E_Name); + Put (" = "); + Put (Image (El.E_Val)); + El := El.E_Next; + exit when El = O_Cnode_Null; + Put (", "); + end loop; + Put ("}"); + end; + when ON_Array_Type => + Put ("array ["); + Disp_Tnode (Atype.Index_Type, False); + Put ("] of "); + Disp_Tnode (Atype.El_Type, False); + when ON_Access_Type => + Put ("access "); + if Atype.D_Type /= O_Tnode_Null then + Disp_Tnode (Atype.D_Type, False); + end if; + when ON_Record_Type => + Put_Line ("record "); + Disp_Fnodes (Atype.Elements); + Put ("end record"); + when ON_Union_Type => + Put_Line ("union "); + Disp_Fnodes (Atype.Elements); + Put ("end union"); + when ON_Array_Sub_Type => + Put ("subarray "); + Disp_Tnode_Name (Atype.Base_Type); + Put ("["); + Disp_Cnode (Atype.Length, Atype.Base_Type.Index_Type); + Put ("]"); + end case; + end Disp_Tnode; + + procedure Disp_Storage_Name (Storage : O_Storage) is + begin + case Storage is + when O_Storage_External => + Put ("external"); + when O_Storage_Public => + Put ("public"); + when O_Storage_Private => + Put ("private"); + when O_Storage_Local => + Put ("local"); + end case; + end Disp_Storage_Name; + + procedure Disp_Decls (Decls : O_Dnode) + is + El : O_Dnode; + begin + El := Decls; + while El /= null loop + Disp_Dnode (El); + El := El.Next; + if Is_Top then + -- NOTE: some declaration does not disp anything, so there may be + -- double new line. + New_Line; + end if; + end loop; + end Disp_Decls; + + procedure Disp_Function_Decl (Decl : O_Dnode) is + begin + Disp_Storage_Name (Decl.Storage); + Put (" "); + if Decl.Dtype = null then + Put ("procedure "); + else + Put ("function "); + end if; + Disp_Ident (Decl.Name); + Put_Line (" ("); + Add_Tab; + declare + El : O_Dnode; + begin + El := Decl.Interfaces; + if El /= null then + loop + Disp_Dnode (El); + El := El.Next; + exit when El = null; + Put_Line (";"); + end loop; + end if; + Put (")"); + end; + if Decl.Dtype /= null then + New_Line; + Put ("return "); + Disp_Tnode (Decl.Dtype, False); + end if; + Rem_Tab; + end Disp_Function_Decl; + + procedure Disp_Dnode (Decl : O_Dnode) is + begin + case Decl.Kind is + when ON_Type_Decl => + Put ("type "); + Disp_Ident (Decl.Name); + Put (" is "); + if not Decl.Dtype.Uncomplete then + Disp_Tnode (Decl.Dtype, True); + else + case Decl.Dtype.Kind is + when ON_Record_Type => + Put ("record"); + when ON_Access_Type => + Put ("access"); + when others => + raise Program_Error; + end case; + end if; + Put_Line (";"); + when ON_Completed_Type_Decl => + Put ("type "); + Disp_Ident (Decl.Name); + Put (" is "); + Disp_Tnode (Decl.Dtype, True); + Put_Line (";"); + when ON_Const_Decl => + Disp_Storage_Name (Decl.Storage); + Put (" "); + Put ("constant "); + Disp_Ident (Decl.Name); + Put (" : "); + Disp_Tnode_Name (Decl.Dtype); + Put_Line (";"); + when ON_Const_Value => + Put ("constant "); + Disp_Ident (Decl.Name); + Put (" := "); + Disp_Cnode (Decl.Value, Decl.Dtype); + Put_Line (";"); + when ON_Var_Decl => + Disp_Storage_Name (Decl.Storage); + Put (" "); + Put ("var "); + Disp_Ident (Decl.Name); + Put (" : "); + Disp_Tnode_Name (Decl.Dtype); + Put_Line (";"); + when ON_Function_Decl => + if Decl.Next = null or Decl.Next /= Decl.Func_Body then + -- This is a forward/external declaration. + Disp_Function_Decl (Decl); + Put_Line (";"); + end if; + when ON_Function_Body => + Disp_Function_Decl (Decl.Func_Decl); + New_Line; + Disp_Snode (Decl.Func_Stmt, Decl.Func_Stmt); + when ON_Interface_Decl => + Disp_Ident (Decl.Name); + Put (": "); + Disp_Tnode (Decl.Dtype, False); + when ON_Debug_Line_Decl => + Put_Line ("--#" & Natural'Image (Decl.Line)); + when ON_Debug_Comment_Decl => + Put_Line ("-- " & Decl.Comment.all); + when ON_Debug_Filename_Decl => + Put_Line ("--F " & Decl.Filename.all); + end case; + end Disp_Dnode; + + procedure Disp_Snode (First : O_Snode; Last : O_Snode) is + Stmt : O_Snode; + begin + Stmt := First; + loop + --if Stmt.Kind = ON_Elsif_Stmt or Stmt.Kind = ON_When_Stmt then + -- Put_Indent (Tab - 1); + --else + -- Put_Indent (Tab); + --end if; + case Stmt.Kind is + when ON_Declare_Stmt => + Put_Line ("declare"); + Add_Tab; + Disp_Decls (Stmt.Decls); + Rem_Tab; + Put_Line ("begin"); + Add_Tab; + if Stmt.Stmts /= null then + Disp_Snode (Stmt.Stmts, null); + end if; + Rem_Tab; + Put_Line ("end;"); + when ON_Assign_Stmt => + Disp_Lnode (Stmt.Target); + Put (" := "); + Disp_Enode (Stmt.Value, Stmt.Target.Rtype); + Put_Line (";"); + when ON_Return_Stmt => + Put ("return "); + if Stmt.Ret_Val /= null then + Disp_Enode (Stmt.Ret_Val, O_Tnode_Null); + end if; + Put_Line (";"); + when ON_If_Stmt => + Add_Tab; + Disp_Snode (Stmt.Next, Stmt.If_Last); + Stmt := Stmt.If_Last; + Rem_Tab; + Put_Line ("end if;"); + when ON_Elsif_Stmt => + Rem_Tab; + if Stmt.Cond = null then + Put_Line ("else"); + else + if First = Stmt then + Put ("if "); + else + Put ("elsif "); + end if; + Disp_Enode (Stmt.Cond, O_Tnode_Null); + Put_Line (" then"); + end if; + Add_Tab; + when ON_Loop_Stmt => + Disp_Loop_Name (Stmt); + Put_Line (":"); + Add_Tab; + Disp_Snode (Stmt.Next, Stmt.Loop_Last); + Stmt := Stmt.Loop_Last; + Rem_Tab; + Put_Line ("end loop;"); + when ON_Exit_Stmt => + Put ("exit "); + Disp_Loop_Name (Stmt.Loop_Id); + Put_Line (";"); + when ON_Next_Stmt => + Put ("next "); + Disp_Loop_Name (Stmt.Loop_Id); + Put_Line (";"); + when ON_Case_Stmt => + Put ("case "); + Disp_Enode (Stmt.Selector, O_Tnode_Null); + Put_Line (" is"); + Add_Tab; + Disp_Snode (Stmt.Next, Stmt.Case_Last); + Stmt := Stmt.Case_Last; + Rem_Tab; + Put_Line ("end case;"); + when ON_When_Stmt => + declare + Choice: O_Choice; + Choice_Type : constant O_Tnode := + Stmt.Branch_Parent.Selector.Rtype; + begin + Rem_Tab; + Choice := Stmt.Choice_List; + Put ("when "); + loop + case Choice.Kind is + when ON_Choice_Expr => + Disp_Cnode (Choice.Expr, Choice_Type); + when ON_Choice_Range => + Disp_Cnode (Choice.Low, Choice_Type); + Put (" ... "); + Disp_Cnode (Choice.High, Choice_Type); + when ON_Choice_Default => + Put ("default"); + end case; + Choice := Choice.Next; + exit when Choice = null; + Put_Line (","); + Put (" "); + end loop; + Put_Line (" =>"); + Add_Tab; + end; + when ON_Call_Stmt => + Disp_Dnode_Name (Stmt.Proc); + Put (' '); + Disp_Assoc_List (Stmt.Assoc); + Put_Line (";"); + when ON_Debug_Line_Stmt => + Put_Line ("--#" & Natural'Image (Stmt.Line)); + when ON_Debug_Comment_Stmt => + Put_Line ("-- " & Stmt.Comment.all); + end case; + exit when Stmt = Last; + Stmt := Stmt.Next; + exit when Stmt = null and Last = null; + end loop; + end Disp_Snode; + + procedure Disp_Ortho (Decls : O_Snode) is + begin + Disp_Decls (Decls.Decls); + Flush; + end Disp_Ortho; + + procedure Disp_Tnode_Decl (N : O_Tnode) is + begin + Disp_Ident (N.Decl.Name); + Put (" : "); + Disp_Tnode (N, True); + end Disp_Tnode_Decl; + + procedure Debug_Tnode (N : O_Tnode) + is + Ctx : Disp_Context; + begin + Push_Context (Interfaces.C_Streams.stdout, Ctx); + Disp_Tnode_Decl (N); + Pop_Context (Ctx); + end Debug_Tnode; + + procedure Debug_Enode (N : O_Enode) + is + Ctx : Disp_Context; + begin + Push_Context (Interfaces.C_Streams.stdout, Ctx); + Disp_Enode (N, O_Tnode_Null); + Put (" : "); + Disp_Tnode_Decl (N.Rtype); + Pop_Context (Ctx); + end Debug_Enode; + + procedure Debug_Fnode (N : O_Fnode) + is + Ctx : Disp_Context; + begin + Push_Context (Interfaces.C_Streams.stdout, Ctx); + Disp_Ident (N.Ident); + Put (": "); + Disp_Tnode (N.Ftype, False); + Pop_Context (Ctx); + end Debug_Fnode; + + procedure Debug_Dnode (N : O_Dnode) + is + Ctx : Disp_Context; + begin + Push_Context (Interfaces.C_Streams.stdout, Ctx); + Disp_Dnode (N); + Pop_Context (Ctx); + end Debug_Dnode; + + procedure Debug_Lnode (N : O_Lnode) + is + Ctx : Disp_Context; + begin + Push_Context (Interfaces.C_Streams.stdout, Ctx); + Disp_Lnode (N); + Put (" : "); + Disp_Tnode_Decl (N.Rtype); + Pop_Context (Ctx); + end Debug_Lnode; + + procedure Debug_Snode (N : O_Snode) + is + Ctx : Disp_Context; + begin + Push_Context (Interfaces.C_Streams.stdout, Ctx); + Disp_Snode (N, null); + Pop_Context (Ctx); + end Debug_Snode; + + pragma Unreferenced (Debug_Tnode, Debug_Enode, Debug_Fnode, + Debug_Dnode, Debug_Lnode, Debug_Snode); +end Ortho_Debug.Disp; diff --git a/src/ortho/debug/ortho_debug-disp.ads b/src/ortho/debug/ortho_debug-disp.ads new file mode 100644 index 000000000..c365a3530 --- /dev/null +++ b/src/ortho/debug/ortho_debug-disp.ads @@ -0,0 +1,29 @@ +-- Display the ortho codes from a tree. +-- Copyright (C) 2005 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 Interfaces.C_Streams; + +package Ortho_Debug.Disp is + -- Initialize the current context. + -- Must be called before any use of the DISP_* subprograms. + procedure Init_Context (File : Interfaces.C_Streams.FILEs); + + -- Disp nodes in a pseudo-language. + procedure Disp_Ortho (Decls : O_Snode); + +private +end Ortho_Debug.Disp; diff --git a/src/ortho/debug/ortho_debug-main.adb b/src/ortho/debug/ortho_debug-main.adb new file mode 100644 index 000000000..b470deaab --- /dev/null +++ b/src/ortho/debug/ortho_debug-main.adb @@ -0,0 +1,151 @@ +-- Main procedure of ortho debug back-end. +-- Copyright (C) 2005 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.Command_Line; use Ada.Command_Line; +with Ada.Unchecked_Deallocation; +with Ada.Text_IO; use Ada.Text_IO; +with Ortho_Debug; use Ortho_Debug; +with Ortho_Debug_Front; use Ortho_Debug_Front; +with Ortho_Debug.Disp; +with System; use System; +with Interfaces.C_Streams; use Interfaces.C_Streams; + +procedure Ortho_Debug.Main is + -- Do not output the ortho code. + Flag_Silent : Boolean := False; + + -- Force output, even in case of crash. + Flag_Force : Boolean := False; + + I : Natural; + Argc : Natural; + Arg : String_Acc; + Opt : String_Acc; + Res : Natural; + File : String_Acc; + Output : FILEs; + R : Boolean; + + procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation + (Name => String_Acc, Object => String); +begin + Ortho_Debug_Front.Init; + Output := NULL_Stream; + + Set_Exit_Status (Failure); + + -- Decode options. + Argc := Argument_Count; + I := 1; + loop + exit when I > Argc; + exit when Argument (I) (1) /= '-'; + if Argument (I) = "--silent" or else Argument (I) = "-quiet" then + Flag_Silent := True; + I := I + 1; + elsif Argument (I) = "--force" then + Flag_Force := True; + I := I + 1; + elsif Argument (I)'Length >= 2 and then Argument (I)(2) = 'g' then + -- Skip -g[XXX] flags. + I := I + 1; + elsif Argument (I) = "-o" and then I + 1 <= Argc then + -- TODO: write the output to the file ? + if Output /= NULL_Stream then + Put_Line (Command_Name & ": only one output allowed"); + return; + end if; + declare + Name : String := Argument (I + 1) & ASCII.Nul; + Mode : String := 'w' & ASCII.Nul; + begin + Output := fopen (Name'Address, Mode'Address); + if Output = NULL_Stream then + Put_Line (Command_Name & ": cannot open " & Argument (I + 1)); + return; + end if; + end; + I := I + 2; + else + Opt := new String'(Argument (I)); + if I < Argc then + Arg := new String'(Argument (I + 1)); + else + Arg := null; + end if; + Res := Ortho_Debug_Front.Decode_Option (Opt, Arg); + Unchecked_Deallocation (Opt); + Unchecked_Deallocation (Arg); + if Res = 0 then + Put_Line (Argument (I) & ": unknown option"); + return; + else + I := I + Res; + end if; + end if; + end loop; + + -- Initialize tree. + begin + Ortho_Debug.Init; + + if I <= Argc then + R := True; + for J in I .. Argc loop + File := new String'(Argument (J)); + R := R and Ortho_Debug_Front.Parse (File); + Unchecked_Deallocation (File); + end loop; + else + R := Ortho_Debug_Front.Parse (null); + end if; + Ortho_Debug.Finish; + exception + when others => + if not Flag_Force then + raise; + else + R := False; + end if; + end; + + -- Write down the result. + if (R and (Output /= NULL_Stream or not Flag_Silent)) + or Flag_Force + then + if Output = NULL_Stream then + Ortho_Debug.Disp.Init_Context (stdout); + else + Ortho_Debug.Disp.Init_Context (Output); + end if; + Ortho_Debug.Disp.Disp_Ortho (Ortho_Debug.Top); + if Output /= NULL_Stream then + declare + Status : int; + pragma Unreferenced (Status); + begin + Status := fclose (Output); + end; + end if; + end if; + + if R then + Set_Exit_Status (Success); + else + Set_Exit_Status (Failure); + end if; +end Ortho_Debug.Main; diff --git a/src/ortho/debug/ortho_debug.adb b/src/ortho/debug/ortho_debug.adb new file mode 100644 index 000000000..8285a6473 --- /dev/null +++ b/src/ortho/debug/ortho_debug.adb @@ -0,0 +1,1931 @@ +-- Ortho debug back-end. +-- Copyright (C) 2005 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.Unchecked_Deallocation; + +package body Ortho_Debug is + -- If True, disable some checks so that the output can be generated. + Disable_Checks : constant Boolean := False; + + type ON_Op_To_OE_Type is array (ON_Op_Kind) of OE_Kind; + ON_Op_To_OE : constant ON_Op_To_OE_Type := + ( + ON_Nil => OE_Nil, + + -- Dyadic operations. + ON_Add_Ov => OE_Add_Ov, + ON_Sub_Ov => OE_Sub_Ov, + ON_Mul_Ov => OE_Mul_Ov, + ON_Div_Ov => OE_Div_Ov, + ON_Rem_Ov => OE_Rem_Ov, + ON_Mod_Ov => OE_Mod_Ov, + + -- Binary operations. + ON_And => OE_And, + ON_Or => OE_Or, + ON_Xor => OE_Xor, + + -- Monadic operations. + ON_Not => OE_Not, + ON_Neg_Ov => OE_Neg_Ov, + ON_Abs_Ov => OE_Abs_Ov, + + -- Comparaisons + ON_Eq => OE_Eq, + ON_Neq => OE_Neq, + ON_Le => OE_Le, + ON_Lt => OE_Lt, + ON_Ge => OE_Ge, + ON_Gt => OE_Gt + ); + + type Decl_Scope_Type is record + -- Declarations are chained. + Parent : O_Snode; + Last_Decl : O_Dnode; + Last_Stmt : O_Snode; + + -- If this scope corresponds to a function, PREV_FUNCTION contains + -- the previous function. + Prev_Function : O_Dnode; + + -- Declaration scopes are chained. + Prev : Decl_Scope_Acc; + end record; + + type Stmt_Kind is + (Stmt_Function, Stmt_Declare, Stmt_If, Stmt_Loop, Stmt_Case); + type Stmt_Scope_Type (Kind : Stmt_Kind); + type Stmt_Scope_Acc is access Stmt_Scope_Type; + type Stmt_Scope_Type (Kind : Stmt_Kind) is record + -- Statement which created this scope. + Parent : O_Snode; + -- Previous (parent) scope. + Prev : Stmt_Scope_Acc; + case Kind is + when Stmt_Function => + Prev_Function : Stmt_Scope_Acc; + -- Declaration for the function. + Decl : O_Dnode; + when Stmt_Declare => + null; + when Stmt_If => + Last_Elsif : O_Snode; + when Stmt_Loop => + null; + when Stmt_Case => + Last_Branch : O_Snode; + Last_Choice : O_Choice; + Case_Type : O_Tnode; + end case; + end record; + subtype Stmt_Function_Scope_Type is Stmt_Scope_Type (Stmt_Function); + subtype Stmt_Declare_Scope_Type is Stmt_Scope_Type (Stmt_Declare); + subtype Stmt_If_Scope_Type is Stmt_Scope_Type (Stmt_If); + subtype Stmt_Loop_Scope_Type is Stmt_Scope_Type (Stmt_Loop); + subtype Stmt_Case_Scope_Type is Stmt_Scope_Type (Stmt_Case); + + Current_Stmt_Scope : Stmt_Scope_Acc := null; + Current_Function : Stmt_Scope_Acc := null; + Current_Decl_Scope : Decl_Scope_Acc := null; + Current_Loop_Level : Natural := 0; + + procedure Push_Decl_Scope (Parent : O_Snode) + is + Res : Decl_Scope_Acc; + begin + Res := new Decl_Scope_Type'(Parent => Parent, + Last_Decl => null, + Last_Stmt => null, + Prev_Function => null, + Prev => Current_Decl_Scope); + Parent.Alive := True; + Current_Decl_Scope := Res; + end Push_Decl_Scope; + + procedure Pop_Decl_Scope + is + procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation + (Object => Decl_Scope_Type, Name => Decl_Scope_Acc); + Old : Decl_Scope_Acc; + begin + Old := Current_Decl_Scope; + Old.Parent.Alive := False; + Current_Decl_Scope := Old.Prev; + Unchecked_Deallocation (Old); + end Pop_Decl_Scope; + + procedure Add_Decl (El : O_Dnode; Check_Dup : Boolean := True) is + begin + if Current_Decl_Scope = null then + -- Not yet initialized, or after compilation. + raise Program_Error; + end if; + + -- Note: this requires an hashed ident table. + -- Use ortho_ident_hash. + if False and then Check_Dup + and then not Is_Nul (El.Name) + then + -- Check the name is not already defined. + declare + E : O_Dnode; + begin + E := Current_Decl_Scope.Parent.Decls; + while E /= O_Dnode_Null loop + if Is_Equal (E.Name, El.Name) then + raise Syntax_Error; + end if; + E := E.Next; + end loop; + end; + end if; + + if Current_Decl_Scope.Last_Decl = null then + if Current_Decl_Scope.Parent.Kind = ON_Declare_Stmt then + Current_Decl_Scope.Parent.Decls := El; + else + raise Type_Error; + end if; + else + Current_Decl_Scope.Last_Decl.Next := El; + end if; + El.Next := null; + Current_Decl_Scope.Last_Decl := El; + end Add_Decl; + + procedure Add_Stmt (Stmt : O_Snode) + is + begin + if Current_Decl_Scope = null or Current_Function = null then + -- You are adding a statement at the global level, ie not inside + -- a function. + raise Syntax_Error; + end if; + + Stmt.Next := null; + if Current_Decl_Scope.Last_Stmt = null then + if Current_Decl_Scope.Parent.Kind = ON_Declare_Stmt then + Current_Decl_Scope.Parent.Stmts := Stmt; + else + raise Syntax_Error; + end if; + else + Current_Decl_Scope.Last_Stmt.Next := Stmt; + end if; + Current_Decl_Scope.Last_Stmt := Stmt; + end Add_Stmt; + + procedure Push_Stmt_Scope (Scope : Stmt_Scope_Acc) + is + begin + if Scope.Prev /= Current_Stmt_Scope then + -- SCOPE was badly initialized. + raise Program_Error; + end if; + Current_Stmt_Scope := Scope; + end Push_Stmt_Scope; + + procedure Pop_Stmt_Scope (Kind : Stmt_Kind) + is + procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation + (Object => Stmt_Scope_Type, Name => Stmt_Scope_Acc); + Old : Stmt_Scope_Acc; + begin + Old := Current_Stmt_Scope; + if Old.Kind /= Kind then + raise Syntax_Error; + end if; + --Old.Parent.Last_Stmt := Current_Decl_Scope.Last_Stmt; + Current_Stmt_Scope := Old.Prev; + Unchecked_Deallocation (Old); + end Pop_Stmt_Scope; + + -- Check declaration DECL is reachable, ie its scope is in the current + -- stack of scopes. + procedure Check_Scope (Decl : O_Dnode) + is + Res : Boolean; + begin + case Decl.Kind is + when ON_Interface_Decl => + Res := Decl.Func_Scope.Alive; + when others => + Res := Decl.Scope.Alive; + end case; + if not Res then + raise Syntax_Error; + end if; + end Check_Scope; + + -- Raise SYNTAX_ERROR if OBJ is not at a constant address. +-- procedure Check_Const_Address (Obj : O_Lnode) is +-- begin +-- case Obj.Kind is +-- when OL_Const_Ref +-- | OL_Var_Ref => +-- case Obj.Decl.Storage is +-- when O_Storage_External +-- | O_Storage_Public +-- | O_Storage_Private => +-- null; +-- when O_Storage_Local => +-- raise Syntax_Error; +-- end case; +-- when others => +-- -- FIXME: constant indexed element, selected element maybe +-- -- of const address. +-- raise Syntax_Error; +-- end case; +-- end Check_Const_Address; + + procedure Check_Type (T1, T2 : O_Tnode) is + begin + if T1 = T2 then + return; + end if; + if T1.Kind = ON_Array_Sub_Type and then T2.Kind = ON_Array_Sub_Type + and then T1.Base_Type = T2.Base_Type + and then T1.Length.all = T2.Length.all + then + return; + end if; + raise Type_Error; + end Check_Type; + + procedure Check_Ref (N : O_Enode) is + begin + if N.Ref then + -- Already referenced. + raise Syntax_Error; + end if; + N.Ref := True; + end Check_Ref; + + procedure Check_Ref (N : O_Lnode) is + begin + if N.Ref then + raise Syntax_Error; + end if; + N.Ref := True; + end Check_Ref; + + procedure Check_Complete_Type (T : O_Tnode) is + begin + if not T.Complete then + -- Uncomplete type cannot be used here (since its size is required, + -- for example). + raise Syntax_Error; + end if; + end Check_Complete_Type; + + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode + is + K : constant OE_Kind := ON_Op_To_OE (Kind); + Res : O_Enode; + begin + Check_Type (Left.Rtype, Right.Rtype); + Check_Ref (Left); + Check_Ref (Right); + Res := new O_Enode_Type (K); + Res.Rtype := Left.Rtype; + Res.Ref := False; + Res.Left := Left; + Res.Right := Right; + return Res; + end New_Dyadic_Op; + + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode + is + Res : O_Enode; + begin + Check_Ref (Operand); + Res := new O_Enode_Type (ON_Op_To_OE (Kind)); + Res.Ref := False; + Res.Operand := Operand; + Res.Rtype := Operand.Rtype; + return Res; + 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 Ntype.Kind /= ON_Boolean_Type then + raise Type_Error; + end if; + if Left.Rtype /= Right.Rtype then + raise Type_Error; + end if; + Check_Ref (Left); + Check_Ref (Right); + Res := new O_Enode_Type (ON_Op_To_OE (Kind)); + Res.Ref := False; + Res.Left := Left; + Res.Right := Right; + Res.Rtype := Ntype; + return Res; + end New_Compare_Op; + + + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode + is + subtype O_Cnode_Signed_Lit is O_Cnode_Type (OC_Signed_Lit); + begin + if Ltype.Kind = ON_Signed_Type then + return new O_Cnode_Signed_Lit'(Kind => OC_Signed_Lit, + Ctype => Ltype, + Ref => False, + S_Val => Value); + else + raise Type_Error; + end if; + end New_Signed_Literal; + + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode + is + subtype O_Cnode_Unsigned_Lit is O_Cnode_Type (OC_Unsigned_Lit); + begin + if Ltype.Kind = ON_Unsigned_Type then + return new O_Cnode_Unsigned_Lit'(Kind => OC_Unsigned_Lit, + Ctype => Ltype, + Ref => False, + U_Val => Value); + else + raise Type_Error; + end if; + end New_Unsigned_Literal; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode + is + subtype O_Cnode_Float_Lit is O_Cnode_Type (OC_Float_Lit); + begin + if Ltype.Kind = ON_Float_Type then + return new O_Cnode_Float_Lit'(Kind => OC_Float_Lit, + Ctype => Ltype, + Ref => False, + F_Val => Value); + else + raise Type_Error; + end if; + end New_Float_Literal; + + function New_Null_Access (Ltype : O_Tnode) return O_Cnode + is + subtype O_Cnode_Null_Lit_Type is O_Cnode_Type (OC_Null_Lit); + begin + if Ltype.Kind /= ON_Access_Type then + raise Type_Error; + end if; + return new O_Cnode_Null_Lit_Type'(Kind => OC_Null_Lit, + Ctype => Ltype, + Ref => False); + end New_Null_Access; + + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode + is + subtype O_Cnode_Sizeof_Type is O_Cnode_Type (OC_Sizeof_Lit); + begin + if Rtype.Kind /= ON_Unsigned_Type + and then Rtype.Kind /= ON_Access_Type + then + raise Type_Error; + end if; + Check_Complete_Type (Atype); + if Atype.Kind = ON_Array_Type then + raise Type_Error; + end if; + return new O_Cnode_Sizeof_Type'(Kind => OC_Sizeof_Lit, + Ctype => Rtype, + Ref => False, + S_Type => Atype); + end New_Sizeof; + + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode + is + subtype O_Cnode_Alignof_Type is O_Cnode_Type (OC_Alignof_Lit); + begin + if Rtype.Kind /= ON_Unsigned_Type then + raise Type_Error; + end if; + Check_Complete_Type (Atype); + return new O_Cnode_Alignof_Type'(Kind => OC_Alignof_Lit, + Ctype => Rtype, + Ref => False, + S_Type => Atype); + end New_Alignof; + + function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode + is + subtype O_Cnode_Offsetof_Type is O_Cnode_Type (OC_Offsetof_Lit); + begin + if Rtype.Kind /= ON_Unsigned_Type + and then Rtype.Kind /= ON_Access_Type + then + raise Type_Error; + end if; + if Field.Parent /= Atype then + raise Type_Error; + end if; + return new O_Cnode_Offsetof_Type'(Kind => OC_Offsetof_Lit, + Ctype => Rtype, + Ref => False, + Off_Field => Field); + end New_Offsetof; + + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode + is + subtype O_Enode_Alloca_Type is O_Enode_Type (OE_Alloca); + Res : O_Enode; + begin + if Rtype.Kind /= ON_Access_Type then + raise Type_Error; + end if; + if Size.Rtype.Kind /= ON_Unsigned_Type then + raise Type_Error; + end if; + Res := new O_Enode_Alloca_Type'(Kind => OE_Alloca, + Rtype => Rtype, + Ref => False, + A_Size => Size); + return Res; + end New_Alloca; + + procedure Check_Constrained_Type (Atype : O_Tnode) is + begin + case Atype.Kind is + when ON_Array_Type => + raise Type_Error; + when ON_Unsigned_Type + | ON_Signed_Type + | ON_Boolean_Type + | ON_Record_Type + | ON_Union_Type + | ON_Access_Type + | ON_Float_Type + | ON_Array_Sub_Type + | ON_Enum_Type => + null; + end case; + end Check_Constrained_Type; + + procedure New_Completed_Type_Decl (Atype : O_Tnode) + is + N : O_Dnode; + begin + if Atype.Decl = null then + -- The uncompleted type must have been declared. + raise Type_Error; + end if; + N := new O_Dnode_Type (ON_Completed_Type_Decl); + N.Name := Atype.Decl.Name; + N.Dtype := Atype; + Add_Decl (N, False); + end New_Completed_Type_Decl; + + procedure New_Uncomplete_Record_Type (Res : out O_Tnode) + is + subtype O_Tnode_Record_Type is O_Tnode_Type (ON_Record_Type); + begin + Res := new O_Tnode_Record_Type'(Kind => ON_Record_Type, + Decl => O_Dnode_Null, + Uncomplete => True, + Complete => False, + Elements => O_Fnode_Null); + end New_Uncomplete_Record_Type; + + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List) is + begin + if not Res.Uncomplete then + -- RES record type is not an uncomplete record type. + raise Syntax_Error; + end if; + if Res.Elements /= O_Fnode_Null then + -- RES record type already has elements... + raise Syntax_Error; + end if; + Elements.Res := Res; + Elements.Last := null; + end Start_Uncomplete_Record_Type; + + procedure Start_Record_Type (Elements : out O_Element_List) + is + subtype O_Tnode_Record_Type is O_Tnode_Type (ON_Record_Type); + begin + Elements.Res := new O_Tnode_Record_Type'(Kind => ON_Record_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => False, + Elements => O_Fnode_Null); + Elements.Last := null; + end Start_Record_Type; + + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode) + is + begin + Check_Complete_Type (Etype); + Check_Constrained_Type (Etype); + El := new O_Fnode_Type'(Parent => Elements.Res, + Next => null, + Ident => Ident, + Ftype => Etype, + Offset => 0); + -- Append EL. + if Elements.Last = null then + Elements.Res.Elements := El; + else + Elements.Last.Next := El; + end if; + Elements.Last := El; + end New_Record_Field; + + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode) is + begin + -- Align the structure. + Res := Elements.Res; + if Res.Uncomplete then + New_Completed_Type_Decl (Res); + end if; + Res.Complete := True; + end Finish_Record_Type; + + procedure Start_Union_Type (Elements : out O_Element_List) + is + subtype O_Tnode_Union_Type is O_Tnode_Type (ON_Union_Type); + begin + Elements.Res := new O_Tnode_Union_Type'(Kind => ON_Union_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => False, + Elements => O_Fnode_Null); + Elements.Last := null; + end Start_Union_Type; + + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode) + is + begin + New_Record_Field (Elements, El, Ident, Etype); + end New_Union_Field; + + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode) is + begin + Res := Elements.Res; + Res.Complete := True; + end Finish_Union_Type; + + function New_Access_Type (Dtype : O_Tnode) return O_Tnode + is + subtype O_Tnode_Access is O_Tnode_Type (ON_Access_Type); + Res : O_Tnode; + begin + if Dtype /= O_Tnode_Null + and then Dtype.Kind = ON_Array_Sub_Type + then + -- Access to sub array are not allowed, use access to array. + raise Type_Error; + end if; + Res := new O_Tnode_Access'(Kind => ON_Access_Type, + Decl => O_Dnode_Null, + Uncomplete => Dtype = O_Tnode_Null, + Complete => True, + D_Type => Dtype); + return Res; + end New_Access_Type; + + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode) + is + begin + if Dtype.Kind = ON_Array_Sub_Type then + -- Access to sub array are not allowed, use access to array. + raise Type_Error; + end if; + if Atype.D_Type /= O_Tnode_Null + or Atype.Uncomplete = False + then + -- Type already completed. + raise Syntax_Error; + end if; + Atype.D_Type := Dtype; + New_Completed_Type_Decl (Atype); + end Finish_Access_Type; + + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode + is + subtype O_Tnode_Array is O_Tnode_Type (ON_Array_Type); + begin + Check_Constrained_Type (El_Type); + Check_Complete_Type (El_Type); + return new O_Tnode_Array'(Kind => ON_Array_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => True, + El_Type => El_Type, + Index_Type => Index_Type); + end New_Array_Type; + + function New_Constrained_Array_Type (Atype : O_Tnode; Length : O_Cnode) + return O_Tnode + is + subtype O_Tnode_Sub_Array is O_Tnode_Type (ON_Array_Sub_Type); + begin + if Atype.Kind /= ON_Array_Type then + raise Type_Error; + end if; + return new O_Tnode_Sub_Array'(Kind => ON_Array_Sub_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => True, + Base_Type => Atype, + Length => Length); + end New_Constrained_Array_Type; + + function New_Unsigned_Type (Size : Natural) return O_Tnode + is + subtype O_Tnode_Unsigned is O_Tnode_Type (ON_Unsigned_Type); + begin + return new O_Tnode_Unsigned'(Kind => ON_Unsigned_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => True, + Int_Size => Size); + end New_Unsigned_Type; + + function New_Signed_Type (Size : Natural) return O_Tnode + is + subtype O_Tnode_Signed is O_Tnode_Type (ON_Signed_Type); + begin + return new O_Tnode_Signed'(Kind => ON_Signed_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => True, + Int_Size => Size); + end New_Signed_Type; + + function New_Float_Type return O_Tnode + is + subtype O_Tnode_Float is O_Tnode_Type (ON_Float_Type); + begin + return new O_Tnode_Float'(Kind => ON_Float_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => True); + end New_Float_Type; + + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode) + is + subtype O_Tnode_Boolean is O_Tnode_Type (ON_Boolean_Type); + subtype O_Cnode_Boolean_Lit is O_Cnode_Type (OC_Boolean_Lit); + begin + Res := new O_Tnode_Boolean'(Kind => ON_Boolean_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => True, + True_N => O_Cnode_Null, + False_N => O_Cnode_Null); + True_E := new O_Cnode_Boolean_Lit'(Kind => OC_Boolean_Lit, + Ctype => Res, + Ref => False, + B_Val => True, + B_Id => True_Id); + False_E := new O_Cnode_Boolean_Lit'(Kind => OC_Boolean_Lit, + Ctype => Res, + Ref => False, + B_Val => False, + B_Id => False_Id); + Res.True_N := True_E; + Res.False_N := False_E; + end New_Boolean_Type; + + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural) + is + pragma Unreferenced (Size); + subtype O_Tnode_Enum is O_Tnode_Type (ON_Enum_Type); + Res : O_Tnode; + begin + Res := new O_Tnode_Enum'(Kind => ON_Enum_Type, + Decl => O_Dnode_Null, + Uncomplete => False, + Complete => False, + Nbr => 0, + Literals => O_Cnode_Null); + List.Res := Res; + List.Last := O_Cnode_Null; + end Start_Enum_Type; + + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; + Res : out O_Cnode) + is + subtype O_Cnode_Enum_Lit is O_Cnode_Type (OC_Enum_Lit); + begin + Res := new O_Cnode_Enum_Lit'(Kind => OC_Enum_Lit, + Ctype => List.Res, + Ref => False, + E_Val => List.Res.Nbr, + E_Name => Ident, + E_Next => O_Cnode_Null); + -- Link it. + if List.Last = O_Cnode_Null then + List.Res.Literals := Res; + else + List.Last.E_Next := Res; + end if; + List.Last := Res; + + List.Res.Nbr := List.Res.Nbr + 1; + end New_Enum_Literal; + + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode) is + begin + Res := List.Res; + Res.Complete := True; + end Finish_Enum_Type; + + function Get_Base_Type (Atype : O_Tnode) return O_Tnode + is + begin + case Atype.Kind is + when ON_Array_Sub_Type => + return Atype.Base_Type; + when others => + return Atype; + end case; + end Get_Base_Type; + + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; Atype : O_Tnode) + is + subtype O_Cnode_Aggregate is O_Cnode_Type (OC_Aggregate); + Res : O_Cnode; + begin + if Atype.Kind /= ON_Record_Type then + raise Type_Error; + end if; + Check_Complete_Type (Atype); + Res := new O_Cnode_Aggregate'(Kind => OC_Aggregate, + Ctype => Atype, + Ref => False, + Aggr_Els => null); + List.Res := Res; + List.Last := null; + List.Field := Atype.Elements; + end Start_Record_Aggr; + + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode) + is + subtype O_Cnode_Aggrel_Type is O_Cnode_Type (OC_Aggr_Element); + El : O_Cnode; + begin + if List.Field = O_Fnode_Null then + -- No more element in the aggregate. + raise Syntax_Error; + end if; + Check_Type (Value.Ctype, List.Field.Ftype); + El := new O_Cnode_Aggrel_Type'(Kind => OC_Aggr_Element, + Ctype => Value.Ctype, + Ref => False, + Aggr_Value => Value, + Aggr_Next => null); + if List.Last = null then + List.Res.Aggr_Els := El; + else + List.Last.Aggr_Next := El; + end if; + List.Last := El; + List.Field := List.Field.Next; + end New_Record_Aggr_El; + + procedure Finish_Record_Aggr + (List : in out O_Record_Aggr_List; Res : out O_Cnode) + is + begin + if List.Field /= null then + -- Not enough elements in aggregate. + raise Type_Error; + end if; + Res := List.Res; + end Finish_Record_Aggr; + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode) + is + subtype O_Cnode_Aggregate is O_Cnode_Type (OC_Aggregate); + Res : O_Cnode; + begin + if Atype.Kind /= ON_Array_Sub_Type then + raise Type_Error; + end if; + Check_Complete_Type (Atype); + Res := new O_Cnode_Aggregate'(Kind => OC_Aggregate, + Ctype => Atype, + Ref => False, + Aggr_Els => null); + List.Res := Res; + List.Last := null; + List.El_Type := Atype.Base_Type.El_Type; + end Start_Array_Aggr; + + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode) + is + subtype O_Cnode_Aggrel_Type is O_Cnode_Type (OC_Aggr_Element); + El : O_Cnode; + begin + Check_Type (Value.Ctype, List.El_Type); + El := new O_Cnode_Aggrel_Type'(Kind => OC_Aggr_Element, + Ctype => Value.Ctype, + Ref => False, + Aggr_Value => Value, + Aggr_Next => null); + if List.Last = null then + List.Res.Aggr_Els := El; + else + List.Last.Aggr_Next := El; + end if; + List.Last := El; + end New_Array_Aggr_El; + + procedure Finish_Array_Aggr + (List : in out O_Array_Aggr_List; Res : out O_Cnode) is + begin + Res := List.Res; + end Finish_Array_Aggr; + + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode + is + subtype O_Cnode_Union_Aggr is O_Cnode_Type (OC_Union_Aggr); + Res : O_Cnode; + begin + if Atype.Kind /= ON_Union_Type then + raise Type_Error; + end if; + Check_Type (Value.Ctype, Field.Ftype); + + Res := new O_Cnode_Union_Aggr'(Kind => OC_Union_Aggr, + Ctype => Atype, + Ref => False, + Uaggr_Field => Field, + Uaggr_Value => Value); + return Res; + end New_Union_Aggr; + + function New_Obj (Obj : O_Dnode) return O_Lnode + is + subtype O_Lnode_Obj is O_Lnode_Type (OL_Obj); + begin + case Obj.Kind is + when ON_Const_Decl + | ON_Var_Decl + | ON_Interface_Decl => + null; + when others => + raise Program_Error; + end case; + Check_Scope (Obj); + return new O_Lnode_Obj'(Kind => OL_Obj, + Rtype => Obj.Dtype, + Ref => False, + Obj => Obj); + end New_Obj; + + function New_Indexed_Element (Arr : O_Lnode; Index : O_Enode) + return O_Lnode + is + subtype O_Lnode_Indexed is O_Lnode_Type (OL_Indexed_Element); + Res : O_Lnode; + begin + Check_Ref (Arr); + Res := new O_Lnode_Indexed'(Kind => OL_Indexed_Element, + Rtype => Get_Base_Type (Arr.Rtype).El_Type, + Ref => False, + Array_Base => Arr, + Index => Index); + return Res; + end New_Indexed_Element; + + function New_Slice (Arr : O_Lnode; Res_Type : O_Tnode; Index : O_Enode) + return O_Lnode + is + subtype O_Lnode_Slice is O_Lnode_Type (OL_Slice); + Res : O_Lnode; + begin + if Res_Type.Kind /= ON_Array_Type + and then Res_Type.Kind /= ON_Array_Sub_Type + then + raise Type_Error; + end if; + Check_Ref (Arr); + Check_Ref (Index); + -- FIXME: check type. + Res := new O_Lnode_Slice'(Kind => OL_Slice, + Rtype => Res_Type, + Ref => False, + Slice_Base => Arr, + Slice_Index => Index); + return Res; + end New_Slice; + + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode + is + subtype O_Lnode_Selected_Element is O_Lnode_Type (OL_Selected_Element); + begin + if Rec.Rtype.Kind /= ON_Record_Type then + raise Type_Error; + end if; + if Rec.Rtype /= El.Parent then + raise Type_Error; + end if; + Check_Ref (Rec); + return new O_Lnode_Selected_Element'(Kind => OL_Selected_Element, + Rtype => El.Ftype, + Ref => False, + Rec_Base => Rec, + Rec_El => El); + end New_Selected_Element; + + function New_Access_Element (Acc : O_Enode) return O_Lnode + is + subtype O_Lnode_Access_Element is O_Lnode_Type (OL_Access_Element); + begin + if Acc.Rtype.Kind /= ON_Access_Type then + raise Type_Error; + end if; + Check_Ref (Acc); + return new O_Lnode_Access_Element'(Kind => OL_Access_Element, + Rtype => Acc.Rtype.D_Type, + Ref => False, + Acc_Base => Acc); + end New_Access_Element; + + function Check_Conv (Source : ON_Type_Kind; Target : ON_Type_Kind) + return Boolean + is + type Conv_Array is array (ON_Type_Kind, ON_Type_Kind) of Boolean; + T : constant Boolean := True; + F : constant Boolean := False; + Conv_Allowed : constant Conv_Array := + (ON_Boolean_Type => (T, F, T, T, F, F, F, F, F, F), + ON_Enum_Type => (F, F, T, T, F, F, F, F, F, F), + ON_Unsigned_Type => (T, T, T, T, F, F, F, F, F, F), + ON_Signed_Type => (T, T, T, T, T, F, F, F, F, F), + ON_Float_Type => (F, F, F, T, T, F, F, F, F, F), + ON_Array_Type => (F, F, F, F, F, F, T, F, F, F), + ON_Array_Sub_Type =>(F, F, F, F, F, T, T, F, F, F), + ON_Record_Type => (F, F, F, F, F, F, F, F, F, F), + ON_Union_Type => (F, F, F, F, F, F, F, F, F, F), + ON_Access_Type => (F, F, F, F, F, F, F, F, F, T)); + begin + if Source = Target then + return True; + else + return Conv_Allowed (Source, Target); + end if; + end Check_Conv; + + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode + is + subtype O_Enode_Convert is O_Enode_Type (OE_Convert_Ov); + Res : O_Enode; + begin + Check_Ref (Val); + if not Check_Conv (Val.Rtype.Kind, Rtype.Kind) then + raise Type_Error; + end if; + Res := new O_Enode_Convert'(Kind => OE_Convert_Ov, + Rtype => Rtype, + Ref => False, + Conv => Val); + return Res; + end New_Convert_Ov; + + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode + is + subtype O_Enode_Address is O_Enode_Type (OE_Unchecked_Address); + begin + Check_Ref (Lvalue); + if Atype.Kind /= ON_Access_Type then + -- An address is of type access. + raise Type_Error; + end if; + return new O_Enode_Address'(Kind => OE_Unchecked_Address, + Rtype => Atype, + Ref => False, + Lvalue => Lvalue); + end New_Unchecked_Address; + + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode + is + subtype O_Enode_Address is O_Enode_Type (OE_Address); + begin + Check_Ref (Lvalue); + if Atype.Kind /= ON_Access_Type then + -- An address is of type access. + raise Type_Error; + end if; + if Get_Base_Type (Lvalue.Rtype) /= Get_Base_Type (Atype.D_Type) then + if not Disable_Checks then + raise Type_Error; + end if; + end if; + return new O_Enode_Address'(Kind => OE_Address, + Rtype => Atype, + Ref => False, + Lvalue => Lvalue); + end New_Address; + + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode + is + subtype O_Cnode_Address is O_Cnode_Type (OC_Unchecked_Address); + begin + Check_Scope (Decl); + if Atype.Kind /= ON_Access_Type then + -- An address is of type access. + raise Type_Error; + end if; + return new O_Cnode_Address'(Kind => OC_Unchecked_Address, + Ctype => Atype, + Ref => False, + Decl => Decl); + end New_Global_Unchecked_Address; + + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) return O_Cnode + is + subtype O_Cnode_Address is O_Cnode_Type (OC_Address); + begin + Check_Scope (Decl); + if Atype.Kind /= ON_Access_Type then + -- An address is of type access. + raise Type_Error; + end if; + if Get_Base_Type (Decl.Dtype) /= Get_Base_Type (Atype.D_Type) then + raise Type_Error; + end if; + return new O_Cnode_Address'(Kind => OC_Address, + Ctype => Atype, + Ref => False, + Decl => Decl); + end New_Global_Address; + + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode + is + subtype O_Cnode_Subprg_Address is O_Cnode_Type (OC_Subprogram_Address); + begin + if Atype.Kind /= ON_Access_Type then + -- An address is of type access. + raise Type_Error; + end if; + return new O_Cnode_Subprg_Address'(Kind => OC_Subprogram_Address, + Ctype => Atype, + Ref => False, + Decl => Subprg); + end New_Subprogram_Address; + + -- Raise TYPE_ERROR is ATYPE is a composite type. + procedure Check_Not_Composite (Atype : O_Tnode) is + begin + case Atype.Kind is + when ON_Boolean_Type + | ON_Unsigned_Type + | ON_Signed_Type + | ON_Float_Type + | ON_Enum_Type + | ON_Access_Type=> + return; + when ON_Array_Type + | ON_Record_Type + | ON_Union_Type + | ON_Array_Sub_Type => + raise Type_Error; + end case; + end Check_Not_Composite; + + function New_Value (Lvalue : O_Lnode) return O_Enode is + subtype O_Enode_Value is O_Enode_Type (OE_Value); + begin + Check_Not_Composite (Lvalue.Rtype); + Check_Ref (Lvalue); + return new O_Enode_Value'(Kind => OE_Value, + Rtype => Lvalue.Rtype, + Ref => False, + Value => Lvalue); + end New_Value; + + function New_Obj_Value (Obj : O_Dnode) return O_Enode is + begin + return New_Value (New_Obj (Obj)); + end New_Obj_Value; + + function New_Lit (Lit : O_Cnode) return O_Enode is + subtype O_Enode_Lit is O_Enode_Type (OE_Lit); + begin + Check_Not_Composite (Lit.Ctype); + return new O_Enode_Lit'(Kind => OE_Lit, + Rtype => Lit.Ctype, + Ref => False, + Lit => Lit); + end New_Lit; + + --------------------- + -- Declarations. -- + --------------------- + + procedure New_Debug_Filename_Decl (Filename : String) + is + subtype O_Dnode_Filename_Decl is O_Dnode_Type (ON_Debug_Filename_Decl); + N : O_Dnode; + begin + N := new O_Dnode_Filename_Decl; + N.Filename := new String'(Filename); + Add_Decl (N, False); + end New_Debug_Filename_Decl; + + procedure New_Debug_Line_Decl (Line : Natural) + is + subtype O_Dnode_Line_Decl is O_Dnode_Type (ON_Debug_Line_Decl); + N : O_Dnode; + begin + N := new O_Dnode_Line_Decl; + N.Line := Line; + Add_Decl (N, False); + end New_Debug_Line_Decl; + + procedure New_Debug_Comment_Decl (Comment : String) + is + subtype O_Dnode_Comment_Decl is O_Dnode_Type (ON_Debug_Comment_Decl); + N : O_Dnode; + begin + N := new O_Dnode_Comment_Decl; + N.Comment := new String'(Comment); + Add_Decl (N, False); + end New_Debug_Comment_Decl; + + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode) + is + N : O_Dnode; + begin + if Atype.Decl /= null then + -- Type was already declared. + raise Type_Error; + end if; + N := new O_Dnode_Type (ON_Type_Decl); + N.Name := Ident; + N.Dtype := Atype; + Atype.Decl := N; + Add_Decl (N); + end New_Type_Decl; + + procedure Check_Object_Storage (Storage : O_Storage) is + begin + if Current_Function /= null then + -- Inside a subprogram. + case Storage is + when O_Storage_Public => + -- Cannot create public variables inside a subprogram. + raise Syntax_Error; + when O_Storage_Private + | O_Storage_Local + | O_Storage_External => + null; + end case; + else + -- Global scope. + case Storage is + when O_Storage_Public + | O_Storage_Private + | O_Storage_External => + null; + when O_Storage_Local => + -- Cannot create a local variables outside a subprogram. + raise Syntax_Error; + end case; + end if; + end Check_Object_Storage; + + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode) + is + subtype O_Dnode_Const is O_Dnode_Type (ON_Const_Decl); + begin + Check_Complete_Type (Atype); + if Storage = O_Storage_Local then + -- A constant cannot be local. + raise Syntax_Error; + end if; + Check_Object_Storage (Storage); + Res := new O_Dnode_Const'(Kind => ON_Const_Decl, + Name => Ident, + Next => null, + Dtype => Atype, + Storage => Storage, + Scope => Current_Decl_Scope.Parent, + Lineno => 0, + Const_Value => O_Dnode_Null); + Add_Decl (Res); + end New_Const_Decl; + + procedure Start_Const_Value (Const : in out O_Dnode) + is + subtype O_Dnode_Const_Value is O_Dnode_Type (ON_Const_Value); + N : O_Dnode; + begin + if Const.Const_Value /= O_Dnode_Null then + -- Constant already has a value. + raise Syntax_Error; + end if; + + if Const.Storage = O_Storage_External then + -- An external constant must not have a value. + raise Syntax_Error; + end if; + + -- FIXME: check scope is the same. + + N := new O_Dnode_Const_Value'(Kind => ON_Const_Value, + Name => Const.Name, + Next => null, + Dtype => Const.Dtype, + Storage => Const.Storage, + Scope => Current_Decl_Scope.Parent, + Lineno => 0, + Const_Decl => Const, + Value => O_Cnode_Null); + Const.Const_Value := N; + Add_Decl (N, False); + end Start_Const_Value; + + procedure Finish_Const_Value (Const : in out O_Dnode; Val : O_Cnode) + is + begin + if Const.Const_Value = O_Dnode_Null then + -- Start_Const_Value not called. + raise Syntax_Error; + end if; + if Const.Const_Value.Value /= O_Cnode_Null then + -- Finish_Const_Value already called. + raise Syntax_Error; + end if; + if Val = O_Cnode_Null then + -- No value or bad type. + raise Type_Error; + end if; + Check_Type (Val.Ctype, Const.Dtype); + Const.Const_Value.Value := Val; + end Finish_Const_Value; + + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode) + is + subtype O_Dnode_Var is O_Dnode_Type (ON_Var_Decl); + begin + Check_Complete_Type (Atype); + Check_Object_Storage (Storage); + Res := new O_Dnode_Var'(Kind => ON_Var_Decl, + Name => Ident, + Next => null, + Dtype => Atype, + Storage => Storage, + Lineno => 0, + Scope => Current_Decl_Scope.Parent); + Add_Decl (Res); + end New_Var_Decl; + + procedure Start_Subprogram_Decl_1 + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode) + is + subtype O_Dnode_Function is O_Dnode_Type (ON_Function_Decl); + N : O_Dnode; + begin + N := new O_Dnode_Function'(Kind => ON_Function_Decl, + Next => null, + Name => Ident, + Dtype => Rtype, + Storage => Storage, + Scope => Current_Decl_Scope.Parent, + Lineno => 0, + Interfaces => null, + Func_Body => null, + Alive => False); + Add_Decl (N); + Interfaces.Func := N; + Interfaces.Last := null; + end Start_Subprogram_Decl_1; + + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode) + is + begin + Check_Not_Composite (Rtype); + Check_Complete_Type (Rtype); + Start_Subprogram_Decl_1 (Interfaces, Ident, Storage, Rtype); + end Start_Function_Decl; + + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage) is + begin + Start_Subprogram_Decl_1 (Interfaces, Ident, Storage, null); + end Start_Procedure_Decl; + + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode) + is + subtype O_Dnode_Interface is O_Dnode_Type (ON_Interface_Decl); + begin + Check_Not_Composite (Atype); + Check_Complete_Type (Atype); + Res := new O_Dnode_Interface'(Kind => ON_Interface_Decl, + Next => null, + Name => Ident, + Dtype => Atype, + Storage => O_Storage_Private, + Scope => Current_Decl_Scope.Parent, + Lineno => 0, + Func_Scope => Interfaces.Func); + if Interfaces.Last = null then + Interfaces.Func.Interfaces := Res; + else + Interfaces.Last.Next := Res; + end if; + Interfaces.Last := Res; + end New_Interface_Decl; + + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode) + is + begin + Res := Interfaces.Func; + end Finish_Subprogram_Decl; + + procedure Start_Subprogram_Body (Func : O_Dnode) + is + B : O_Dnode; + S : O_Snode; + begin + if Func.Func_Body /= null then + -- Function was already declared. + raise Syntax_Error; + end if; + S := new O_Snode_Type (ON_Declare_Stmt); + S.all := O_Snode_Type'(Kind => ON_Declare_Stmt, + Next => null, + Decls => null, + Stmts => null, + Lineno => 0, + Alive => True); + B := new O_Dnode_Type (ON_Function_Body); + B.all := O_Dnode_Type'(ON_Function_Body, + Name => Func.Name, + Dtype => Func.Dtype, + Storage => Func.Storage, + Scope => Current_Decl_Scope.Parent, + Lineno => 0, + Func_Decl => Func, + Func_Stmt => S, + Next => null); + Add_Decl (B, False); + Func.Func_Body := B; + Push_Decl_Scope (S); + Push_Stmt_Scope + (new Stmt_Function_Scope_Type'(Kind => Stmt_Function, + Parent => S, + Prev => Current_Stmt_Scope, + Prev_Function => Current_Function, + Decl => Func)); + Current_Function := Current_Stmt_Scope; + Func.Alive := True; + end Start_Subprogram_Body; + + procedure Finish_Subprogram_Body is + begin + Pop_Decl_Scope; + if Current_Function.Kind /= Stmt_Function then + -- Internal error. + raise Syntax_Error; + end if; + Current_Function.Decl.Alive := False; + Current_Function := Current_Function.Prev_Function; + Pop_Stmt_Scope (Stmt_Function); + end Finish_Subprogram_Body; + + ------------------- + -- Statements. -- + ------------------- + + procedure New_Debug_Line_Stmt (Line : Natural) + is + subtype O_Snode_Line_Stmt is O_Snode_Type (ON_Debug_Line_Stmt); + begin + Add_Stmt (new O_Snode_Line_Stmt'(Kind => ON_Debug_Line_Stmt, + Next => null, + Lineno => 0, + Line => Line)); + end New_Debug_Line_Stmt; + + procedure New_Debug_Comment_Stmt (Comment : String) + is + subtype O_Snode_Comment_Stmt is O_Snode_Type (ON_Debug_Comment_Stmt); + begin + Add_Stmt (new O_Snode_Comment_Stmt'(Kind => ON_Debug_Comment_Stmt, + Next => null, + Lineno => 0, + Comment => new String'(Comment))); + end New_Debug_Comment_Stmt; + + procedure Start_Declare_Stmt + is + N : O_Snode; + begin + N := new O_Snode_Type (ON_Declare_Stmt); + Add_Stmt (N); + Push_Decl_Scope (N); + Push_Stmt_Scope + (new Stmt_Declare_Scope_Type'(Kind => Stmt_Declare, + Parent => N, + Prev => Current_Stmt_Scope)); + end Start_Declare_Stmt; + + procedure Finish_Declare_Stmt is + begin + Pop_Decl_Scope; + Pop_Stmt_Scope (Stmt_Declare); + end Finish_Declare_Stmt; + + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode) + is + N : O_Snode; + begin + Check_Type (Target.Rtype, Value.Rtype); + Check_Not_Composite (Target.Rtype); + Check_Ref (Target); + Check_Ref (Value); + N := new O_Snode_Type (ON_Assign_Stmt); + N.all := O_Snode_Type'(Kind => ON_Assign_Stmt, + Next => null, + Lineno => 0, + Target => Target, + Value => Value); + Add_Stmt (N); + end New_Assign_Stmt; + + procedure New_Return_Stmt_1 (Value : O_Enode) + is + subtype O_Snode_Return_Stmt is O_Snode_Type (ON_Return_Stmt); + N : O_Snode; + begin + N := new O_Snode_Return_Stmt'(Kind => ON_Return_Stmt, + Next => null, + Lineno => 0, + Ret_Val => Value); + Add_Stmt (N); + end New_Return_Stmt_1; + + procedure New_Return_Stmt (Value : O_Enode) + is + begin + if Current_Function = null + or else Current_Function.Decl.Dtype = O_Tnode_Null + then + -- Either not in a function or in a procedure. + raise Syntax_Error; + end if; + Check_Type (Value.Rtype, Current_Function.Decl.Dtype); + Check_Ref (Value); + New_Return_Stmt_1 (Value); + end New_Return_Stmt; + + procedure New_Return_Stmt is + begin + if Current_Function = null + or else Current_Function.Decl.Dtype /= O_Tnode_Null + then + -- Not in a procedure. + raise Syntax_Error; + end if; + New_Return_Stmt_1 (null); + end New_Return_Stmt; + + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode) + is + begin + Check_Scope (Subprg); + Assocs.Subprg := Subprg; + Assocs.Interfaces := Subprg.Interfaces; + Assocs.First := null; + Assocs.Last := null; + end Start_Association; + + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode) + is + N : O_Anode; + begin + Check_Type (Assocs.Interfaces.Dtype, Val.Rtype); + Check_Ref (Val); + N := new O_Anode_Type'(Next => null, + Formal => Assocs.Interfaces, Actual => Val); + Assocs.Interfaces := Assocs.Interfaces.Next; + if Assocs.Last = null then + Assocs.First := N; + else + Assocs.Last.Next := N; + end if; + Assocs.Last := N; + end New_Association; + + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode + is + subtype O_Enode_Call is O_Enode_Type (OE_Function_Call); + Res : O_Enode; + begin + if Assocs.Interfaces /= null then + -- Not enough arguments. + raise Syntax_Error; + end if; + if Assocs.Subprg.Dtype = null then + -- This is a procedure. + raise Syntax_Error; + end if; + + Res := new O_Enode_Call'(Kind => OE_Function_Call, + Rtype => Assocs.Subprg.Dtype, + Ref => False, + Func => Assocs.Subprg, + Assoc => Assocs.First); + return Res; + end New_Function_Call; + + procedure New_Procedure_Call (Assocs : in out O_Assoc_List) + is + N : O_Snode; + begin + if Assocs.Interfaces /= null then + -- Not enough arguments. + raise Syntax_Error; + end if; + if Assocs.Subprg.Dtype /= null then + -- This is a function. + raise Syntax_Error; + end if; + N := new O_Snode_Type (ON_Call_Stmt); + N.Proc := Assocs.Subprg; + N.Assoc := Assocs.First; + Add_Stmt (N); + end New_Procedure_Call; + + procedure New_Elsif_Stmt (Block : in out O_If_Block; Cond : O_Enode); + + procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode) + is + subtype O_Snode_If is O_Snode_Type (ON_If_Stmt); + N : O_Snode; + begin + -- Note: no checks are performed here, since they are done in + -- new_elsif_stmt. + N := new O_Snode_If'(Kind => ON_If_Stmt, + Next => null, + Lineno => 0, + Elsifs => null, + If_Last => null); + Add_Stmt (N); + Push_Stmt_Scope (new Stmt_If_Scope_Type'(Kind => Stmt_If, + Parent => N, + Prev => Current_Stmt_Scope, + Last_Elsif => null)); + New_Elsif_Stmt (Block, Cond); + end Start_If_Stmt; + + procedure New_Elsif_Stmt (Block : in out O_If_Block; Cond : O_Enode) + is + pragma Unreferenced (Block); + N : O_Snode; + begin + if Cond /= null then + if Cond.Rtype.Kind /= ON_Boolean_Type then + raise Type_Error; + end if; + Check_Ref (Cond); + end if; + N := new O_Snode_Type (ON_Elsif_Stmt); + N.all := O_Snode_Type'(Kind => ON_Elsif_Stmt, + Next => null, + Lineno => 0, + Cond => Cond, + Next_Elsif => null); + if Current_Stmt_Scope.Kind /= Stmt_If then + raise Syntax_Error; + end if; + Add_Stmt (N); + if Current_Stmt_Scope.Last_Elsif = null then + Current_Stmt_Scope.Parent.Elsifs := N; + else + -- Check for double 'else' + if Current_Stmt_Scope.Last_Elsif.Cond = null then + raise Syntax_Error; + end if; + Current_Stmt_Scope.Last_Elsif.Next_Elsif := N; + end if; + Current_Stmt_Scope.Last_Elsif := N; + end New_Elsif_Stmt; + + procedure New_Else_Stmt (Block : in out O_If_Block) is + begin + New_Elsif_Stmt (Block, null); + end New_Else_Stmt; + + procedure Finish_If_Stmt (Block : in out O_If_Block) + is + pragma Unreferenced (Block); + Parent : O_Snode; + begin + Parent := Current_Stmt_Scope.Parent; + Pop_Stmt_Scope (Stmt_If); + Parent.If_Last := Current_Decl_Scope.Last_Stmt; + end Finish_If_Stmt; + + procedure Start_Loop_Stmt (Label : out O_Snode) + is + subtype O_Snode_Loop_Type is O_Snode_Type (ON_Loop_Stmt); + begin + Current_Loop_Level := Current_Loop_Level + 1; + Label := new O_Snode_Loop_Type'(Kind => ON_Loop_Stmt, + Next => null, + Lineno => 0, + Loop_Last => null, + Loop_Level => Current_Loop_Level); + Add_Stmt (Label); + Push_Stmt_Scope (new Stmt_Loop_Scope_Type'(Kind => Stmt_Loop, + Parent => Label, + Prev => Current_Stmt_Scope)); + end Start_Loop_Stmt; + + procedure Finish_Loop_Stmt (Label : in out O_Snode) + is + pragma Unreferenced (Label); + Parent : O_Snode; + begin + Parent := Current_Stmt_Scope.Parent; + Pop_Stmt_Scope (Stmt_Loop); + Parent.Loop_Last := Current_Decl_Scope.Last_Stmt; + Current_Loop_Level := Current_Loop_Level - 1; + end Finish_Loop_Stmt; + + procedure New_Exit_Next_Stmt (Kind : ON_Stmt_Kind; L : O_Snode) + is + N : O_Snode; + begin + N := new O_Snode_Type (Kind); + N.Next := null; + N.Loop_Id := L; + Add_Stmt (N); + end New_Exit_Next_Stmt; + + procedure New_Exit_Stmt (L : O_Snode) is + begin + New_Exit_Next_Stmt (ON_Exit_Stmt, L); + end New_Exit_Stmt; + + procedure New_Next_Stmt (L : O_Snode) is + begin + New_Exit_Next_Stmt (ON_Next_Stmt, L); + end New_Next_Stmt; + + procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode) + is + subtype O_Snode_Case_Type is O_Snode_Type (ON_Case_Stmt); + N : O_Snode; + begin + case Value.Rtype.Kind is + when ON_Boolean_Type + | ON_Unsigned_Type + | ON_Signed_Type + | ON_Enum_Type => + null; + when others => + raise Type_Error; + end case; + Check_Ref (Value); + N := new O_Snode_Case_Type'(Kind => ON_Case_Stmt, + Next => null, + Lineno => 0, + Case_Last => null, + Selector => Value, + Branches => null); + Block.Case_Stmt := N; + Add_Stmt (N); + Push_Stmt_Scope (new Stmt_Case_Scope_Type'(Kind => Stmt_Case, + Parent => N, + Prev => Current_Stmt_Scope, + Last_Branch => null, + Last_Choice => null, + Case_Type => Value.Rtype)); + end Start_Case_Stmt; + + procedure Start_Choice (Block : in out O_Case_Block) + is + N : O_Snode; + begin + if Current_Stmt_Scope.Kind /= Stmt_Case then + -- You are adding a branch outside a case statment. + raise Syntax_Error; + end if; + if Current_Stmt_Scope.Last_Choice /= null then + -- You are creating branch while the previous one was not finished. + raise Syntax_Error; + end if; + + N := new O_Snode_Type (ON_When_Stmt); + N.all := O_Snode_Type'(Kind => ON_When_Stmt, + Next => null, + Lineno => 0, + Branch_Parent => Block.Case_Stmt, + Choice_List => null, + Next_Branch => null); + if Current_Stmt_Scope.Last_Branch = null then + Current_Stmt_Scope.Parent.Branches := N; + else + Current_Stmt_Scope.Last_Branch.Next_Branch := N; + end if; + Current_Stmt_Scope.Last_Branch := N; + Current_Stmt_Scope.Last_Choice := null; + Add_Stmt (N); + end Start_Choice; + + procedure Add_Choice (Block : in out O_Case_Block; Choice : O_Choice) + is + pragma Unreferenced (Block); + begin + if Current_Stmt_Scope.Kind /= Stmt_Case then + -- You are adding a choice not inside a case statement. + raise Syntax_Error; + end if; + if Current_Stmt_Scope.Last_Branch = null then + -- You are not inside a branch. + raise Syntax_Error; + end if; + if Current_Stmt_Scope.Last_Choice = null then + if Current_Stmt_Scope.Last_Branch.Choice_List /= null then + -- The branch was already closed. + raise Syntax_Error; + end if; + Current_Stmt_Scope.Last_Branch.Choice_List := Choice; + else + Current_Stmt_Scope.Last_Choice.Next := Choice; + end if; + Current_Stmt_Scope.Last_Choice := Choice; + end Add_Choice; + + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode) + is + N : O_Choice; + begin + if Current_Stmt_Scope.Kind /= Stmt_Case then + -- You are creating a choice not inside a case statement. + raise Syntax_Error; + end if; + if Current_Stmt_Scope.Case_Type /= Expr.Ctype then + -- Expr type is not the same as choice type. + raise Type_Error; + end if; + + N := new O_Choice_Type (ON_Choice_Expr); + N.all := O_Choice_Type'(Kind => ON_Choice_Expr, + Next => null, + Expr => Expr); + Add_Choice (Block, N); + end New_Expr_Choice; + + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode) + is + N : O_Choice; + begin + if Current_Stmt_Scope.Kind /= Stmt_Case then + -- You are creating a choice not inside a case statement. + raise Syntax_Error; + end if; + if Current_Stmt_Scope.Case_Type /= Low.Ctype + or Current_Stmt_Scope.Case_Type /= High.Ctype + then + -- Low/High type is not the same as choice type. + raise Type_Error; + end if; + + N := new O_Choice_Type (ON_Choice_Range); + N.all := O_Choice_Type'(Kind => ON_Choice_Range, + Next => null, + Low => Low, + High => High); + Add_Choice (Block, N); + end New_Range_Choice; + + procedure New_Default_Choice (Block : in out O_Case_Block) + is + N : O_Choice; + begin + if Current_Stmt_Scope.Kind /= Stmt_Case then + -- You are creating a choice not inside a case statement. + raise Syntax_Error; + end if; + + N := new O_Choice_Type (ON_Choice_Default); + N.all := O_Choice_Type'(Kind => ON_Choice_Default, + Next => null); + Add_Choice (Block, N); + end New_Default_Choice; + + procedure Finish_Choice (Block : in out O_Case_Block) + is + pragma Unreferenced (Block); + begin + if Current_Stmt_Scope.Kind /= Stmt_Case then + -- You are adding a choice not inside a case statement. + raise Syntax_Error; + end if; + if Current_Stmt_Scope.Last_Branch = null then + -- You are not inside a branch. + raise Syntax_Error; + end if; + if Current_Stmt_Scope.Last_Choice = null then + -- The branch is empty or you are not inside a branch. + raise Syntax_Error; + end if; + Current_Stmt_Scope.Last_Choice := null; + end Finish_Choice; + + procedure Finish_Case_Stmt (Block : in out O_Case_Block) + is + pragma Unreferenced (Block); + Parent : O_Snode; + begin + Parent := Current_Stmt_Scope.Parent; + Pop_Stmt_Scope (Stmt_Case); + Parent.Case_Last := Current_Decl_Scope.Last_Stmt; + end Finish_Case_Stmt; + + procedure Init is + begin + Top := new O_Snode_Type (ON_Declare_Stmt); + Push_Decl_Scope (Top); + end Init; + + procedure Finish is + begin + Pop_Decl_Scope; + end Finish; +end Ortho_Debug; diff --git a/src/ortho/debug/ortho_debug.private.ads b/src/ortho/debug/ortho_debug.private.ads new file mode 100644 index 000000000..69ee16cf7 --- /dev/null +++ b/src/ortho/debug/ortho_debug.private.ads @@ -0,0 +1,467 @@ +-- Ortho debug back-end declarations. +-- Copyright (C) 2005-2014 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 Interfaces; use Interfaces; +with Ortho_Ident; +use Ortho_Ident; + +-- Interface to create nodes. +package Ortho_Debug is + procedure Init; + procedure Finish; + +private + -- This back-end supports nested subprograms. + Has_Nested_Subprograms : constant Boolean := True; + + -- A node for a type. + type O_Tnode_Type (<>); + type O_Tnode is access O_Tnode_Type; + + -- A node for a statement. + type O_Snode_Type (<>); + type O_Snode is access O_Snode_Type; + + Top : O_Snode; + + type Str_Acc is access String; + + type Decl_Scope_Type; + type Decl_Scope_Acc is access Decl_Scope_Type; + + type On_Decl_Kind is + (ON_Type_Decl, ON_Completed_Type_Decl, + ON_Const_Decl, ON_Var_Decl, ON_Interface_Decl, + ON_Function_Decl, ON_Function_Body, + ON_Const_Value, + ON_Debug_Line_Decl, ON_Debug_Comment_Decl, ON_Debug_Filename_Decl); + + type O_Dnode_Type (<>); + type O_Dnode is access O_Dnode_Type; + + O_Dnode_Null : constant O_Dnode := null; + + type O_Dnode_Type (Kind : On_Decl_Kind) is record + Next : O_Dnode; + Name : O_Ident; + Dtype : O_Tnode; + Storage : O_Storage; + -- Declare statement in which the declaration appears. + Scope : O_Snode; + -- Line number, for regen. + Lineno : Natural; + case Kind is + when ON_Type_Decl => + null; + when ON_Completed_Type_Decl => + null; + when ON_Const_Decl => + Const_Value : O_Dnode; + when ON_Const_Value => + Const_Decl : O_Dnode; + Value : O_Cnode; + when ON_Var_Decl => + null; + when ON_Function_Decl => + Interfaces : O_Dnode; + Func_Body : O_Dnode; + Alive : Boolean; + when ON_Function_Body => + Func_Decl : O_Dnode; + Func_Stmt : O_Snode; + when ON_Interface_Decl => + Func_Scope : O_Dnode; + when ON_Debug_Line_Decl => + Line : Natural; + when ON_Debug_Comment_Decl => + Comment : Str_Acc; + when ON_Debug_Filename_Decl => + Filename : Str_Acc; + end case; + end record; + + -- A node for a record element. + type O_Fnode_Type; + type O_Fnode is access O_Fnode_Type; + + O_Fnode_Null : constant O_Fnode := null; + + type O_Fnode_Type is record + -- Record type. + Parent : O_Tnode; + -- Next field in the record. + Next : O_Fnode; + -- Name of the record field. + Ident : O_Ident; + -- Type of the record field. + Ftype : O_Tnode; + -- Offset in the field. + Offset : Unsigned_32; + end record; + + type O_Anode_Type; + type O_Anode is access O_Anode_Type; + type O_Anode_Type is record + Next : O_Anode; + Formal : O_Dnode; + Actual : O_Enode; + end record; + + type OC_Kind is + ( + OC_Boolean_Lit, + OC_Unsigned_Lit, + OC_Signed_Lit, + OC_Float_Lit, + OC_Enum_Lit, + OC_Null_Lit, + OC_Sizeof_Lit, + OC_Alignof_Lit, + OC_Offsetof_Lit, + OC_Aggregate, + OC_Aggr_Element, + OC_Union_Aggr, + OC_Address, + OC_Unchecked_Address, + OC_Subprogram_Address + ); + type O_Cnode_Type (Kind : OC_Kind) is record + -- Type of the constant. + Ctype : O_Tnode; + -- True if referenced. + Ref : Boolean; + case Kind is + when OC_Unsigned_Lit => + U_Val : Unsigned_64; + when OC_Signed_Lit => + S_Val : Integer_64; + when OC_Float_Lit => + F_Val : IEEE_Float_64; + when OC_Boolean_Lit => + B_Val : Boolean; + B_Id : O_Ident; + when OC_Enum_Lit => + E_Val : Integer; + E_Next : O_Cnode; + E_Name : O_Ident; + when OC_Null_Lit => + null; + when OC_Sizeof_Lit + | OC_Alignof_Lit => + S_Type : O_Tnode; + when OC_Offsetof_Lit => + Off_Field : O_Fnode; + when OC_Aggregate => + Aggr_Els : O_Cnode; + when OC_Union_Aggr => + Uaggr_Field : O_Fnode; + Uaggr_Value : O_Cnode; + when OC_Aggr_Element => + Aggr_Value : O_Cnode; + Aggr_Next : O_Cnode; + when OC_Address + | OC_Unchecked_Address + | OC_Subprogram_Address => + Decl : O_Dnode; + end case; + end record; + + type O_Cnode is access O_Cnode_Type; + O_Cnode_Null : constant O_Cnode := null; + + type OE_Kind is + ( + -- Literals. + OE_Lit, + + -- Dyadic operations. + OE_Add_Ov, -- OE_Dyadic_Op_Kind + OE_Sub_Ov, -- OE_Dyadic_Op_Kind + OE_Mul_Ov, -- OE_Dyadic_Op_Kind + OE_Div_Ov, -- OE_Dyadic_Op_Kind + OE_Rem_Ov, -- OE_Dyadic_Op_Kind + OE_Mod_Ov, -- OE_Dyadic_Op_Kind + OE_Exp_Ov, -- OE_Dyadic_Op_Kind + + -- Binary operations. + OE_And, -- OE_Dyadic_Op_Kind + OE_Or, -- OE_Dyadic_Op_Kind + OE_Xor, -- OE_Dyadic_Op_Kind + OE_And_Then, -- OE_Dyadic_Op_Kind + OE_Or_Else, -- OE_Dyadic_Op_Kind + + -- Monadic operations. + OE_Not, -- OE_Monadic_Op_Kind + OE_Neg_Ov, -- OE_Monadic_Op_Kind + OE_Abs_Ov, -- OE_Monadic_Op_Kind + + -- Comparaisons + OE_Eq, -- OE_Compare_Op_Kind + OE_Neq, -- OE_Compare_Op_Kind + OE_Le, -- OE_Compare_Op_Kind + OE_Lt, -- OE_Compare_Op_Kind + OE_Ge, -- OE_Compare_Op_Kind + OE_Gt, -- OE_Compare_Op_Kind + + -- Misc. + OE_Convert_Ov, + OE_Address, + OE_Unchecked_Address, + OE_Alloca, + OE_Function_Call, + + OE_Value, + OE_Nil + ); + + subtype OE_Dyadic_Expr_Kind is OE_Kind range OE_Add_Ov .. OE_Or_Else; + subtype OE_Monadic_Expr_Kind is OE_Kind range OE_Not .. OE_Abs_Ov; + subtype OE_Compare_Expr_Kind is OE_Kind range OE_Eq .. OE_Gt; + + type O_Enode_Type (Kind : OE_Kind); + type O_Enode is access O_Enode_Type; + O_Enode_Null : constant O_Enode := null; + + type O_Enode_Type (Kind : OE_Kind) is record + -- Type of the result. + Rtype : O_Tnode; + -- True if referenced. + Ref : Boolean; + case Kind is + when OE_Dyadic_Expr_Kind + | OE_Compare_Expr_Kind => + Left : O_Enode; + Right : O_Enode; + when OE_Monadic_Expr_Kind => + Operand : O_Enode; + when OE_Lit => + Lit : O_Cnode; + when OE_Address + | OE_Unchecked_Address => + Lvalue : O_Lnode; + when OE_Convert_Ov => + Conv : O_Enode; + when OE_Function_Call => + Func : O_Dnode; + Assoc : O_Anode; + when OE_Value => + Value : O_Lnode; + when OE_Alloca => + A_Size : O_Enode; + when OE_Nil => + null; + end case; + end record; + type O_Enode_Array is array (Natural range <>) of O_Enode; + type O_Enode_Array_Acc is access O_Enode_Array; + + type OL_Kind is + ( + -- Name. + OL_Obj, + OL_Indexed_Element, + OL_Slice, + OL_Selected_Element, + OL_Access_Element + + -- Variable, constant, parameter reference. + -- This allows to read/write a declaration. + --OL_Var_Ref, + --OL_Const_Ref, + --OL_Param_Ref + ); + + type O_Lnode_Type (Kind : OL_Kind); + type O_Lnode is access O_Lnode_Type; + O_Lnode_Null : constant O_Lnode := null; + + type O_Lnode_Type (Kind : OL_Kind) is record + -- Type of the result. + Rtype : O_Tnode; + -- True if referenced. + Ref : Boolean; + case Kind is + when OL_Obj => + Obj : O_Dnode; + when OL_Indexed_Element => + Array_Base : O_Lnode; + Index : O_Enode; + when OL_Slice => + Slice_Base : O_Lnode; + Slice_Index : O_Enode; + when OL_Selected_Element => + Rec_Base : O_Lnode; + Rec_El : O_Fnode; + when OL_Access_Element => + Acc_Base : O_Enode; +-- when OL_Var_Ref +-- | OL_Const_Ref +-- | OL_Param_Ref => +-- Decl : O_Dnode; + end case; + end record; + + O_Tnode_Null : constant O_Tnode := null; + type ON_Type_Kind is + (ON_Boolean_Type, ON_Enum_Type, + ON_Unsigned_Type, ON_Signed_Type, ON_Float_Type, ON_Array_Type, + ON_Array_Sub_Type, ON_Record_Type, ON_Union_Type, ON_Access_Type); + type O_Tnode_Type (Kind : ON_Type_Kind) is record + Decl : O_Dnode; + -- True if the type was first created as an uncomplete type. + Uncomplete : Boolean; + -- True if the type is complete. + Complete : Boolean; + case Kind is + when ON_Boolean_Type => + True_N : O_Cnode; + False_N : O_Cnode; + when ON_Unsigned_Type + | ON_Signed_Type => + Int_Size : Natural; + when ON_Float_Type => + null; + when ON_Enum_Type => + Nbr : Natural; + Literals: O_Cnode; + when ON_Array_Type => + El_Type : O_Tnode; + Index_Type : O_Tnode; + when ON_Access_Type => + D_Type : O_Tnode; + when ON_Record_Type + | ON_Union_Type => + Elements : O_Fnode; + when ON_Array_Sub_Type => + Length : O_Cnode; + Base_Type : O_Tnode; + end case; + end record; + + type ON_Choice_Kind is (ON_Choice_Expr, ON_Choice_Range, ON_Choice_Default); + type O_Choice_Type (Kind : ON_Choice_Kind); + type O_Choice is access O_Choice_Type; + type O_Choice_Type (Kind : ON_Choice_Kind) is record + Next : O_Choice; + case Kind is + when ON_Choice_Expr => + Expr : O_Cnode; + when ON_Choice_Range => + Low, High : O_Cnode; + when ON_Choice_Default => + null; + end case; + end record; + + O_Snode_Null : constant O_Snode := null; + type ON_Stmt_Kind is + (ON_Declare_Stmt, ON_Assign_Stmt, ON_Return_Stmt, ON_If_Stmt, + ON_Elsif_Stmt, ON_Loop_Stmt, ON_Exit_Stmt, ON_Next_Stmt, + ON_Case_Stmt, ON_When_Stmt, ON_Call_Stmt, + ON_Debug_Line_Stmt, ON_Debug_Comment_Stmt); + type O_Snode_Type (Kind : ON_Stmt_Kind) is record + Next : O_Snode; + Lineno : Natural; + case Kind is + when ON_Declare_Stmt => + Decls : O_Dnode; + Stmts : O_Snode; + -- True if the statement is currently open. + Alive : Boolean; + when ON_Assign_Stmt => + Target : O_Lnode; + Value : O_Enode; + when ON_Return_Stmt => + Ret_Val : O_Enode; + when ON_If_Stmt => + Elsifs : O_Snode; + If_Last : O_Snode; + when ON_Elsif_Stmt => + Cond : O_Enode; + Next_Elsif : O_Snode; + when ON_Loop_Stmt => + Loop_Last : O_Snode; + Loop_Level : Natural; + when ON_Exit_Stmt + | ON_Next_Stmt => + Loop_Id : O_Snode; + when ON_Case_Stmt => + Selector : O_Enode; + -- Simply linked list of branches + Branches : O_Snode; + Case_Last : O_Snode; + when ON_When_Stmt => + -- The corresponding 'case' + Branch_Parent : O_Snode; + Choice_List : O_Choice; + Next_Branch : O_Snode; + when ON_Call_Stmt => + Proc : O_Dnode; + Assoc : O_Anode; + when ON_Debug_Line_Stmt => + Line : Natural; + when ON_Debug_Comment_Stmt => + Comment : Str_Acc; + end case; + end record; + + type O_Inter_List is record + Func : O_Dnode; + Last : O_Dnode; + end record; + + type O_Element_List is record + -- The type definition. + Res : O_Tnode; + -- The last element added. + Last : O_Fnode; + end record; + + type O_Record_Aggr_List is record + Res : O_Cnode; + Last : O_Cnode; + Field : O_Fnode; + end record; + + type O_Array_Aggr_List is record + Res : O_Cnode; + Last : O_Cnode; + El_Type : O_Tnode; + end record; + + type O_Assoc_List is record + Subprg : O_Dnode; + Interfaces : O_Dnode; + First, Last : O_Anode; + end record; + + type O_Enum_List is record + -- The type built. + Res : O_Tnode; + + -- the chain of declarations. + Last : O_Cnode; + end record; + type O_Case_Block is record + Case_Stmt : O_Snode; + end record; + + type O_If_Block is record + null; + end record; +end Ortho_Debug; diff --git a/src/ortho/debug/ortho_debug_front.ads b/src/ortho/debug/ortho_debug_front.ads new file mode 100644 index 000000000..17e32c9ed --- /dev/null +++ b/src/ortho/debug/ortho_debug_front.ads @@ -0,0 +1,20 @@ +-- Ortho debug interface with front-end. +-- Copyright (C) 2005 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 Ortho_Front; +package Ortho_Debug_Front renames Ortho_Front; diff --git a/src/ortho/debug/ortho_ident.ads b/src/ortho/debug/ortho_ident.ads new file mode 100644 index 000000000..46aa8854d --- /dev/null +++ b/src/ortho/debug/ortho_ident.ads @@ -0,0 +1,20 @@ +-- Ortho debug back-end interface with identifiers package. +-- Copyright (C) 2005 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 Ortho_Ident_Simple; +package Ortho_Ident renames Ortho_Ident_Simple; diff --git a/src/ortho/debug/ortho_ident_hash.adb b/src/ortho/debug/ortho_ident_hash.adb new file mode 100644 index 000000000..60ab89586 --- /dev/null +++ b/src/ortho/debug/ortho_ident_hash.adb @@ -0,0 +1,72 @@ +-- Ortho debug hashed identifiers implementation. +-- Copyright (C) 2005 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. + +package body Ortho_Ident_Hash is + type O_Ident_Array is array (Hash_Type range <>) of O_Ident; + Hash_Max : constant Hash_Type := 511; + Symtable : O_Ident_Array (0 .. Hash_Max - 1) := (others => null); + + function Get_Identifier (Str : String) return O_Ident + is + Hash : Hash_Type; + Ent : Hash_Type; + Res : O_Ident; + begin + -- 1. Compute Hash. + Hash := 0; + for I in Str'Range loop + Hash := Hash * 31 + Character'Pos (Str (I)); + end loop; + + -- 2. Search. + Ent := Hash mod Hash_Max; + Res := Symtable (Ent); + while Res /= null loop + if Res.Hash = Hash and then Res.Ident.all = Str then + return Res; + end if; + Res := Res.Next; + end loop; + + -- Not found: add. + Res := new Ident_Type'(Hash => Hash, + Ident => new String'(Str), + Next => Symtable (Ent)); + Symtable (Ent) := Res; + return Res; + end Get_Identifier; + + function Get_String (Id : O_Ident) return String is + begin + if Id = null then + return "?ANON?"; + else + return Id.Ident.all; + end if; + end Get_String; + + function Is_Nul (Id : O_Ident) return Boolean is + begin + return Id = null; + end Is_Nul; + + function Is_Equal (Id : O_Ident; Str : String) return Boolean is + begin + return Id.Ident.all = Str; + end Is_Equal; +end Ortho_Ident_Hash; diff --git a/src/ortho/debug/ortho_ident_hash.ads b/src/ortho/debug/ortho_ident_hash.ads new file mode 100644 index 000000000..a6e4a56cc --- /dev/null +++ b/src/ortho/debug/ortho_ident_hash.ads @@ -0,0 +1,46 @@ +-- Ortho debug hashed identifiers implementation. +-- Copyright (C) 2005 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. + +package Ortho_Ident_Hash is + type O_Ident is private; + O_Ident_Nul : constant O_Ident; + + function Get_Identifier (Str : String) return O_Ident; + function Get_String (Id : O_Ident) return String; + function Is_Equal (L, R : O_Ident) return Boolean renames "="; + function Is_Equal (Id : O_Ident; Str : String) return Boolean; + function Is_Nul (Id : O_Ident) return Boolean; +private + type Hash_Type is mod 2**32; + + type String_Acc is access constant String; + + -- Symbol table. + type Ident_Type; + type O_Ident is access Ident_Type; + type Ident_type is record + -- The hash for the symbol. + Hash : Hash_Type; + -- Identification of the symbol. + Ident : String_Acc; + -- Next symbol with the same collision. + Next : O_Ident; + end record; + + O_Ident_Nul : constant O_Ident := null; +end Ortho_Ident_Hash; diff --git a/src/ortho/debug/ortho_ident_simple.adb b/src/ortho/debug/ortho_ident_simple.adb new file mode 100644 index 000000000..83b9756f8 --- /dev/null +++ b/src/ortho/debug/ortho_ident_simple.adb @@ -0,0 +1,44 @@ +-- Ortho debug identifiers simple implementation. +-- Copyright (C) 2005 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. + +package body Ortho_Ident_Simple is + function Get_Identifier (Str : String) return O_Ident + is + begin + return new String'(Str); + end Get_Identifier; + + function Get_String (Id : O_Ident) return String is + begin + if Id = null then + return "?ANON?"; + else + return Id.all; + end if; + end Get_String; + + function Is_Nul (Id : O_Ident) return Boolean is + begin + return Id = null; + end Is_Nul; + + function Is_Equal (Id : O_Ident; Str : String) return Boolean is + begin + return Id.all = Str; + end Is_Equal; +end Ortho_Ident_Simple; diff --git a/src/ortho/debug/ortho_ident_simple.ads b/src/ortho/debug/ortho_ident_simple.ads new file mode 100644 index 000000000..f94fe1938 --- /dev/null +++ b/src/ortho/debug/ortho_ident_simple.ads @@ -0,0 +1,31 @@ +-- Ortho debug identifiers simple implementation. +-- Copyright (C) 2005 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. + +package Ortho_Ident_Simple is + type O_Ident is private; + O_Ident_Nul : constant O_Ident; + + function Get_Identifier (Str : String) return O_Ident; + function Get_String (Id : O_Ident) return String; + function Is_Equal (L, R : O_Ident) return Boolean renames "="; + function Is_Equal (Id : O_Ident; Str : String) return Boolean; + function Is_Nul (Id : O_Ident) return Boolean; +private + type O_Ident is access String; + O_Ident_Nul : constant O_Ident := null; +end Ortho_Ident_Simple; diff --git a/src/ortho/debug/ortho_nodes.ads b/src/ortho/debug/ortho_nodes.ads new file mode 100644 index 000000000..8ade66722 --- /dev/null +++ b/src/ortho/debug/ortho_nodes.ads @@ -0,0 +1,21 @@ +-- Ortho debug back-end interface with front-end. +-- Copyright (C) 2005 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 Ortho_Debug; + +package Ortho_Nodes renames Ortho_Debug; diff --git a/src/ortho/gcc/Makefile b/src/ortho/gcc/Makefile new file mode 100644 index 000000000..5aafb31c7 --- /dev/null +++ b/src/ortho/gcc/Makefile @@ -0,0 +1,86 @@ +ortho_srcdir=.. +orthobe_srcdir=$(ortho_srcdir)/gcc +agcc_objdir=. +agcc_srcdir=$(ortho_srcdir)/gcc +SED=sed +BE=gcc +GNATMAKE=gnatmake +CC=gcc +CXX=g++ +COMPILER=$(CXX) +LINKER=$(CXX) + +# Modify AGCC_GCCSRC_DIR and AGCC_GCCOBJ_DIR for your environment +AGCC_GCCSRC_DIR:=$(HOME)/Projects/gcc4.9.2/source/gcc-4.9.2/ +AGCC_GCCOBJ_DIR:=$(HOME)/Projects/gcc4.9.2/build/ + +# Supplied by main GCC Makefile, copied here for compatibility with same +GMPLIBS = -L$(AGCC_GCCOBJ_DIR)./gmp/.libs -L$(AGCC_GCCOBJ_DIR)./mpfr/.libs \ + -L$(AGCC_GCCOBJ_DIR)./mpc/src/.libs -lmpc -lmpfr -lgmp +GMPINC = -I$(AGCC_GCCOBJ_DIR)./gmp -I$(AGCC_GCCSRC_DIR)/gmp \ + -I$(AGCC_GCCOBJ_DIR)./mpfr -I$(AGCC_GCCSRC_DIR)/mpfr \ + -I$(AGCC_GCCSRC_DIR)/mpc/src + +HOST_LIBS = +ZLIB=-lz + +# Override variables in Makefile.conf for your environment +-include $(orthobe_srcdir)/Makefile.conf + +all: $(ortho_exec) + +ORTHO_BASENAME=ortho_gcc +include $(ortho_srcdir)/Makefile.inc + +AGCC_INC_FLAGS=-I$(AGCC_GCCOBJ_DIR)/gcc -I$(AGCC_GCCSRC_DIR)/include \ + -I$(AGCC_GCCSRC_DIR)/gcc -I$(AGCC_GCCSRC_DIR)/gcc/config \ + -I$(AGCC_GCCSRC_DIR)/libcpp/include $(GMPINC) +AGCC_CFLAGS=-g -Wall -DIN_GCC $(AGCC_INC_FLAGS) + +ortho-lang.o: $(agcc_srcdir)/ortho-lang.c \ + $(AGCC_GCCOBJ_DIR)gcc/gtype-vhdl.h \ + $(AGCC_GCCOBJ_DIR)gcc/gt-vhdl-ortho-lang.h + $(COMPILER) -c -o $@ $< $(AGCC_CFLAGS) $(INCLUDES) + +AGCC_LOCAL_OBJS=ortho-lang.o + +AGCC_DEPS := $(AGCC_LOCAL_OBJS) +AGCC_OBJS := $(AGCC_LOCAL_OBJS) \ + $(AGCC_GCCOBJ_DIR)gcc/attribs.o \ + $(AGCC_GCCOBJ_DIR)libcpp/libcpp.a \ + $(AGCC_GCCOBJ_DIR)libiberty/libiberty.a + +LIBBACKTRACE = $(AGCC_GCCOBJ_DIR)/libbacktrace/.libs/libbacktrace.a +LIBDECNUMBER = $(AGCC_GCCOBJ_DIR)/libdecnumber/libdecnumber.a +LIBIBERTY = $(AGCC_GCCOBJ_DIR)/libiberty/libiberty.a +CPPLIB= # Not needed for GHDL + +BACKEND = $(AGCC_GCCOBJ_DIR)/gcc/libbackend.a \ + $(AGCC_GCCOBJ_DIR)/gcc/libcommon-target.a + +BACKENDLIBS = $(CLOOGLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) \ + $(ZLIB) +LIBS = $(AGCC_GCCOBJ_DIR)/gcc/libcommon.a \ + $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBBACKTRACE) \ + $(LIBIBERTY) $(LIBDECNUMBER) $(HOST_LIBS) + +$(ortho_exec): $(AGCC_DEPS) $(orthobe_srcdir)/ortho_gcc.ads force + $(GNATMAKE) -m -o $@ -g -aI$(ortho_srcdir) \ + -aI$(ortho_srcdir)/gcc $(GNAT_FLAGS) ortho_gcc-main \ + -bargs -E -largs --LINK=$(LINKER) $(AGCC_OBJS) \ + $(BACKEND) $(LIBS) $(BACKENDLIBS) + +agcc-clean: force + $(RM) -f $(agcc_objdir)/*.o + $(RM) -f $(agcc_srcdir)/*~ + +clean: agcc-clean + $(RM) -f *.o *.ali ortho_nodes-main + $(RM) b~*.ad? *~ + +distclean: clean agcc-clean + + +force: + +.PHONY: force all clean agcc-clean diff --git a/src/ortho/gcc/Makefile.conf.linux b/src/ortho/gcc/Makefile.conf.linux new file mode 100644 index 000000000..00ea91728 --- /dev/null +++ b/src/ortho/gcc/Makefile.conf.linux @@ -0,0 +1,4 @@ +# Example Makefile.conf +# Copy this file to Makefile.conf and edit as necessary for your platform + +HOST_LIBS = -ldl -lstdc++ diff --git a/src/ortho/gcc/lang.opt b/src/ortho/gcc/lang.opt new file mode 100644 index 000000000..562fbe08d --- /dev/null +++ b/src/ortho/gcc/lang.opt @@ -0,0 +1,96 @@ +Language +vhdl + +-std= +vhdl Joined +Select the vhdl standard + +-compile-standard +vhdl +Used during compiler build to compile the std.standard package + +-bootstrap +vhdl +Used during compiler build to compile std packages + +-work= +vhdl Joined +Set the name of the work library + +-workdir= +vhdl Joined +Set the directory of the work library + +P +vhdl JoinedOrMissing +;-P<dir> Add <dir> to the end of the vhdl library path + +-elab +vhdl Separate +--elab <name> Used internally during elaboration of <name> + +-anaelab +vhdl Separate +--anaelab <name> Used internally during elaboration of <name> + +; -c is a driver option for gcc. --ghdl-source is used instead. +;c +;vhdl Separate +;-c <filename> Analyze <filename> for --anaelab + +;v +;vhdl +;Verbose + +-warn- +vhdl Joined +--warn-<name> Warn about <name> + +-ghdl +vhdl Joined +--ghdl-<option> Pass <option> to vhdl front-end + +-expect-failure +vhdl +Expect a compiler error (used for testsuite) + +-no-vital-checks +vhdl +Disable VITAL checks + +-vital-checks +vhdl +Enable VITAL checks + +fexplicit +vhdl +Explicit function declarations override implicit one in use + +frelaxed-rules +vhdl +Relax some LRM rules to compile vendor libraries + +fpsl +vhdl +Allow PSL asserts in comments + +-no-direct-drivers +vhdl +Disable direct drivers optimization + +-syn-binding +vhdl +Use synthetizer rules for default bindings + +l +vhdl Joined Separate +-l<filename> Put list of files for link in <filename> + +; -C was commented out, as it is already defined for C/C++. +;C +;vhdl +;Allow any character in comments + +-mb-comments +vhdl +Allow any character in comments diff --git a/src/ortho/gcc/ortho-lang.c b/src/ortho/gcc/ortho-lang.c new file mode 100644 index 000000000..c19012e6e --- /dev/null +++ b/src/ortho/gcc/ortho-lang.c @@ -0,0 +1,2191 @@ +/* GCC back-end for ortho + Copyright (C) 2002-1014 Tristan Gingold and al. + + 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. */ + +#include <stddef.h> +#include <math.h> +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tm_p.h" +#include "defaults.h" +#include "ggc.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "toplev.h" +#include "opts.h" +#include "options.h" +#include "real.h" +#include "tree-iterator.h" +#include "function.h" +#include "cgraph.h" +#include "target.h" +#include "convert.h" +#include "tree-pass.h" +#include "tree-dump.h" + +/* Undefine for gcc-4.8 */ +#define GCC49 + +#ifdef GCC49 + +#include "print-tree.h" +#include "stringpool.h" +#include "stor-layout.h" +#include "varasm.h" + +/* Returns the number of FIELD_DECLs in TYPE. + Copied here from expr.c in gcc4.9 as it is no longer exported by tree.h. */ + +static int +fields_length (const_tree type) +{ + tree t = TYPE_FIELDS (type); + int count = 0; + + for (; t; t = DECL_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL) + ++count; + + return count; +} + +#else + +// adapt gcc4.9 practice to gcc4.8 functions +bool +tree_fits_uhwi_p (const_tree t) +{ + return host_integerp (t, 1); +} + +unsigned HOST_WIDE_INT +tree_to_uhwi (const_tree t) +{ + return tree_low_cst (t, 1); +} + +#endif + +/* TODO: + * remove stmt_list_stack, save in if/case/loop block + * Re-add -v (if necessary) + */ + +static tree type_for_size (unsigned int precision, int unsignedp); + +const int tree_identifier_size = sizeof (struct tree_identifier); + +struct GTY(()) binding_level +{ + /* The BIND_EXPR node for this binding. */ + tree bind; + + /* The BLOCK node for this binding. */ + tree block; + + /* If true, stack must be saved (alloca is used). */ + int save_stack; + + /* Parent binding level. */ + struct binding_level *prev; + + /* Decls in this binding. */ + tree first_decl; + tree last_decl; + + /* Blocks in this binding. */ + tree first_block; + tree last_block; +}; + +/* The current binding level. */ +static GTY(()) struct binding_level *cur_binding_level = NULL; + +/* Chain of unused binding levels. */ +static GTY(()) struct binding_level *old_binding_levels = NULL; + +/* Chain of statements currently generated. */ +static GTY(()) tree cur_stmts = NULL_TREE; + +static void +push_binding (void) +{ + struct binding_level *res; + + if (old_binding_levels == NULL) + res = ggc_alloc_binding_level (); + else + { + res = old_binding_levels; + old_binding_levels = res->prev; + } + + /* Init. */ + res->first_decl = NULL_TREE; + res->last_decl = NULL_TREE; + + res->first_block = NULL_TREE; + res->last_block = NULL_TREE; + + res->save_stack = 0; + + res->bind = make_node (BIND_EXPR); + res->block = make_node (BLOCK); + BIND_EXPR_BLOCK (res->bind) = res->block; + TREE_SIDE_EFFECTS (res->bind) = true; + TREE_TYPE (res->bind) = void_type_node; + TREE_USED (res->block) = true; + + if (cur_binding_level != NULL) + { + /* Append the block created. */ + if (cur_binding_level->first_block == NULL) + cur_binding_level->first_block = res->block; + else + BLOCK_CHAIN (cur_binding_level->last_block) = res->block; + cur_binding_level->last_block = res->block; + + BLOCK_SUPERCONTEXT (res->block) = cur_binding_level->block; + } + + res->prev = cur_binding_level; + cur_binding_level = res; +} + +static void +push_decl (tree decl) +{ + DECL_CONTEXT (decl) = current_function_decl; + + if (cur_binding_level->first_decl == NULL) + cur_binding_level->first_decl = decl; + else + TREE_CHAIN (cur_binding_level->last_decl) = decl; + cur_binding_level->last_decl = decl; +} + +static tree +pop_binding (void) +{ + tree res; + struct binding_level *cur; + + cur = cur_binding_level; + res = cur->bind; + + if (cur->save_stack) + { + tree tmp_var; + tree save; + tree save_call; + tree restore; + tree t; + + /* Create an artificial var to save the stack pointer. */ + tmp_var = build_decl (input_location, VAR_DECL, NULL, ptr_type_node); + DECL_ARTIFICIAL (tmp_var) = true; + DECL_IGNORED_P (tmp_var) = true; + TREE_USED (tmp_var) = true; + push_decl (tmp_var); + + /* Create the save stmt. */ + save_call = build_call_expr + (builtin_decl_implicit (BUILT_IN_STACK_SAVE), 0); + save = build2 (MODIFY_EXPR, ptr_type_node, tmp_var, save_call); + TREE_SIDE_EFFECTS (save) = true; + + /* Create the restore stmt. */ + restore = build_call_expr + (builtin_decl_implicit (BUILT_IN_STACK_RESTORE), 1, tmp_var); + + /* Build a try-finally block. + The statement list is the block of current statements. */ + t = build2 (TRY_FINALLY_EXPR, void_type_node, cur_stmts, NULL_TREE); + TREE_SIDE_EFFECTS (t) = true; + + /* The finally block is the restore stmt. */ + append_to_statement_list (restore, &TREE_OPERAND (t, 1)); + + /* The body of the BIND_BLOCK is the save stmt, followed by the + try block. */ + BIND_EXPR_BODY (res) = NULL_TREE; + append_to_statement_list (save, &BIND_EXPR_BODY (res)); + append_to_statement_list (t, &BIND_EXPR_BODY (res)); + } + else + { + /* The body of the BIND_BLOCK is the statement block. */ + BIND_EXPR_BODY (res) = cur_stmts; + } + BIND_EXPR_VARS (res) = cur->first_decl; + + BLOCK_SUBBLOCKS (cur->block) = cur->first_block; + BLOCK_VARS (cur->block) = cur->first_decl; + + cur_binding_level = cur->prev; + cur->prev = old_binding_levels; + old_binding_levels = cur; + + return res; +} + +// naive conversion to new vec API following the wiki at +// http://gcc.gnu.org/wiki/cxx-conversion/cxx-vec +// see also push_stmts, pop_stmts +static vec <tree> stmt_list_stack = vec<tree>(); + +static void +push_stmts (tree stmts) +{ + stmt_list_stack.safe_push(cur_stmts); + cur_stmts = stmts; +} + +static void +pop_stmts (void) +{ + cur_stmts = stmt_list_stack.pop(); +} + +static void +append_stmt (tree stmt) +{ + if (!EXPR_HAS_LOCATION (stmt)) + SET_EXPR_LOCATION (stmt, input_location); + TREE_SIDE_EFFECTS (stmt) = true; + append_to_statement_list (stmt, &cur_stmts); +} + +static GTY(()) tree top; + +static GTY(()) tree stack_alloc_function_ptr; + +static bool +global_bindings_p (void) +{ + return cur_binding_level->prev == NULL; +} + +static tree +pushdecl (tree t) +{ + //gcc_unreachable (); + // gcc4.8.2 we get here from build_common_builtin_nodes () call in ortho_init + return t; +} + +static tree +builtin_function (const char *name, + tree type, + int function_code, + enum built_in_class decl_class, + const char *library_name, + tree attrs ATTRIBUTE_UNUSED); + +REAL_VALUE_TYPE fp_const_p5; /* 0.5 */ +REAL_VALUE_TYPE fp_const_m_p5; /* -0.5 */ +REAL_VALUE_TYPE fp_const_zero; /* 0.0 */ + +static bool +ortho_init (void) +{ + tree n; + + input_location = BUILTINS_LOCATION; + + /* Create a global binding. */ + push_binding (); + + build_common_tree_nodes (0, 0); + + n = build_decl (input_location, + TYPE_DECL, get_identifier ("int"), integer_type_node); + push_decl (n); + n = build_decl (input_location, + TYPE_DECL, get_identifier ("char"), char_type_node); + push_decl (n); + + /* Create alloca builtin. */ + { + tree args_type = tree_cons (NULL_TREE, size_type_node, void_list_node); + tree func_type = build_function_type (ptr_type_node, args_type); + + set_builtin_decl + (BUILT_IN_ALLOCA, + builtin_function + ("__builtin_alloca", func_type, + BUILT_IN_ALLOCA, BUILT_IN_NORMAL, NULL, NULL_TREE), true); + + stack_alloc_function_ptr = build1 + (ADDR_EXPR, + build_pointer_type (func_type), + builtin_decl_implicit (BUILT_IN_ALLOCA)); + } + + { + tree ptr_ftype = build_function_type (ptr_type_node, NULL_TREE); + + set_builtin_decl + (BUILT_IN_STACK_SAVE, + builtin_function + ("__builtin_stack_save", ptr_ftype, + BUILT_IN_STACK_SAVE, BUILT_IN_NORMAL, NULL, NULL_TREE), true); + } + + { + tree ftype_ptr; + + ftype_ptr = build_function_type + (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, NULL_TREE)); + + set_builtin_decl + (BUILT_IN_STACK_RESTORE, + builtin_function + ("__builtin_stack_restore", ftype_ptr, + BUILT_IN_STACK_RESTORE, BUILT_IN_NORMAL, NULL, NULL_TREE), true); + } + { + REAL_VALUE_TYPE v; + + REAL_VALUE_FROM_INT (v, 1, 0, DFmode); + real_ldexp (&fp_const_p5, &v, -1); + + REAL_VALUE_FROM_INT (v, -1, -1, DFmode); + real_ldexp (&fp_const_m_p5, &v, -1); + + REAL_VALUE_FROM_INT (fp_const_zero, 0, 0, DFmode); + } + + build_common_builtin_nodes (); + // FIXME: this MAY remove the need for creating the builtins above... + // Evaluate tree.c / build_common_builtin_nodes (); for each in turn. + + return true; +} + +static void +ortho_finish (void) +{ +} + +static unsigned int +ortho_option_lang_mask (void) +{ + return CL_vhdl; +} + +static bool +ortho_post_options (const char **pfilename) +{ + if (*pfilename == NULL || strcmp (*pfilename, "-") == 0) + *pfilename = "*stdin*"; + + /* Default hook. */ + lhd_post_options (pfilename); + + // This stops compile failures writing debug information when both -g and -O2 + // (or -O1, -O3 or -Os) options are present. + // Should really make it conditional on specific options + // FIXME : re-evaluate if this is still necessary with newer gccrevisions + dwarf_strict = 1; + + /* Run the back-end. */ + return false; +} + +extern "C" int lang_handle_option (const char *opt, const char *arg); + +static bool +ortho_handle_option (size_t code, const char *arg, + int value ATTRIBUTE_UNUSED, + int kind ATTRIBUTE_UNUSED, + location_t loc ATTRIBUTE_UNUSED, + const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED) +{ + const char *opt; + + opt = cl_options[code].opt_text; + + switch (code) + { + case OPT__elab: + case OPT_l: + case OPT_c: + case OPT__anaelab: + /* Only a few options have a real arguments. */ + return lang_handle_option (opt, arg) != 0; + default: + /* The other options must have a joint argument. */ + if (arg != NULL) + { + size_t len1; + size_t len2; + char *nopt; + + len1 = strlen (opt); + len2 = strlen (arg); + nopt = (char *) alloca (len1 + len2 + 1); + memcpy (nopt, opt, len1); + memcpy (nopt + len1, arg, len2); + nopt[len1 + len2] = 0; + opt = nopt; + } + return lang_handle_option (opt, NULL) != 0; + } +} + +extern "C" int lang_parse_file (const char *filename); + +static void +ortho_parse_file (void) +{ + const char *filename; + + if (num_in_fnames == 0) + filename = NULL; + else + filename = in_fnames[0]; + + linemap_add (line_table, LC_ENTER, 0, filename ? filename :"*no-file*", 1); + input_location = linemap_line_start (line_table, 1, 252); + + if (!lang_parse_file (filename)) + errorcount++; + linemap_add (line_table, LC_LEAVE, 0, NULL, 1); +} + +/* Called by the back-end or by the front-end when the address of EXP + must be taken. + This function should found the base object (if any), and mark it as + addressable (via TREE_ADDRESSABLE). It may emit a warning if this + object cannot be addressable (front-end restriction). + Returns TRUE in case of success, FALSE in case of failure. + Note that the status is never checked by the back-end. */ +static bool +ortho_mark_addressable (tree exp) +{ + tree n; + + n = exp; + + while (1) + switch (TREE_CODE (n)) + { + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + TREE_ADDRESSABLE (n) = true; + return true; + + case COMPONENT_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + n = TREE_OPERAND (n, 0); + break; + + case FUNCTION_DECL: + case CONSTRUCTOR: + TREE_ADDRESSABLE (n) = true; + return true; + + case INDIRECT_REF: + return true; + + default: + gcc_unreachable (); + } +} + +static tree +ortho_truthvalue_conversion (tree expr) +{ + tree expr_type; + tree t; + tree f; + + expr_type = TREE_TYPE (expr); + if (TREE_CODE (expr_type) != BOOLEAN_TYPE) + { + t = integer_one_node; + f = integer_zero_node; + } + else + { + f = TYPE_MIN_VALUE (expr_type); + t = TYPE_MAX_VALUE (expr_type); + } + + + switch (TREE_CODE (expr)) + { + case EQ_EXPR: + case NE_EXPR: + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case ERROR_MARK: + return expr; + + case INTEGER_CST: + /* Not 0 is true. */ + return integer_zerop (expr) ? f : t; + + case REAL_CST: + return real_zerop (expr) ? f : t; + + default: + gcc_unreachable (); + } +} + +/* The following function has been copied and modified from c-convert.c. */ + +/* Change of width--truncation and extension of integers or reals-- + is represented with NOP_EXPR. Proper functioning of many things + assumes that no other conversions can be NOP_EXPRs. + + Conversion between integer and pointer is represented with CONVERT_EXPR. + Converting integer to real uses FLOAT_EXPR + and real to integer uses FIX_TRUNC_EXPR. + + Here is a list of all the functions that assume that widening and + narrowing is always done with a NOP_EXPR: + In convert.c, convert_to_integer. + In c-typeck.c, build_binary_op (boolean ops), and + c_common_truthvalue_conversion. + In expr.c: expand_expr, for operands of a MULT_EXPR. + In fold-const.c: fold. + In tree.c: get_narrower and get_unwidened. */ + +/* Subroutines of `convert'. */ + + + +/* Create an expression whose value is that of EXPR, + converted to type TYPE. The TREE_TYPE of the value + is always TYPE. This function implements all reasonable + conversions; callers should filter out those that are + not permitted by the language being compiled. */ + +tree +convert (tree type, tree expr) +{ + tree e = expr; + enum tree_code code = TREE_CODE (type); + const char *invalid_conv_diag; + + if (type == error_mark_node + || expr == error_mark_node + || TREE_TYPE (expr) == error_mark_node) + return error_mark_node; + + if ((invalid_conv_diag + = targetm.invalid_conversion (TREE_TYPE (expr), type))) + { + error (invalid_conv_diag); + return error_mark_node; + } + + if (type == TREE_TYPE (expr)) + return expr; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) + return fold_build1 (NOP_EXPR, type, expr); + if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) + return error_mark_node; + if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE || code == VOID_TYPE) + { + gcc_unreachable (); + } + if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) + return fold (convert_to_integer (type, e)); + if (code == BOOLEAN_TYPE) + { + tree t = ortho_truthvalue_conversion (expr); + if (TREE_CODE (t) == ERROR_MARK) + return t; + + /* If it returns a NOP_EXPR, we must fold it here to avoid + infinite recursion between fold () and convert (). */ + if (TREE_CODE (t) == NOP_EXPR) + return fold_build1 (NOP_EXPR, type, TREE_OPERAND (t, 0)); + else + return fold_build1 (NOP_EXPR, type, t); + } + if (code == POINTER_TYPE || code == REFERENCE_TYPE) + return fold (convert_to_pointer (type, e)); + if (code == REAL_TYPE) + return fold (convert_to_real (type, e)); + + gcc_unreachable (); +} + +/* Return a definition for a builtin function named NAME and whose data type + is TYPE. TYPE should be a function type with argument types. + FUNCTION_CODE tells later passes how to compile calls to this function. + See tree.h for its possible values. + + If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, + the name to be called if we can't opencode the function. If + ATTRS is nonzero, use that for the function's attribute list. */ +static tree +builtin_function (const char *name, + tree type, + int function_code, + enum built_in_class decl_class, + const char *library_name, + tree attrs ATTRIBUTE_UNUSED) +{ + tree decl = build_decl (input_location, + FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + if (library_name) + SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name)); + make_decl_rtl (decl); + DECL_BUILT_IN_CLASS (decl) = decl_class; + DECL_FUNCTION_CODE (decl) = (built_in_function) function_code; + DECL_SOURCE_LOCATION (decl) = input_location; + return decl; +} + +#ifndef MAX_BITS_PER_WORD +#define MAX_BITS_PER_WORD BITS_PER_WORD +#endif + +/* This variable keeps a table for types for each precision so that we only + allocate each of them once. Signed and unsigned types are kept separate. + */ +static GTY(()) tree signed_and_unsigned_types[MAX_BITS_PER_WORD + 1][2]; + +/* Return an integer type with the number of bits of precision given by + PRECISION. UNSIGNEDP is nonzero if the type is unsigned; otherwise + it is a signed type. */ +static tree +type_for_size (unsigned int precision, int unsignedp) +{ + tree t; + + if (precision <= MAX_BITS_PER_WORD + && signed_and_unsigned_types[precision][unsignedp] != NULL_TREE) + return signed_and_unsigned_types[precision][unsignedp]; + + if (unsignedp) + t = make_unsigned_type (precision); + else + t = make_signed_type (precision); + + if (precision <= MAX_BITS_PER_WORD) + signed_and_unsigned_types[precision][unsignedp] = t; + + return t; +} + +/* Return a data type that has machine mode MODE. UNSIGNEDP selects + an unsigned type; otherwise a signed type is returned. */ +static tree +type_for_mode (enum machine_mode mode, int unsignedp) +{ + if (SCALAR_INT_MODE_P (mode)) + return type_for_size (GET_MODE_BITSIZE (mode), unsignedp); + + if (mode == TYPE_MODE (void_type_node)) + return void_type_node; + + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (long_double_type_node)) + return long_double_type_node; + + return NULL_TREE; +} + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "vhdl" +#undef LANG_HOOKS_IDENTIFIER_SIZE +#define LANG_HOOKS_IDENTIFIER_SIZE sizeof (struct tree_identifier) +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT ortho_init +#undef LANG_HOOKS_FINISH +#define LANG_HOOKS_FINISH ortho_finish +#undef LANG_HOOKS_OPTION_LANG_MASK +#define LANG_HOOKS_OPTION_LANG_MASK ortho_option_lang_mask +#undef LANG_HOOKS_HANDLE_OPTION +#define LANG_HOOKS_HANDLE_OPTION ortho_handle_option +#undef LANG_HOOKS_POST_OPTIONS +#define LANG_HOOKS_POST_OPTIONS ortho_post_options +#undef LANG_HOOKS_HONOR_READONLY +#define LANG_HOOKS_HONOR_READONLY true +#undef LANG_HOOKS_MARK_ADDRESSABLE +#define LANG_HOOKS_MARK_ADDRESSABLE ortho_mark_addressable +#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION +#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION ortho_expand_function + +#undef LANG_HOOKS_TYPE_FOR_MODE +#define LANG_HOOKS_TYPE_FOR_MODE type_for_mode +#undef LANG_HOOKS_TYPE_FOR_SIZE +#define LANG_HOOKS_TYPE_FOR_SIZE type_for_size +#undef LANG_HOOKS_SIGNED_TYPE +#define LANG_HOOKS_SIGNED_TYPE signed_type +#undef LANG_HOOKS_UNSIGNED_TYPE +#define LANG_HOOKS_UNSIGNED_TYPE unsigned_type +#undef LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE +#define LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE signed_or_unsigned_type +#undef LANG_HOOKS_PARSE_FILE +#define LANG_HOOKS_PARSE_FILE ortho_parse_file + +#define pushlevel lhd_do_nothing_i +#define poplevel lhd_do_nothing_iii_return_null_tree +#define set_block lhd_do_nothing_t +#undef LANG_HOOKS_GETDECLS +#define LANG_HOOKS_GETDECLS lhd_return_null_tree_v + +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +union GTY((desc ("0"), + chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL"))) + lang_tree_node +{ + union tree_node GTY((tag ("0"), + desc ("tree_node_structure (&%h)"))) generic; +}; + +/* GHDL does not use the lang_decl and lang_type. + + FIXME: the variable_size annotation here is needed because these types are + variable-sized in some other front-ends. Due to gengtype deficiency, the + GTY options of such types have to agree across all front-ends. */ + +struct GTY((variable_size)) lang_type { char dummy; }; +struct GTY((variable_size)) lang_decl { char dummy; }; + +struct GTY(()) language_function +{ + char dummy; +}; + + +extern "C" { + +struct GTY(()) chain_constr_type +{ + tree first; + tree last; +}; + +static void +chain_init (struct chain_constr_type *constr) +{ + constr->first = NULL_TREE; + constr->last = NULL_TREE; +} + +static void +chain_append (struct chain_constr_type *constr, tree el) +{ + if (constr->first == NULL_TREE) + { + gcc_assert (constr->last == NULL_TREE); + constr->first = el; + } + else + TREE_CHAIN (constr->last) = el; + constr->last = el; +} + +struct GTY(()) list_constr_type +{ + tree first; + tree last; +}; + +static void +list_init (struct list_constr_type *constr) +{ + constr->first = NULL_TREE; + constr->last = NULL_TREE; +} + +static void +ortho_list_append (struct list_constr_type *constr, tree el) +{ + tree res; + + res = tree_cons (NULL_TREE, el, NULL_TREE); + if (constr->first == NULL_TREE) + constr->first = res; + else + TREE_CHAIN (constr->last) = res; + constr->last = res; +} + +enum ON_op_kind { + /* Not an operation; invalid. */ + ON_Nil, + + /* Dyadic operations. */ + ON_Add_Ov, + ON_Sub_Ov, + ON_Mul_Ov, + ON_Div_Ov, + ON_Rem_Ov, + ON_Mod_Ov, + + /* Binary operations. */ + ON_And, + ON_Or, + ON_Xor, + + /* Monadic operations. */ + ON_Not, + ON_Neg_Ov, + ON_Abs_Ov, + + /* Comparaisons */ + ON_Eq, + ON_Neq, + ON_Le, + ON_Lt, + ON_Ge, + ON_Gt, + + ON_LAST +}; + +static enum tree_code ON_op_to_TREE_CODE[ON_LAST] = { + ERROR_MARK, + + PLUS_EXPR, + MINUS_EXPR, + MULT_EXPR, + ERROR_MARK, + TRUNC_MOD_EXPR, + FLOOR_MOD_EXPR, + + BIT_AND_EXPR, + BIT_IOR_EXPR, + BIT_XOR_EXPR, + + BIT_NOT_EXPR, + NEGATE_EXPR, + ABS_EXPR, + + EQ_EXPR, + NE_EXPR, + LE_EXPR, + LT_EXPR, + GE_EXPR, + GT_EXPR, +}; + +tree +new_dyadic_op (enum ON_op_kind kind, tree left, tree right) +{ + tree left_type; + enum tree_code code; + + /* Truncate to avoid representations issue. */ + kind = (enum ON_op_kind)((unsigned)kind & 0xff); + + left_type = TREE_TYPE (left); + gcc_assert (left_type == TREE_TYPE (right)); + + switch (kind) + { + case ON_Div_Ov: + if (TREE_CODE (left_type) == REAL_TYPE) + code = RDIV_EXPR; + else + code = TRUNC_DIV_EXPR; + break; + default: + code = ON_op_to_TREE_CODE[kind]; + break; + } + return build2 (code, left_type, left, right); +} + +tree +new_monadic_op (enum ON_op_kind kind, tree operand) +{ + /* Truncate to avoid representations issue. */ + kind = (enum ON_op_kind)((unsigned)kind & 0xff); + + return build1 (ON_op_to_TREE_CODE[kind], TREE_TYPE (operand), operand); +} + +tree +new_compare_op (enum ON_op_kind kind, tree left, tree right, tree ntype) +{ + gcc_assert (TREE_CODE (ntype) == BOOLEAN_TYPE); + gcc_assert (TREE_TYPE (left) == TREE_TYPE (right)); + + /* Truncate to avoid representations issue. */ + kind = (enum ON_op_kind)((unsigned)kind & 0xff); + + return build2 (ON_op_to_TREE_CODE[kind], ntype, left, right); +} + +tree +new_convert_ov (tree val, tree rtype) +{ + tree val_type; + enum tree_code val_code; + enum tree_code rtype_code; + enum tree_code code; + + val_type = TREE_TYPE (val); + if (val_type == rtype) + return val; + + /* FIXME: check conversions. */ + val_code = TREE_CODE (val_type); + rtype_code = TREE_CODE (rtype); + if (val_code == POINTER_TYPE && rtype_code == POINTER_TYPE) + code = NOP_EXPR; + else if (val_code == INTEGER_TYPE && rtype_code == INTEGER_TYPE) + code = CONVERT_EXPR; + else if (val_code == REAL_TYPE && rtype_code == INTEGER_TYPE) + { + /* REAL to INTEGER + Gcc only handles FIX_TRUNC_EXPR, but we need rounding. */ + tree m_p5; + tree p5; + tree zero; + tree saved; + tree comp; + tree adj; + tree res; + + m_p5 = build_real (val_type, fp_const_m_p5); + p5 = build_real (val_type, fp_const_p5); + zero = build_real (val_type, fp_const_zero); + saved = save_expr (val); + comp = build2 (GE_EXPR, integer_type_node, saved, zero); + /* FIXME: instead of res = res + (comp ? .5 : -.5) + do: res = res (comp ? + : -) .5 */ + adj = build3 (COND_EXPR, val_type, comp, p5, m_p5); + res = build2 (PLUS_EXPR, val_type, saved, adj); + res = build1 (FIX_TRUNC_EXPR, rtype, res); + return res; + } + else if (val_code == INTEGER_TYPE && rtype_code == ENUMERAL_TYPE) + code = CONVERT_EXPR; + else if (val_code == ENUMERAL_TYPE && rtype_code == INTEGER_TYPE) + code = CONVERT_EXPR; + else if (val_code == INTEGER_TYPE && rtype_code == REAL_TYPE) + code = FLOAT_EXPR; + else if (val_code == BOOLEAN_TYPE && rtype_code == BOOLEAN_TYPE) + code = NOP_EXPR; + else if (val_code == BOOLEAN_TYPE && rtype_code == INTEGER_TYPE) + code = CONVERT_EXPR; + else if (val_code == INTEGER_TYPE && rtype_code == BOOLEAN_TYPE) + code = NOP_EXPR; + else if (val_code == REAL_TYPE && rtype_code == REAL_TYPE) + code = NOP_EXPR; + else + gcc_unreachable (); + + return build1 (code, rtype, val); +} + +tree +new_alloca (tree rtype, tree size) +{ + tree res; + + /* Must save stack except when at function level. */ + if (cur_binding_level->prev != NULL + && cur_binding_level->prev->prev != NULL) + cur_binding_level->save_stack = 1; + + res = build_call_nary (ptr_type_node, stack_alloc_function_ptr, + 1, fold_convert (size_type_node, size)); + return fold_convert (rtype, res); +} + +tree +new_signed_literal (tree ltype, long long value) +{ + tree res; + HOST_WIDE_INT lo; + HOST_WIDE_INT hi; + + lo = value; + hi = (value >> 1) >> (8 * sizeof (HOST_WIDE_INT) - 1); + res = build_int_cst_wide (ltype, lo, hi); + return res; +} + +tree +new_unsigned_literal (tree ltype, unsigned long long value) +{ + tree res; + unsigned HOST_WIDE_INT lo; + unsigned HOST_WIDE_INT hi; + + lo = value; + hi = (value >> 1) >> (8 * sizeof (HOST_WIDE_INT) - 1); + res = build_int_cst_wide (ltype, lo, hi); + return res; +} + +tree +new_null_access (tree ltype) +{ + tree res; + + res = build_int_cst_wide (ltype, 0, 0); + return res; +} + +tree +new_float_literal (tree ltype, double value) +{ + signed long long s; + double frac; + int ex; + REAL_VALUE_TYPE r_sign; + REAL_VALUE_TYPE r_exp; + REAL_VALUE_TYPE r; + tree res; + HOST_WIDE_INT lo; + HOST_WIDE_INT hi; + + frac = frexp (value, &ex); + + s = ldexp (frac, 60); + lo = s; + hi = (s >> 1) >> (8 * sizeof (HOST_WIDE_INT) - 1); + res = build_int_cst_wide (long_integer_type_node, lo, hi); + REAL_VALUE_FROM_INT (r_sign, lo, hi, DFmode); + real_2expN (&r_exp, ex - 60, DFmode); + real_arithmetic (&r, MULT_EXPR, &r_sign, &r_exp); + res = build_real (ltype, r); + return res; +} + +struct GTY(()) o_element_list +{ + tree res; + struct chain_constr_type chain; +}; + +void +new_uncomplete_record_type (tree *res) +{ + *res = make_node (RECORD_TYPE); +} + +void +start_record_type (struct o_element_list *elements) +{ + elements->res = make_node (RECORD_TYPE); + chain_init (&elements->chain); +} + +void +start_uncomplete_record_type (tree res, struct o_element_list *elements) +{ + elements->res = res; + chain_init (&elements->chain); +} + +static void +new_record_union_field (struct o_element_list *list, + tree *el, + tree ident, + tree etype) +{ + tree res; + + res = build_decl (input_location, + FIELD_DECL, ident, etype); + DECL_CONTEXT (res) = list->res; + chain_append (&list->chain, res); + *el = res; +} + +void +new_record_field (struct o_element_list *list, + tree *el, + tree ident, + tree etype) +{ + return new_record_union_field (list, el, ident, etype); +} + +void +finish_record_type (struct o_element_list *elements, tree *res) +{ + TYPE_FIELDS (elements->res) = elements->chain.first; + layout_type (elements->res); + *res = elements->res; + + if (TYPE_NAME (elements->res) != NULL_TREE) + { + /* The type was completed. */ + rest_of_type_compilation (elements->res, 1); + } +} + +void +start_union_type (struct o_element_list *elements) +{ + elements->res = make_node (UNION_TYPE); + chain_init (&elements->chain); +} + +void +new_union_field (struct o_element_list *elements, + tree *el, + tree ident, + tree etype) +{ + return new_record_union_field (elements, el, ident, etype); +} + +void +finish_union_type (struct o_element_list *elements, tree *res) +{ + TYPE_FIELDS (elements->res) = elements->chain.first; + layout_type (elements->res); + *res = elements->res; +} + +tree +new_unsigned_type (int size) +{ + return make_unsigned_type (size); +} + +tree +new_signed_type (int size) +{ + return make_signed_type (size); +} + +tree +new_float_type (void) +{ + tree res; + + res = make_node (REAL_TYPE); + TYPE_PRECISION (res) = DOUBLE_TYPE_SIZE; + layout_type (res); + return res; +} + +tree +new_access_type (tree dtype) +{ + tree res; + + if (dtype == NULL_TREE) + { + res = make_node (POINTER_TYPE); + TREE_TYPE (res) = NULL_TREE; + /* Seems necessary. */ + SET_TYPE_MODE (res, Pmode); + layout_type (res); + return res; + } + else + return build_pointer_type (dtype); +} + +void +finish_access_type (tree atype, tree dtype) +{ + gcc_assert (TREE_CODE (atype) == POINTER_TYPE + && TREE_TYPE (atype) == NULL_TREE); + + TREE_TYPE (atype) = dtype; +} + +tree +new_array_type (tree el_type, tree index_type) +{ + return build_array_type (el_type, index_type); +} + + +tree +new_constrained_array_type (tree atype, tree length) +{ + tree range_type; + tree index_type; + tree len; + tree one; + tree res; + + index_type = TYPE_DOMAIN (atype); + if (integer_zerop (length)) + { + /* Handle null array, by creating a one-length array... */ + len = size_zero_node; + } + else + { + one = build_int_cstu (index_type, 1); + len = build2 (MINUS_EXPR, index_type, length, one); + len = fold (len); + } + + range_type = build_range_type (index_type, size_zero_node, len); + res = build_array_type (TREE_TYPE (atype), range_type); + + /* Constrained arrays are *always* a subtype of its array type. + Just copy alias set. */ + TYPE_ALIAS_SET (res) = get_alias_set (atype); + return res; +} + +void +new_boolean_type (tree *res, + tree false_id ATTRIBUTE_UNUSED, tree *false_e, + tree true_id ATTRIBUTE_UNUSED, tree *true_e) +{ + *res = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (*res) = 1; + fixup_unsigned_type (*res); + *false_e = TYPE_MIN_VALUE (*res); + *true_e = TYPE_MAX_VALUE (*res); +} + +struct o_enum_list +{ + tree res; + struct chain_constr_type chain; + int num; + int size; +}; + +void +start_enum_type (struct o_enum_list *list, int size) +{ + list->res = make_node (ENUMERAL_TYPE); + // as of gcc4.8, TYPE_PRECISION of 0 is rigorously enforced! + TYPE_PRECISION(list->res) = size; + chain_init (&list->chain); + list->num = 0; + list->size = size; +} + +void +new_enum_literal (struct o_enum_list *list, tree ident, tree *res) +{ + *res = build_int_cstu (list->res, (HOST_WIDE_INT)(list->num)); + chain_append (&list->chain, tree_cons (ident, *res, NULL_TREE)); + list->num++; +} + +void +finish_enum_type (struct o_enum_list *list, tree *res) +{ + *res = list->res; + TYPE_VALUES (*res) = list->chain.first; + TYPE_UNSIGNED (*res) = 1; + TYPE_PRECISION (*res) = list->size; + set_min_and_max_values_for_integral_type (*res, list->size, 1); + layout_type (*res); +} + +struct GTY(()) o_record_aggr_list +{ + /* Type of the record. */ + tree atype; + /* Type of the next field to be added. */ + tree field; + /* Vector of elements. */ + // VEC(constructor_elt,gc) *elts; + vec<constructor_elt,va_gc> *elts; +}; + +void +start_record_aggr (struct o_record_aggr_list *list, tree atype) +{ + list->atype = atype; + list->field = TYPE_FIELDS (atype); + //list->elts = VEC_alloc (constructor_elt, gc, fields_length (atype)); + vec_alloc(list->elts, fields_length (atype)); +} + +void +new_record_aggr_el (struct o_record_aggr_list *list, tree value) +{ + CONSTRUCTOR_APPEND_ELT (list->elts, list->field, value); + list->field = TREE_CHAIN (list->field); +} + +void +finish_record_aggr (struct o_record_aggr_list *list, tree *res) +{ + *res = build_constructor (list->atype, list->elts); +} + +struct GTY(()) o_array_aggr_list +{ + tree atype; + /* Vector of elements. */ + vec<constructor_elt,va_gc> *elts; +}; + +void +start_array_aggr (struct o_array_aggr_list *list, tree atype) +{ + tree nelts; + unsigned HOST_WIDE_INT n; + + list->atype = atype; + list->elts = NULL; + + nelts = array_type_nelts (atype); + gcc_assert (nelts != NULL_TREE && tree_fits_uhwi_p (nelts)); + + n = tree_to_uhwi (nelts) + 1; + vec_alloc(list->elts, n); +} + +void +new_array_aggr_el (struct o_array_aggr_list *list, tree value) +{ + CONSTRUCTOR_APPEND_ELT (list->elts, NULL_TREE, value); +} + +void +finish_array_aggr (struct o_array_aggr_list *list, tree *res) +{ + *res = build_constructor (list->atype, list->elts); +} + + +tree +new_union_aggr (tree atype, tree field, tree value) +{ + tree res; + + res = build_constructor_single (atype, field, value); + TREE_CONSTANT (res) = 1; + return res; +} + +tree +new_indexed_element (tree arr, tree index) +{ + ortho_mark_addressable (arr); + return build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (arr)), + arr, index, NULL_TREE, NULL_TREE); +} + +tree +new_slice (tree arr, tree res_type, tree index) +{ +#if 0 + tree res; + tree el_ptr_type; + tree el_type; + tree res_ptr_type; +#endif + + /* *((RES_TYPE *)(&ARR[INDEX])) + convert ARR to a pointer, add index, and reconvert to array ? */ + gcc_assert (TREE_CODE (res_type) == ARRAY_TYPE); + + ortho_mark_addressable (arr); + return build4 (ARRAY_RANGE_REF, res_type, arr, index, NULL_TREE, NULL_TREE); +#if 0 + el_type = TREE_TYPE (TREE_TYPE (arr)); + el_ptr_type = build_pointer_type (el_type); + + res = build4 (ARRAY_REF, el_type, arr, index, NULL_TREE, NULL_TREE); + res = build1 (ADDR_EXPR, el_ptr_type, res); + res_ptr_type = build_pointer_type (res_type); + res = build1 (NOP_EXPR, res_ptr_type, res); + res = build1 (INDIRECT_REF, res_type, res); + return res; +#endif +} + +tree +new_selected_element (tree rec, tree el) +{ + tree res; + + gcc_assert (TREE_CODE (TREE_TYPE (rec)) == RECORD_TYPE); + + res = build3 (COMPONENT_REF, TREE_TYPE (el), rec, el, NULL_TREE); + return res; +} + +tree +new_access_element (tree acc) +{ + tree acc_type; + + acc_type = TREE_TYPE (acc); + gcc_assert (TREE_CODE (acc_type) == POINTER_TYPE); + + return build1 (INDIRECT_REF, TREE_TYPE (acc_type), acc); +} + +tree +new_offsetof (tree rec_type, tree field, tree rtype) +{ + tree off; + tree bit_off; + HOST_WIDE_INT pos; + tree res; + + gcc_assert (DECL_CONTEXT (field) == rec_type); + + off = DECL_FIELD_OFFSET (field); + + /* The offset must be a constant. */ + gcc_assert (tree_fits_uhwi_p (off)); + + bit_off = DECL_FIELD_BIT_OFFSET (field); + + /* The offset must be a constant. */ + gcc_assert (tree_fits_uhwi_p (bit_off)); + + pos = TREE_INT_CST_LOW (off) + + (TREE_INT_CST_LOW (bit_off) / BITS_PER_UNIT); + res = build_int_cstu (rtype, pos); + return res; +} + +tree +new_sizeof (tree atype, tree rtype) +{ + tree size; + + size = TYPE_SIZE_UNIT (atype); + + return fold (build1 (NOP_EXPR, rtype, size)); +} + +tree +new_alignof (tree atype, tree rtype) +{ + return build_int_cstu (rtype, TYPE_ALIGN_UNIT (atype)); +} + +static tree +ortho_build_addr (tree lvalue, tree atype) +{ + tree res; + + if (TREE_CODE (lvalue) == INDIRECT_REF) + { + /* ADDR_REF(INDIRECT_REF(x)) -> x. */ + res = TREE_OPERAND (lvalue, 0); + } + else + { + tree ptr_type; + + /* &base[off] -> base+off. */ + ortho_mark_addressable (lvalue); + + if (TREE_TYPE (lvalue) != TREE_TYPE (atype)) + ptr_type = build_pointer_type (TREE_TYPE (lvalue)); + else + ptr_type = atype; + res = fold_build1 (ADDR_EXPR, ptr_type, lvalue); + } + + if (TREE_TYPE (res) != atype) + res = fold_build1 (NOP_EXPR, atype, res); + + return res; +} + +tree +new_unchecked_address (tree lvalue, tree atype) +{ + return ortho_build_addr (lvalue, atype); +} + +tree +new_address (tree lvalue, tree atype) +{ + return ortho_build_addr (lvalue, atype); +} + +tree +new_global_address (tree lvalue, tree atype) +{ + return ortho_build_addr (lvalue, atype); +} + +tree +new_global_unchecked_address (tree lvalue, tree atype) +{ + return ortho_build_addr (lvalue, atype); +} + +/* Return a pointer to function FUNC. */ +static tree +build_function_ptr (tree func) +{ + return build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (func)), func); +} + +tree +new_subprogram_address (tree subprg, tree atype) +{ + return fold (build1 (NOP_EXPR, atype, build_function_ptr (subprg))); +} + +tree +new_value (tree lvalue) +{ + return lvalue; +} + +void +new_debug_line_decl (int line) +{ + input_location = linemap_line_start (line_table, line, 252); +} + +void +new_type_decl (tree ident, tree atype) +{ + tree decl; + + TYPE_NAME (atype) = ident; + decl = build_decl (input_location, TYPE_DECL, ident, atype); + TYPE_STUB_DECL (atype) = decl; + push_decl (decl); + /* + if Get_TYPE_SIZE (Ttype) /= NULL_TREE then + -- Do not generate debug info for uncompleted types. + Rest_Of_Type_Compilation (Ttype, C_True); + end if; + */ +} + +enum o_storage { o_storage_external, + o_storage_public, + o_storage_private, + o_storage_local }; + +static void +set_storage (tree Node, enum o_storage storage) +{ + switch (storage) + { + case o_storage_external: + DECL_EXTERNAL (Node) = 1; + TREE_PUBLIC (Node) = 1; + TREE_STATIC (Node) = 0; + break; + case o_storage_public: + DECL_EXTERNAL (Node) = 0; + TREE_PUBLIC (Node) = 1; + TREE_STATIC (Node) = 1; + break; + case o_storage_private: + DECL_EXTERNAL (Node) = 0; + TREE_PUBLIC (Node) = 0; + TREE_STATIC (Node) = 1; + break; + case o_storage_local: + DECL_EXTERNAL (Node) = 0; + TREE_PUBLIC (Node) = 0; + TREE_STATIC (Node) = 0; + break; + } +} + +void +new_const_decl (tree *res, tree ident, enum o_storage storage, tree atype) +{ + tree cst; + + cst = build_decl (input_location, VAR_DECL, ident, atype); + set_storage (cst, storage); + TREE_READONLY (cst) = 1; + push_decl (cst); + switch (storage) + { + case o_storage_local: + gcc_unreachable (); + case o_storage_external: + /* We are at top level if Current_Function_Decl is null. */ + rest_of_decl_compilation + (cst, current_function_decl == NULL_TREE, 0); + break; + case o_storage_public: + case o_storage_private: + break; + } + *res = cst; +} + +void +start_const_value (tree *cst ATTRIBUTE_UNUSED) +{ +} + +void +finish_const_value (tree *cst, tree val) +{ + DECL_INITIAL (*cst) = val; + TREE_CONSTANT (val) = 1; + TREE_STATIC (*cst) = 1; + rest_of_decl_compilation + (*cst, current_function_decl == NULL_TREE, 0); +} + +void +new_var_decl (tree *res, tree ident, enum o_storage storage, tree atype) +{ + tree var; + + var = build_decl (input_location, VAR_DECL, ident, atype); + if (current_function_decl != NULL_TREE) + { + /* Local variable. */ + TREE_STATIC (var) = 0; + DECL_EXTERNAL (var) = 0; + TREE_PUBLIC (var) = 0; + } + else + set_storage (var, storage); + + push_decl (var); + + if (current_function_decl == NULL_TREE) + rest_of_decl_compilation (var, 1, 0); + + *res = var; +} + +struct GTY(()) o_inter_list +{ + tree ident; + enum o_storage storage; + + /* Return type. */ + tree rtype; + + /* List of parameter types. */ + struct list_constr_type param_list; + + /* Chain of parameters declarations. */ + struct chain_constr_type param_chain; +}; + +void +start_function_decl (struct o_inter_list *interfaces, + tree ident, + enum o_storage storage, + tree rtype) +{ + interfaces->ident = ident; + interfaces->storage = storage; + interfaces->rtype = rtype; + chain_init (&interfaces->param_chain); + list_init (&interfaces->param_list); +} + +void +start_procedure_decl (struct o_inter_list *interfaces, + tree ident, + enum o_storage storage) +{ + start_function_decl (interfaces, ident, storage, void_type_node); +} + +void +new_interface_decl (struct o_inter_list *interfaces, + tree *res, + tree ident, + tree atype) +{ + tree r; + + r = build_decl (input_location, PARM_DECL, ident, atype); + /* DECL_CONTEXT (Res, Xxx); */ + + /* Do type conversion: convert boolean and enums to int */ + switch (TREE_CODE (atype)) + { + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + DECL_ARG_TYPE (r) = integer_type_node; + default: + DECL_ARG_TYPE (r) = atype; + } + + layout_decl (r, 0); + + chain_append (&interfaces->param_chain, r); + ortho_list_append (&interfaces->param_list, atype); + *res = r; +} + +void +finish_subprogram_decl (struct o_inter_list *interfaces, tree *res) +{ + tree decl; + tree result; + tree parm; + int is_global; + + /* Append a void type in the parameter types chain, so that the function + is known not be have variables arguments. */ + ortho_list_append (&interfaces->param_list, void_type_node); + + decl = build_decl (input_location, FUNCTION_DECL, interfaces->ident, + build_function_type (interfaces->rtype, + interfaces->param_list.first)); + DECL_SOURCE_LOCATION (decl) = input_location; + + is_global = current_function_decl == NULL_TREE + || interfaces->storage == o_storage_external; + if (is_global) + set_storage (decl, interfaces->storage); + else + { + /* A nested subprogram. */ + DECL_EXTERNAL (decl) = 0; + TREE_PUBLIC (decl) = 0; + } + /* The function exist in static storage. */ + TREE_STATIC (decl) = 1; + DECL_INITIAL (decl) = error_mark_node; + TREE_ADDRESSABLE (decl) = 1; + + /* Declare the result. + FIXME: should be moved in start_function_body. */ + result = build_decl (input_location, + RESULT_DECL, NULL_TREE, interfaces->rtype); + DECL_RESULT (decl) = result; + DECL_CONTEXT (result) = decl; + + DECL_ARGUMENTS (decl) = interfaces->param_chain.first; + /* Set DECL_CONTEXT of parameters. */ + for (parm = interfaces->param_chain.first; + parm != NULL_TREE; + parm = TREE_CHAIN (parm)) + DECL_CONTEXT (parm) = decl; + + push_decl (decl); + + /* External functions are never nested. + Remove their context, which is set by push_decl. */ + if (interfaces->storage == o_storage_external) + DECL_CONTEXT (decl) = NULL_TREE; + + if (is_global) + rest_of_decl_compilation (decl, 1, 0); + + *res = decl; +} + +void +start_subprogram_body (tree func) +{ + gcc_assert (current_function_decl == DECL_CONTEXT (func)); + current_function_decl = func; + + /* The function is not anymore external. */ + DECL_EXTERNAL (func) = 0; + + push_stmts (alloc_stmt_list ()); + push_binding (); +} + +void +finish_subprogram_body (void) +{ + tree bind; + tree func; + tree parent; + + bind = pop_binding (); + pop_stmts (); + + func = current_function_decl; + DECL_INITIAL (func) = BIND_EXPR_BLOCK (bind); + DECL_SAVED_TREE (func) = bind; + + /* Initialize the RTL code for the function. */ + allocate_struct_function (func, false); + + /* Store the end of the function. */ + cfun->function_end_locus = input_location; + + parent = DECL_CONTEXT (func); + + if (parent != NULL) + cgraph_get_create_node (func); + else + cgraph_finalize_function (func, false); + + current_function_decl = parent; + set_cfun (NULL); +} + + +void +new_debug_line_stmt (int line) +{ + input_location = linemap_line_start (line_table, line, 252); +} + +void +start_declare_stmt (void) +{ + push_stmts (alloc_stmt_list ()); + push_binding (); +} + +void +finish_declare_stmt (void) +{ + tree bind; + + bind = pop_binding (); + pop_stmts (); + append_stmt (bind); +} + + +struct GTY(()) o_assoc_list +{ + tree subprg; + vec<tree, va_gc> *vecptr; +}; + +void +start_association (struct o_assoc_list *assocs, tree subprg) +{ + assocs->subprg = subprg; + assocs->vecptr = NULL; +} + +void +new_association (struct o_assoc_list *assocs, tree val) +{ + vec_safe_push(assocs->vecptr, val); +} + +tree +new_function_call (struct o_assoc_list *assocs) +{ + return build_call_vec (TREE_TYPE (TREE_TYPE (assocs->subprg)), + build_function_ptr (assocs->subprg), + assocs->vecptr); +} + +void +new_procedure_call (struct o_assoc_list *assocs) +{ + tree res; + + res = build_call_vec (TREE_TYPE (TREE_TYPE (assocs->subprg)), + build_function_ptr (assocs->subprg), + assocs->vecptr); + TREE_SIDE_EFFECTS (res) = 1; + append_stmt (res); +} + +void +new_assign_stmt (tree target, tree value) +{ + tree n; + + n = build2 (MODIFY_EXPR, TREE_TYPE (target), target, value); + TREE_SIDE_EFFECTS (n) = 1; + append_stmt (n); +} + +void +new_func_return_stmt (tree value) +{ + tree assign; + tree stmt; + tree res; + + res = DECL_RESULT (current_function_decl); + assign = build2 (MODIFY_EXPR, TREE_TYPE (value), res, value); + TREE_SIDE_EFFECTS (assign) = 1; + stmt = build1 (RETURN_EXPR, void_type_node, assign); + TREE_SIDE_EFFECTS (stmt) = 1; + append_stmt (stmt); +} + +void +new_proc_return_stmt (void) +{ + tree stmt; + + stmt = build1 (RETURN_EXPR, void_type_node, NULL_TREE); + TREE_SIDE_EFFECTS (stmt) = 1; + append_stmt (stmt); +} + + +struct GTY(()) o_if_block +{ + tree stmt; +}; + +void +start_if_stmt (struct o_if_block *block, tree cond) +{ + tree stmt; + tree stmts; + + stmts = alloc_stmt_list (); + stmt = build3 (COND_EXPR, void_type_node, cond, stmts, NULL_TREE); + block->stmt = stmt; + append_stmt (stmt); + push_stmts (stmts); +} + +void +new_else_stmt (struct o_if_block *block) +{ + tree stmts; + + pop_stmts (); + stmts = alloc_stmt_list (); + COND_EXPR_ELSE (block->stmt) = stmts; + push_stmts (stmts); +} + +void +finish_if_stmt (struct o_if_block *block ATTRIBUTE_UNUSED) +{ + pop_stmts (); +} + + +struct GTY(()) o_snode +{ + tree beg_label; + tree end_label; +}; + +/* Create an artificial label. */ +static tree +build_label (void) +{ + tree res; + + res = build_decl (input_location, LABEL_DECL, NULL_TREE, void_type_node); + DECL_CONTEXT (res) = current_function_decl; + DECL_ARTIFICIAL (res) = 1; + return res; +} + +void +start_loop_stmt (struct o_snode *label) +{ + tree stmt; + + label->beg_label = build_label (); + + stmt = build1 (LABEL_EXPR, void_type_node, label->beg_label); + append_stmt (stmt); + + label->end_label = build_label (); +} + +void +finish_loop_stmt (struct o_snode *label) +{ + tree stmt; + + stmt = build1 (GOTO_EXPR, void_type_node, label->beg_label); + TREE_USED (label->beg_label) = 1; + append_stmt (stmt); + /* Emit the end label only if there is a goto to it. + (Return may be used to exit from the loop). */ + if (TREE_USED (label->end_label)) + { + stmt = build1 (LABEL_EXPR, void_type_node, label->end_label); + append_stmt (stmt); + } +} + +void +new_exit_stmt (struct o_snode *l) +{ + tree stmt; + + stmt = build1 (GOTO_EXPR, void_type_node, l->end_label); + append_stmt (stmt); + TREE_USED (l->end_label) = 1; +} + +void +new_next_stmt (struct o_snode *l) +{ + tree stmt; + + stmt = build1 (GOTO_EXPR, void_type_node, l->beg_label); + TREE_USED (l->beg_label) = 1; + append_stmt (stmt); +} + +struct GTY(()) o_case_block +{ + tree case_type; + tree end_label; + int add_break; +}; + +void +start_case_stmt (struct o_case_block *block, tree value) +{ + tree stmt; + tree stmts; + + block->case_type = TREE_TYPE (value); + block->end_label = build_label (); + block->add_break = 0; + stmts = alloc_stmt_list (); + stmt = build3 (SWITCH_EXPR, block->case_type, value, stmts, NULL_TREE); + append_stmt (stmt); + push_stmts (stmts); +} + +void +start_choice (struct o_case_block *block) +{ + tree stmt; + if (block->add_break) + { + stmt = build1 (GOTO_EXPR, block->case_type, block->end_label); + append_stmt (stmt); + + block->add_break = 0; + } +} + +void +new_expr_choice (struct o_case_block *block ATTRIBUTE_UNUSED, tree expr) +{ + tree stmt; + + stmt = build_case_label + (expr, NULL_TREE, create_artificial_label (input_location)); + append_stmt (stmt); +} + +void +new_range_choice (struct o_case_block *block ATTRIBUTE_UNUSED, + tree low, tree high) +{ + tree stmt; + + stmt = build_case_label + (low, high, create_artificial_label (input_location)); + append_stmt (stmt); +} + +void +new_default_choice (struct o_case_block *block ATTRIBUTE_UNUSED) +{ + tree stmt; + + stmt = build_case_label + (NULL_TREE, NULL_TREE, create_artificial_label (input_location)); + append_stmt (stmt); +} + +void +finish_choice (struct o_case_block *block) +{ + block->add_break = 1; +} + +void +finish_case_stmt (struct o_case_block *block) +{ + tree stmt; + + pop_stmts (); + stmt = build1 (LABEL_EXPR, void_type_node, block->end_label); + append_stmt (stmt); +} + +bool +compare_identifier_string (tree id, const char *str, size_t len) +{ + if (IDENTIFIER_LENGTH (id) != len) + return false; + if (!memcmp (IDENTIFIER_POINTER (id), str, len)) + return true; + else + return false; +} + +void +get_identifier_string (tree id, const char **str, int *len) +{ + *len = IDENTIFIER_LENGTH (id); + *str = IDENTIFIER_POINTER (id); +} + +// C linkage wrappers for two (now C++) functions so that +// Ada code can call them without name mangling +tree get_identifier_with_length_c (const char *c, size_t s) +{ + return get_identifier_with_length(c, s); +} + +int toplev_main_c (int argc, char **argv) +{ + return toplev_main(argc, argv); +} + +void +debug_tree_c (tree expr) +{ + warning (OPT_Wall, "Debug tree"); + debug_tree (expr); +} + +} // end extern "C" + +#include "debug.h" +#include "gt-vhdl-ortho-lang.h" +#include "gtype-vhdl.h" diff --git a/src/ortho/gcc/ortho_gcc-main.adb b/src/ortho/gcc/ortho_gcc-main.adb new file mode 100644 index 000000000..70c8a7f79 --- /dev/null +++ b/src/ortho/gcc/ortho_gcc-main.adb @@ -0,0 +1,42 @@ +-- GCC back-end for ortho +-- Copyright (C) 2002-1014 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 System; +with Ortho_Gcc_Front; +with Ada.Command_Line; use Ada.Command_Line; + +procedure Ortho_Gcc.Main +is + gnat_argc : Integer; + gnat_argv : System.Address; + + pragma Import (C, gnat_argc); + pragma Import (C, gnat_argv); + + function Toplev_Main (Argc : Integer; Argv : System.Address) + return Integer; + pragma Import (C, Toplev_Main, "toplev_main_c"); + + Status : Exit_Status; +begin + Ortho_Gcc_Front.Init; + + -- Note: GCC set signal handlers... + Status := Exit_Status (Toplev_Main (gnat_argc, gnat_argv)); + Set_Exit_Status (Status); +end Ortho_Gcc.Main; diff --git a/src/ortho/gcc/ortho_gcc-main.ads b/src/ortho/gcc/ortho_gcc-main.ads new file mode 100644 index 000000000..4bd73a1b6 --- /dev/null +++ b/src/ortho/gcc/ortho_gcc-main.ads @@ -0,0 +1 @@ +procedure Ortho_Gcc.Main; diff --git a/src/ortho/gcc/ortho_gcc.adb b/src/ortho/gcc/ortho_gcc.adb new file mode 100644 index 000000000..ae7b4f53b --- /dev/null +++ b/src/ortho/gcc/ortho_gcc.adb @@ -0,0 +1,121 @@ +-- GCC back-end for ortho. +-- Copyright (C) 2002-1014 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.Unchecked_Deallocation; +with Ortho_Gcc_Front; use Ortho_Gcc_Front; + +package body Ortho_Gcc is + + function New_Lit (Lit : O_Cnode) return O_Enode is + begin + return O_Enode (Lit); + end New_Lit; + + function New_Obj (Obj : O_Dnode) return O_Lnode is + begin + return O_Lnode (Obj); + end New_Obj; + + function New_Obj_Value (Obj : O_Dnode) return O_Enode is + begin + return O_Enode (Obj); + end New_Obj_Value; + + procedure New_Debug_Filename_Decl (Filename : String) is + begin + null; + end New_Debug_Filename_Decl; + + procedure New_Debug_Comment_Decl (Comment : String) + is + pragma Unreferenced (Comment); + begin + null; + end New_Debug_Comment_Decl; + + procedure New_Debug_Comment_Stmt (Comment : String) + is + pragma Unreferenced (Comment); + begin + null; + end New_Debug_Comment_Stmt; + + -- Representation of a C String: this is an access to a bounded string. + -- Therefore, with GNAT, such an access is a thin pointer. + subtype Fat_C_String is String (Positive); + type C_String is access all Fat_C_String; + pragma Convention (C, C_String); + + C_String_Null : constant C_String := null; + + -- Return the length of a C String (ie, the number of characters before + -- the Nul). + function C_String_Len (Str : C_String) return Natural; + pragma Import (C, C_String_Len, "strlen"); + + function Lang_Handle_Option (Opt : C_String; Arg : C_String) + return Integer; + pragma Export (C, Lang_Handle_Option); + + function Lang_Parse_File (Filename : C_String) return Integer; + pragma Export (C, Lang_Parse_File); + + function Lang_Handle_Option (Opt : C_String; Arg : C_String) + return Integer + is + procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation + (Name => String_Acc, Object => String); + + Res : Natural; + Ada_Opt : String_Acc; + Ada_Arg : String_Acc; + Len : Natural; + begin + Len := C_String_Len (Opt); + Ada_Opt := new String'(Opt (1 .. Len)); + if Arg /= C_String_Null then + Len := C_String_Len (Arg); + Ada_Arg := new String'(Arg (1 .. Len)); + else + Ada_Arg := null; + end if; + Res := Ortho_Gcc_Front.Decode_Option (Ada_Opt, Ada_Arg); + Unchecked_Deallocation (Ada_Opt); + Unchecked_Deallocation (Ada_Arg); + return Res; + end Lang_Handle_Option; + + function Lang_Parse_File (Filename : C_String) return Integer + is + Len : Natural; + File : String_Acc; + begin + if Filename = C_String_Null then + File := null; + else + Len := C_String_Len (Filename); + File := new String'(Filename.all (1 .. Len)); + end if; + + if Ortho_Gcc_Front.Parse (File) then + return 1; + else + return 0; + end if; + end Lang_Parse_File; + +end Ortho_Gcc; diff --git a/src/ortho/gcc/ortho_gcc.ads b/src/ortho/gcc/ortho_gcc.ads new file mode 100644 index 000000000..0afdc0887 --- /dev/null +++ b/src/ortho/gcc/ortho_gcc.ads @@ -0,0 +1,701 @@ +-- DO NOT MODIFY - this file was generated from: +-- ortho_nodes.common.ads and ortho_gcc.private.ads +-- +-- GCC back-end for ortho. +-- Copyright (C) 2002-1014 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 System; +with Interfaces; use Interfaces; +with Ortho_Ident; +use Ortho_Ident; + +-- Interface to create nodes. +package Ortho_Gcc is + +-- Start of common part + + type O_Enode is private; + type O_Cnode is private; + type O_Lnode is private; + type O_Tnode is private; + type O_Snode is private; + type O_Dnode is private; + type O_Fnode is private; + + O_Cnode_Null : constant O_Cnode; + O_Dnode_Null : constant O_Dnode; + O_Enode_Null : constant O_Enode; + O_Fnode_Null : constant O_Fnode; + O_Lnode_Null : constant O_Lnode; + O_Snode_Null : constant O_Snode; + O_Tnode_Null : constant O_Tnode; + + -- True if the code generated supports nested subprograms. + Has_Nested_Subprograms : constant Boolean; + + ------------------------ + -- Type definitions -- + ------------------------ + + type O_Element_List is limited private; + + -- Build a record type. + procedure Start_Record_Type (Elements : out O_Element_List); + -- Add a field in the record; not constrained array are prohibited, since + -- its size is unlimited. + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode); + -- Finish the record type. + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an uncomplete record type: + -- First call NEW_UNCOMPLETE_RECORD_TYPE, which returns a record type. + -- This type can be declared or used to define access types on it. + -- Then, complete (if necessary) the record type, by calling + -- START_UNCOMPLETE_RECORD_TYPE, NEW_RECORD_FIELD and FINISH_RECORD_TYPE. + procedure New_Uncomplete_Record_Type (Res : out O_Tnode); + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List); + + -- Build an union type. + procedure Start_Union_Type (Elements : out O_Element_List); + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode); + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an access type. + -- DTYPE may be O_tnode_null in order to build an incomplete access type. + -- It is completed with finish_access_type. + function New_Access_Type (Dtype : O_Tnode) return O_Tnode; + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode); + + -- Build an array type. + -- The array is not constrained and unidimensional. + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode; + + -- Build a constrained array type. + function New_Constrained_Array_Type (Atype : O_Tnode; Length : O_Cnode) + return O_Tnode; + + -- Build a scalar type; size may be 8, 16, 32 or 64. + function New_Unsigned_Type (Size : Natural) return O_Tnode; + function New_Signed_Type (Size : Natural) return O_Tnode; + + -- Build a float type. + function New_Float_Type return O_Tnode; + + -- Build a boolean type. + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode); + + -- Create an enumeration + type O_Enum_List is limited private; + + -- Elements are declared in order, the first is ordered from 0. + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural); + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; Res : out O_Cnode); + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode); + + ---------------- + -- Literals -- + ---------------- + + -- Create a literal from an integer. + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode; + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode; + + -- Create a null access literal. + function New_Null_Access (Ltype : O_Tnode) return O_Cnode; + + -- Build a record/array aggregate. + -- The aggregate is constant, and therefore can be only used to initialize + -- constant declaration. + -- ATYPE must be either a record type or an array subtype. + -- Elements must be added in the order, and must be literals or aggregates. + type O_Record_Aggr_List is limited private; + type O_Array_Aggr_List is limited private; + + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; + Atype : O_Tnode); + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode); + procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; + Res : out O_Cnode); + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode); + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode); + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode); + + -- Build an union aggregate. + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode; + + -- Returns the size in bytes of ATYPE. The result is a literal of + -- unsigned type RTYPE + -- ATYPE cannot be an unconstrained array type. + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the alignment in bytes for ATYPE. The result is a literal of + -- unsgined type RTYPE. + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the offset of FIELD in its record ATYPE. The result is a + -- literal of unsigned type or access type RTYPE. + function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode; + + -- Get the address of a subprogram. + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Same as New_Address but without any restriction. + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + ------------------- + -- Expressions -- + ------------------- + + type ON_Op_Kind is + ( + -- Not an operation; invalid. + ON_Nil, + + -- Dyadic operations. + ON_Add_Ov, -- ON_Dyadic_Op_Kind + ON_Sub_Ov, -- ON_Dyadic_Op_Kind + ON_Mul_Ov, -- ON_Dyadic_Op_Kind + ON_Div_Ov, -- ON_Dyadic_Op_Kind + ON_Rem_Ov, -- ON_Dyadic_Op_Kind + ON_Mod_Ov, -- ON_Dyadic_Op_Kind + + -- Binary operations. + ON_And, -- ON_Dyadic_Op_Kind + ON_Or, -- ON_Dyadic_Op_Kind + ON_Xor, -- ON_Dyadic_Op_Kind + + -- Monadic operations. + ON_Not, -- ON_Monadic_Op_Kind + ON_Neg_Ov, -- ON_Monadic_Op_Kind + ON_Abs_Ov, -- ON_Monadic_Op_Kind + + -- Comparaisons + ON_Eq, -- ON_Compare_Op_Kind + ON_Neq, -- ON_Compare_Op_Kind + ON_Le, -- ON_Compare_Op_Kind + ON_Lt, -- ON_Compare_Op_Kind + ON_Ge, -- ON_Compare_Op_Kind + ON_Gt -- ON_Compare_Op_Kind + ); + + subtype ON_Dyadic_Op_Kind is ON_Op_Kind range ON_Add_Ov .. ON_Xor; + subtype ON_Monadic_Op_Kind is ON_Op_Kind range ON_Not .. ON_Abs_Ov; + subtype ON_Compare_Op_Kind is ON_Op_Kind range ON_Eq .. ON_Gt; + + type O_Storage is (O_Storage_External, + O_Storage_Public, + O_Storage_Private, + O_Storage_Local); + -- Specifies the storage kind of a declaration. + -- O_STORAGE_EXTERNAL: + -- The declaration do not either reserve memory nor generate code, and + -- is imported either from an other file or from a later place in the + -- current file. + -- O_STORAGE_PUBLIC, O_STORAGE_PRIVATE: + -- The declaration reserves memory or generates code. + -- With O_STORAGE_PUBLIC, the declaration is exported outside of the + -- file while with O_STORAGE_PRIVATE, the declaration is local to the + -- file. + + Type_Error : exception; + Syntax_Error : exception; + + -- Create a value from a literal. + function New_Lit (Lit : O_Cnode) return O_Enode; + + -- Create a dyadic operation. + -- Left and right nodes must have the same type. + -- Binary operation is allowed only on boolean types. + -- The result is of the type of the operands. + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode; + + -- Create a monadic operation. + -- Result is of the type of operand. + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode; + + -- Create a comparaison operator. + -- NTYPE is the type of the result and must be a boolean type. + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) + return O_Enode; + + + type O_Inter_List is limited private; + type O_Assoc_List is limited private; + type O_If_Block is limited private; + type O_Case_Block is limited private; + + + -- 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; + + -- 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; + + -- Get an element of a record. + -- Type of REC must be a record type. + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode; + + -- Reference an access. + -- Type of ACC must be an access type. + function New_Access_Element (Acc : O_Enode) return O_Lnode; + + -- Do a conversion. + -- Allowed conversions are: + -- FIXME: to write. + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode; + + -- Same as New_Address but without any restriction. + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode; + + -- Get the value of an Lvalue. + function New_Value (Lvalue : O_Lnode) return O_Enode; + function New_Obj_Value (Obj : O_Dnode) return O_Enode; + + -- Get an lvalue from a declaration. + function New_Obj (Obj : O_Dnode) return O_Lnode; + + -- Return a pointer of type RTPE to SIZE bytes allocated on the stack. + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode; + + -- Declare a type. + -- This simply gives a name to a type. + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode); + + --------------------- + -- Declarations. -- + --------------------- + + -- Filename of the next declaration. + procedure New_Debug_Filename_Decl (Filename : String); + + -- Line number of the next declaration. + procedure New_Debug_Line_Decl (Line : Natural); + + -- Add a comment in the declarative region. + procedure New_Debug_Comment_Decl (Comment : String); + + -- Declare a constant. + -- This simply gives a name to a constant value or aggregate. + -- A constant cannot be modified and its storage cannot be local. + -- ATYPE must be constrained. + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Set the value of a non-external constant. + procedure Start_Const_Value (Const : in out O_Dnode); + procedure Finish_Const_Value (Const : in out O_Dnode; Val : O_Cnode); + + -- Create a variable declaration. + -- A variable can be local only inside a function. + -- ATYPE must be constrained. + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Start a subprogram declaration. + -- Note: nested subprograms are allowed, ie o_storage_local subprograms can + -- be declared inside a subprograms. It is not allowed to declare + -- o_storage_external subprograms inside a subprograms. + -- Return type and interfaces cannot be a composite type. + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode); + -- For a subprogram without return value. + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage); + + -- Add an interface declaration to INTERFACES. + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode); + -- Finish the function declaration, get the node and a statement list. + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode); + -- Start a subprogram body. + -- Note: the declaration may have an external storage, in this case it + -- becomes public. + procedure Start_Subprogram_Body (Func : O_Dnode); + -- Finish a subprogram body. + procedure Finish_Subprogram_Body; + + + ------------------- + -- Statements. -- + ------------------- + + -- Add a line number as a statement. + procedure New_Debug_Line_Stmt (Line : Natural); + + -- Add a comment as a statement. + procedure New_Debug_Comment_Stmt (Comment : String); + + -- Start a declarative region. + procedure Start_Declare_Stmt; + procedure Finish_Declare_Stmt; + + -- Create a function call or a procedure call. + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode); + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode); + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode; + procedure New_Procedure_Call (Assocs : in out O_Assoc_List); + + -- Assign VALUE to TARGET, type must be the same or compatible. + -- FIXME: what about slice assignment? + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode); + + -- Exit from the subprogram and return VALUE. + procedure New_Return_Stmt (Value : O_Enode); + -- Exit from the subprogram, which doesn't return value. + procedure New_Return_Stmt; + + -- Build an IF statement. + procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode); + procedure New_Else_Stmt (Block : in out O_If_Block); + procedure Finish_If_Stmt (Block : in out O_If_Block); + + -- Create a infinite loop statement. + procedure Start_Loop_Stmt (Label : out O_Snode); + procedure Finish_Loop_Stmt (Label : in out O_Snode); + + -- Exit from a loop stmt or from a for stmt. + procedure New_Exit_Stmt (L : O_Snode); + -- Go to the start of a loop stmt or of a for stmt. + -- Loops/Fors between L and the current points are exited. + procedure New_Next_Stmt (L : O_Snode); + + -- Case statement. + -- VALUE is the selector and must be a discrete type. + procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode); + -- A choice branch is composed of expr, range or default choices. + -- A choice branch is enclosed between a Start_Choice and a Finish_Choice. + -- The statements are after the finish_choice. + procedure Start_Choice (Block : in out O_Case_Block); + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode); + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode); + procedure New_Default_Choice (Block : in out O_Case_Block); + procedure Finish_Choice (Block : in out O_Case_Block); + procedure Finish_Case_Stmt (Block : in out O_Case_Block); + +-- End of common part +private + -- GCC supports nested subprograms. + Has_Nested_Subprograms : constant Boolean := True; + + pragma Convention (C, O_Storage); + -- pragma Convention (C, ON_Op_Kind); + + subtype Tree is System.Address; + NULL_TREE : constant Tree := System.Null_Address; + + subtype Vec_Ptr is System.Address; + + type O_Cnode is new Tree; + type O_Enode is new Tree; + type O_Lnode is new Tree; + type O_Tnode is new Tree; + type O_Fnode is new Tree; + type O_Dnode is new Tree; + type O_Snode is record + Beg_Label : Tree; + End_Label : Tree; + end record; + pragma Convention (C, O_Snode); + + O_Cnode_Null : constant O_Cnode := O_Cnode (NULL_TREE); + O_Enode_Null : constant O_Enode := O_Enode (NULL_TREE); + O_Lnode_Null : constant O_Lnode := O_Lnode (NULL_TREE); + O_Tnode_Null : constant O_Tnode := O_Tnode (NULL_TREE); + O_Fnode_Null : constant O_Fnode := O_Fnode (NULL_TREE); + O_Snode_Null : constant O_Snode := (NULL_TREE, NULL_TREE); + O_Dnode_Null : constant O_Dnode := O_Dnode (NULL_TREE); + + pragma Inline (New_Lit); + pragma Inline (New_Obj); + pragma Inline (New_Obj_Value); + + -- Efficiently append element EL to a chain. + -- FIRST is the first element of the chain (must NULL_TREE if the chain + -- is empty), + -- LAST is the last element of the chain (idem). + type Chain_Constr_Type is record + First : Tree; + Last : Tree; + end record; + pragma Convention (C, Chain_Constr_Type); + procedure Chain_Init (Constr : out Chain_Constr_Type); + pragma Import (C, Chain_Init); + procedure Chain_Append (Constr : in out Chain_Constr_Type; El : Tree); + pragma Import (C, Chain_Append); + + -- Efficiently append element EL to a list. + type List_Constr_Type is record + First : Tree; + Last : Tree; + end record; + pragma Convention (C, List_Constr_Type); + procedure List_Init (Constr : out List_Constr_Type); + pragma Import (C, List_Init); + procedure List_Append (Constr : in out List_Constr_Type; El : Tree); + pragma Import (C, List_Append, "ortho_list_append"); + + type O_Loop_Block is record + Beg_Label : Tree; + End_Label : Tree; + end record; + pragma Convention (C, O_Loop_Block); + + type O_Inter_List is record + Ident : O_Ident; + Storage : O_Storage; + -- Return type. + Rtype : O_Tnode; + -- List of parameter types. + Param_List : List_Constr_Type; + -- Chain of parameters declarations. + Param_Chain : Chain_Constr_Type; + end record; + pragma Convention (C, O_Inter_List); + + type O_Element_List is record + Res : Tree; + Chain : Chain_Constr_Type; + end record; + pragma Convention (C, O_Element_List); + + type O_Case_Block is record + Case_Type : Tree; + End_Label : Tree; + Add_Break : Integer; + end record; + pragma Convention (C, O_Case_Block); + + type O_If_Block is record + Stmt : Tree; + end record; + pragma Convention (C, O_If_Block); + + type O_Aggr_List is record + Atype : Tree; + Chain : Chain_Constr_Type; + end record; + + type O_Record_Aggr_List is record + Atype : Tree; + Afield : Tree; + Vec : Vec_Ptr; + end record; + pragma Convention (C, O_Record_Aggr_List); + + type O_Array_Aggr_List is record + Atype : Tree; + Vec : Vec_Ptr; + end record; + pragma Convention (C, O_Array_Aggr_List); + + type O_Assoc_List is record + Subprg : Tree; + List : List_Constr_Type; + end record; + pragma Convention (C, O_Assoc_List); + + type O_Enum_List is record + -- The enumeral_type node. + Res : Tree; + -- Chain of literals. + Chain : Chain_Constr_Type; + -- Numeral value (from 0 to nbr - 1) of the next literal to be declared. + Num : Natural; + -- Size of the enumeration type. + Size : Natural; + end record; + pragma Convention (C, O_Enum_List); + + pragma Import (C, New_Dyadic_Op); + pragma Import (C, New_Monadic_Op); + pragma Import (C, New_Compare_Op); + + pragma Import (C, New_Convert_Ov); + pragma Import (C, New_Alloca); + + pragma Import (C, New_Signed_Literal); + pragma Import (C, New_Unsigned_Literal); + pragma Import (C, New_Float_Literal); + pragma Import (C, New_Null_Access); + + pragma Import (C, Start_Record_Type); + pragma Import (C, New_Record_Field); + pragma Import (C, Finish_Record_Type); + pragma Import (C, New_Uncomplete_Record_Type); + pragma Import (C, Start_Uncomplete_Record_Type); + + pragma Import (C, Start_Union_Type); + pragma Import (C, New_Union_Field); + pragma Import (C, Finish_Union_Type); + + pragma Import (C, New_Unsigned_Type); + pragma Import (C, New_Signed_Type); + pragma Import (C, New_Float_Type); + + pragma Import (C, New_Access_Type); + pragma Import (C, Finish_Access_Type); + + pragma Import (C, New_Array_Type); + pragma Import (C, New_Constrained_Array_Type); + + pragma Import (C, New_Boolean_Type); + pragma Import (C, Start_Enum_Type); + pragma Import (C, New_Enum_Literal); + pragma Import (C, Finish_Enum_Type); + + pragma Import (C, Start_Record_Aggr); + pragma Import (C, New_Record_Aggr_El); + pragma Import (C, Finish_Record_Aggr); + pragma Import (C, Start_Array_Aggr); + pragma Import (C, New_Array_Aggr_El); + pragma Import (C, Finish_Array_Aggr); + pragma Import (C, New_Union_Aggr); + + pragma Import (C, New_Indexed_Element); + pragma Import (C, New_Slice); + pragma Import (C, New_Selected_Element); + pragma Import (C, New_Access_Element); + + pragma Import (C, New_Sizeof); + pragma Import (C, New_Alignof); + pragma Import (C, New_Offsetof); + + pragma Import (C, New_Address); + pragma Import (C, New_Global_Address); + pragma Import (C, New_Unchecked_Address); + pragma Import (C, New_Global_Unchecked_Address); + pragma Import (C, New_Subprogram_Address); + + pragma Import (C, New_Value); + + pragma Import (C, New_Type_Decl); + pragma Import (C, New_Debug_Line_Decl); + pragma Import (C, New_Const_Decl); + pragma Import (C, New_Var_Decl); + + pragma Import (C, Start_Const_Value); + pragma Import (C, Finish_Const_Value); + + pragma Import (C, Start_Function_Decl); + pragma Import (C, Start_Procedure_Decl); + pragma Import (C, New_Interface_Decl); + pragma Import (C, Finish_Subprogram_Decl); + + pragma Import (C, Start_Subprogram_Body); + pragma Import (C, Finish_Subprogram_Body); + + pragma Import (C, New_Debug_Line_Stmt); + pragma Import (C, Start_Declare_Stmt); + pragma Import (C, Finish_Declare_Stmt); + pragma Import (C, Start_Association); + pragma Import (C, New_Association); + pragma Import (C, New_Function_Call); + pragma Import (C, New_Procedure_Call); + + pragma Import (C, New_Assign_Stmt); + + pragma Import (C, Start_If_Stmt); + pragma Import (C, New_Else_Stmt); + pragma Import (C, Finish_If_Stmt); + + pragma Import (C, New_Return_Stmt); + pragma Import_Procedure (New_Return_Stmt, + "new_func_return_stmt", (O_Enode)); + pragma Import_Procedure (New_Return_Stmt, + "new_proc_return_stmt", null); + + pragma Import (C, Start_Loop_Stmt); + pragma Import (C, Finish_Loop_Stmt); + pragma Import (C, New_Exit_Stmt); + pragma Import (C, New_Next_Stmt); + + pragma Import (C, Start_Case_Stmt); + pragma Import (C, Start_Choice); + pragma Import (C, New_Expr_Choice); + pragma Import (C, New_Range_Choice); + pragma Import (C, New_Default_Choice); + pragma Import (C, Finish_Choice); + pragma Import (C, Finish_Case_Stmt); +end Ortho_Gcc; diff --git a/src/ortho/gcc/ortho_gcc.private.ads b/src/ortho/gcc/ortho_gcc.private.ads new file mode 100644 index 000000000..cc2f556f0 --- /dev/null +++ b/src/ortho/gcc/ortho_gcc.private.ads @@ -0,0 +1,269 @@ +-- GCC back-end for ortho. +-- Copyright (C) 2002-1014 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 System; +with Interfaces; use Interfaces; +with Ortho_Ident; +use Ortho_Ident; + +-- Interface to create nodes. +package Ortho_Gcc is + +private + -- GCC supports nested subprograms. + Has_Nested_Subprograms : constant Boolean := True; + + pragma Convention (C, O_Storage); + -- pragma Convention (C, ON_Op_Kind); + + subtype Tree is System.Address; + NULL_TREE : constant Tree := System.Null_Address; + + subtype Vec_Ptr is System.Address; + + type O_Cnode is new Tree; + type O_Enode is new Tree; + type O_Lnode is new Tree; + type O_Tnode is new Tree; + type O_Fnode is new Tree; + type O_Dnode is new Tree; + type O_Snode is record + Beg_Label : Tree; + End_Label : Tree; + end record; + pragma Convention (C, O_Snode); + + O_Cnode_Null : constant O_Cnode := O_Cnode (NULL_TREE); + O_Enode_Null : constant O_Enode := O_Enode (NULL_TREE); + O_Lnode_Null : constant O_Lnode := O_Lnode (NULL_TREE); + O_Tnode_Null : constant O_Tnode := O_Tnode (NULL_TREE); + O_Fnode_Null : constant O_Fnode := O_Fnode (NULL_TREE); + O_Snode_Null : constant O_Snode := (NULL_TREE, NULL_TREE); + O_Dnode_Null : constant O_Dnode := O_Dnode (NULL_TREE); + + pragma Inline (New_Lit); + pragma Inline (New_Obj); + pragma Inline (New_Obj_Value); + + -- Efficiently append element EL to a chain. + -- FIRST is the first element of the chain (must NULL_TREE if the chain + -- is empty), + -- LAST is the last element of the chain (idem). + type Chain_Constr_Type is record + First : Tree; + Last : Tree; + end record; + pragma Convention (C, Chain_Constr_Type); + procedure Chain_Init (Constr : out Chain_Constr_Type); + pragma Import (C, Chain_Init); + procedure Chain_Append (Constr : in out Chain_Constr_Type; El : Tree); + pragma Import (C, Chain_Append); + + -- Efficiently append element EL to a list. + type List_Constr_Type is record + First : Tree; + Last : Tree; + end record; + pragma Convention (C, List_Constr_Type); + procedure List_Init (Constr : out List_Constr_Type); + pragma Import (C, List_Init); + procedure List_Append (Constr : in out List_Constr_Type; El : Tree); + pragma Import (C, List_Append, "ortho_list_append"); + + type O_Loop_Block is record + Beg_Label : Tree; + End_Label : Tree; + end record; + pragma Convention (C, O_Loop_Block); + + type O_Inter_List is record + Ident : O_Ident; + Storage : O_Storage; + -- Return type. + Rtype : O_Tnode; + -- List of parameter types. + Param_List : List_Constr_Type; + -- Chain of parameters declarations. + Param_Chain : Chain_Constr_Type; + end record; + pragma Convention (C, O_Inter_List); + + type O_Element_List is record + Res : Tree; + Chain : Chain_Constr_Type; + end record; + pragma Convention (C, O_Element_List); + + type O_Case_Block is record + Case_Type : Tree; + End_Label : Tree; + Add_Break : Integer; + end record; + pragma Convention (C, O_Case_Block); + + type O_If_Block is record + Stmt : Tree; + end record; + pragma Convention (C, O_If_Block); + + type O_Aggr_List is record + Atype : Tree; + Chain : Chain_Constr_Type; + end record; + + type O_Record_Aggr_List is record + Atype : Tree; + Afield : Tree; + Vec : Vec_Ptr; + end record; + pragma Convention (C, O_Record_Aggr_List); + + type O_Array_Aggr_List is record + Atype : Tree; + Vec : Vec_Ptr; + end record; + pragma Convention (C, O_Array_Aggr_List); + + type O_Assoc_List is record + Subprg : Tree; + List : List_Constr_Type; + end record; + pragma Convention (C, O_Assoc_List); + + type O_Enum_List is record + -- The enumeral_type node. + Res : Tree; + -- Chain of literals. + Chain : Chain_Constr_Type; + -- Numeral value (from 0 to nbr - 1) of the next literal to be declared. + Num : Natural; + -- Size of the enumeration type. + Size : Natural; + end record; + pragma Convention (C, O_Enum_List); + + pragma Import (C, New_Dyadic_Op); + pragma Import (C, New_Monadic_Op); + pragma Import (C, New_Compare_Op); + + pragma Import (C, New_Convert_Ov); + pragma Import (C, New_Alloca); + + pragma Import (C, New_Signed_Literal); + pragma Import (C, New_Unsigned_Literal); + pragma Import (C, New_Float_Literal); + pragma Import (C, New_Null_Access); + + pragma Import (C, Start_Record_Type); + pragma Import (C, New_Record_Field); + pragma Import (C, Finish_Record_Type); + pragma Import (C, New_Uncomplete_Record_Type); + pragma Import (C, Start_Uncomplete_Record_Type); + + pragma Import (C, Start_Union_Type); + pragma Import (C, New_Union_Field); + pragma Import (C, Finish_Union_Type); + + pragma Import (C, New_Unsigned_Type); + pragma Import (C, New_Signed_Type); + pragma Import (C, New_Float_Type); + + pragma Import (C, New_Access_Type); + pragma Import (C, Finish_Access_Type); + + pragma Import (C, New_Array_Type); + pragma Import (C, New_Constrained_Array_Type); + + pragma Import (C, New_Boolean_Type); + pragma Import (C, Start_Enum_Type); + pragma Import (C, New_Enum_Literal); + pragma Import (C, Finish_Enum_Type); + + pragma Import (C, Start_Record_Aggr); + pragma Import (C, New_Record_Aggr_El); + pragma Import (C, Finish_Record_Aggr); + pragma Import (C, Start_Array_Aggr); + pragma Import (C, New_Array_Aggr_El); + pragma Import (C, Finish_Array_Aggr); + pragma Import (C, New_Union_Aggr); + + pragma Import (C, New_Indexed_Element); + pragma Import (C, New_Slice); + pragma Import (C, New_Selected_Element); + pragma Import (C, New_Access_Element); + + pragma Import (C, New_Sizeof); + pragma Import (C, New_Alignof); + pragma Import (C, New_Offsetof); + + pragma Import (C, New_Address); + pragma Import (C, New_Global_Address); + pragma Import (C, New_Unchecked_Address); + pragma Import (C, New_Global_Unchecked_Address); + pragma Import (C, New_Subprogram_Address); + + pragma Import (C, New_Value); + + pragma Import (C, New_Type_Decl); + pragma Import (C, New_Debug_Line_Decl); + pragma Import (C, New_Const_Decl); + pragma Import (C, New_Var_Decl); + + pragma Import (C, Start_Const_Value); + pragma Import (C, Finish_Const_Value); + + pragma Import (C, Start_Function_Decl); + pragma Import (C, Start_Procedure_Decl); + pragma Import (C, New_Interface_Decl); + pragma Import (C, Finish_Subprogram_Decl); + + pragma Import (C, Start_Subprogram_Body); + pragma Import (C, Finish_Subprogram_Body); + + pragma Import (C, New_Debug_Line_Stmt); + pragma Import (C, Start_Declare_Stmt); + pragma Import (C, Finish_Declare_Stmt); + pragma Import (C, Start_Association); + pragma Import (C, New_Association); + pragma Import (C, New_Function_Call); + pragma Import (C, New_Procedure_Call); + + pragma Import (C, New_Assign_Stmt); + + pragma Import (C, Start_If_Stmt); + pragma Import (C, New_Else_Stmt); + pragma Import (C, Finish_If_Stmt); + + pragma Import (C, New_Return_Stmt); + pragma Import_Procedure (New_Return_Stmt, + "new_func_return_stmt", (O_Enode)); + pragma Import_Procedure (New_Return_Stmt, + "new_proc_return_stmt", null); + + pragma Import (C, Start_Loop_Stmt); + pragma Import (C, Finish_Loop_Stmt); + pragma Import (C, New_Exit_Stmt); + pragma Import (C, New_Next_Stmt); + + pragma Import (C, Start_Case_Stmt); + pragma Import (C, Start_Choice); + pragma Import (C, New_Expr_Choice); + pragma Import (C, New_Range_Choice); + pragma Import (C, New_Default_Choice); + pragma Import (C, Finish_Choice); + pragma Import (C, Finish_Case_Stmt); +end Ortho_Gcc; diff --git a/src/ortho/gcc/ortho_gcc_front.ads b/src/ortho/gcc/ortho_gcc_front.ads new file mode 100644 index 000000000..553057b20 --- /dev/null +++ b/src/ortho/gcc/ortho_gcc_front.ads @@ -0,0 +1,2 @@ +with Ortho_Front; +package Ortho_Gcc_Front renames Ortho_Front; diff --git a/src/ortho/gcc/ortho_ident.adb b/src/ortho/gcc/ortho_ident.adb new file mode 100644 index 000000000..770fece2b --- /dev/null +++ b/src/ortho/gcc/ortho_ident.adb @@ -0,0 +1,56 @@ +-- GCC back-end for ortho (identifiers) +-- Copyright (C) 2002-1014 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. + +package body Ortho_Ident is + function Get_Identifier_With_Length (Str : Address; Size : Integer) + return O_Ident; + pragma Import (C, Get_Identifier_With_Length, + "get_identifier_with_length_c"); + + function Compare_Identifier_String + (Id : O_Ident; Str : Address; Size : Integer) + return Boolean; + pragma Import (C, Compare_Identifier_String); + pragma Warnings (Off, Compare_Identifier_String); + + function Get_Identifier (Str : String) return O_Ident is + begin + return Get_Identifier_With_Length (Str'Address, Str'Length); + end Get_Identifier; + + function Is_Equal (Id : O_Ident; Str : String) return Boolean is + begin + return Compare_Identifier_String (Id, Str'Address, Str'Length); + end Is_Equal; + + function Get_String (Id : O_Ident) return String + is + procedure Get_Identifier_String + (Id : O_Ident; Str_Ptr : Address; Len_Ptr : Address); + pragma Import (C, Get_Identifier_String); + + Len : Natural; + type Str_Acc is access String (Positive); + Str : Str_Acc; + begin + Get_Identifier_String (Id, Str'Address, Len'Address); + return Str (1 .. Len); + end Get_String; + +end Ortho_Ident; + diff --git a/src/ortho/gcc/ortho_ident.ads b/src/ortho/gcc/ortho_ident.ads new file mode 100644 index 000000000..76c09ceb9 --- /dev/null +++ b/src/ortho/gcc/ortho_ident.ads @@ -0,0 +1,30 @@ +-- GCC back-end for ortho (identifiers) +-- Copyright (C) 2002-1014 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 System; use System; + +package Ortho_Ident is + subtype O_Ident is Address; + function Get_Identifier (Str : String) return O_Ident; + function Get_String (Id : O_Ident) return String; + function Is_Equal (L, R : O_Ident) return Boolean renames System."="; + function Is_Equal (Id : O_Ident; Str : String) return Boolean; + O_Ident_Nul : constant O_Ident; +private + O_Ident_Nul : constant O_Ident := Null_Address; +end Ortho_Ident; diff --git a/src/ortho/gcc/ortho_nodes.ads b/src/ortho/gcc/ortho_nodes.ads new file mode 100644 index 000000000..7c6c4a076 --- /dev/null +++ b/src/ortho/gcc/ortho_nodes.ads @@ -0,0 +1,3 @@ +with Ortho_Gcc; + +package Ortho_Nodes renames Ortho_Gcc; diff --git a/src/ortho/llvm/Makefile b/src/ortho/llvm/Makefile new file mode 100644 index 000000000..135dbdf4b --- /dev/null +++ b/src/ortho/llvm/Makefile @@ -0,0 +1,30 @@ +ortho_srcdir=.. +GNAT_FLAGS=-gnaty3befhkmr -gnata -gnatf -gnatwael -gnat05 +CXX=clang++ --std=c++11 +LLVM_CONFIG=llvm-config +SED=sed +BE=llvm + +all: $(ortho_exec) + +$(ortho_exec): $(ortho_srcdir)/llvm/ortho_llvm.ads force llvm-cbindings.o + gnatmake -m -o $@ -g -aI$(ortho_srcdir)/llvm -aI$(ortho_srcdir) \ + $(GNAT_FLAGS) ortho_code_main -bargs -E \ + -largs llvm-cbindings.o `$(LLVM_CONFIG) --ldflags --libs --system-libs` -lc++ #-static + +llvm-cbindings.o: $(ortho_srcdir)/llvm/llvm-cbindings.cpp + $(CXX) -c -I`$(LLVM_CONFIG) --includedir --cflags` -g -o $@ $< + +clean: + $(RM) -f *.o *.ali ortho_code_main + $(RM) b~*.ad? *~ + +distclean: clean + + +force: + +.PHONY: force all clean + +ORTHO_BASENAME=ortho_llvm +include $(ortho_srcdir)/Makefile.inc diff --git a/src/ortho/llvm/llvm-analysis.ads b/src/ortho/llvm/llvm-analysis.ads new file mode 100644 index 000000000..bfecec579 --- /dev/null +++ b/src/ortho/llvm/llvm-analysis.ads @@ -0,0 +1,53 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with LLVM.Core; use LLVM.Core; + +package LLVM.Analysis is + type VerifierFailureAction is + ( + AbortProcessAction, -- verifier will print to stderr and abort() + PrintMessageAction, -- verifier will print to stderr and return 1 + ReturnStatusAction -- verifier will just return 1 + ); + pragma Convention (C, VerifierFailureAction); + + -- Verifies that a module is valid, taking the specified action if not. + -- Optionally returns a human-readable description of any invalid + -- constructs. + -- OutMessage must be disposed with DisposeMessage. */ + function VerifyModule(M : ModuleRef; + Action : VerifierFailureAction; + OutMessage : access Cstring) + return Integer; + + -- Verifies that a single function is valid, taking the specified + -- action. Useful for debugging. + function VerifyFunction(Fn : ValueRef; Action : VerifierFailureAction) + return Integer; + + -- Open up a ghostview window that displays the CFG of the current function. + -- Useful for debugging. + procedure ViewFunctionCFG(Fn : ValueRef); + procedure ViewFunctionCFGOnly(Fn : ValueRef); +private + pragma Import (C, VerifyModule, "LLVMVerifyModule"); + pragma Import (C, VerifyFunction, "LLVMVerifyFunction"); + pragma Import (C, ViewFunctionCFG, "LLVMViewFunctionCFG"); + pragma Import (C, ViewFunctionCFGOnly, "LLVMViewFunctionCFGOnly"); +end LLVM.Analysis; + diff --git a/src/ortho/llvm/llvm-bitwriter.ads b/src/ortho/llvm/llvm-bitwriter.ads new file mode 100644 index 000000000..3f9c518e4 --- /dev/null +++ b/src/ortho/llvm/llvm-bitwriter.ads @@ -0,0 +1,34 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with LLVM.Core; use LLVM.Core; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Interfaces.C; use Interfaces.C; + +package LLVM.BitWriter is + -- Writes a module to an open file descriptor. Returns 0 on success. + -- Closes the Handle. Use dup first if this is not what you want. + function WriteBitcodeToFileHandle(M : ModuleRef; Handle : File_Descriptor) + return int; + + -- Writes a module to the specified path. Returns 0 on success. + function WriteBitcodeToFile(M : ModuleRef; Path : Cstring) + return int; +private + pragma Import (C, WriteBitcodeToFileHandle, "LLVMWriteBitcodeToFileHandle"); + pragma Import (C, WriteBitcodeToFile, "LLVMWriteBitcodeToFile"); +end LLVM.BitWriter; diff --git a/src/ortho/llvm/llvm-cbindings.cpp b/src/ortho/llvm/llvm-cbindings.cpp new file mode 100644 index 000000000..e4d666ade --- /dev/null +++ b/src/ortho/llvm/llvm-cbindings.cpp @@ -0,0 +1,61 @@ +/* LLVM binding + Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ +#include "llvm-c/Target.h" +#include "llvm-c/Core.h" +#include "llvm-c/ExecutionEngine.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" + +using namespace llvm; + +extern "C" { + +void +LLVMInitializeNativeTarget_noinline (void) +{ + LLVMInitializeNativeTarget (); +} + +void +LLVMInitializeNativeAsmPrinter_noinline (void) +{ + LLVMInitializeNativeAsmPrinter(); +} + +LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { + return (LLVMTypeRef) Type::getMetadataTy(*unwrap(C)); +} + +LLVMTypeRef LLVMMetadataType_extra(void) { + return LLVMMetadataTypeInContext(LLVMGetGlobalContext()); +} + +void +LLVMMDNodeReplaceOperandWith_extra (LLVMValueRef N, unsigned i, LLVMValueRef V) { + MDNode *MD = cast<MDNode>(unwrap(N)); + MD->replaceOperandWith (i, unwrap(V)); +} + +void *LLVMGetPointerToFunction(LLVMExecutionEngineRef EE, LLVMValueRef Func) +{ + return unwrap(EE)->getPointerToFunction(unwrap<Function>(Func)); +} + +} diff --git a/src/ortho/llvm/llvm-core.ads b/src/ortho/llvm/llvm-core.ads new file mode 100644 index 000000000..74a47484f --- /dev/null +++ b/src/ortho/llvm/llvm-core.ads @@ -0,0 +1,1279 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with System; +with Interfaces.C; use Interfaces.C; +use Interfaces; + +package LLVM.Core is + + subtype Cstring is System.Address; + function "=" (L, R : Cstring) return Boolean renames System."="; + -- Null_Cstring : constant Cstring := Null_Address; + Nul : constant String := (1 => Character'Val (0)); + Empty_Cstring : constant Cstring := Nul'Address; + + -- The top-level container for all LLVM global data. See the LLVMContext + -- class. + type ContextRef is new System.Address; + + -- The top-level container for all other LLVM Intermediate + -- Representation (IR) objects. See the llvm::Module class. + type ModuleRef is new System.Address; + + subtype Bool is int; + + -- Each value in the LLVM IR has a type, an LLVMTypeRef. See the llvm::Type + -- class. + type TypeRef is new System.Address; + Null_TypeRef : constant TypeRef := TypeRef (System.Null_Address); + type TypeRefArray is array (unsigned range <>) of TypeRef; + pragma Convention (C, TypeRefArray); + + type ValueRef is new System.Address; + Null_ValueRef : constant ValueRef := ValueRef (System.Null_Address); + type ValueRefArray is array (unsigned range <>) of ValueRef; -- Ada + pragma Convention (C, ValueRefArray); + + type BasicBlockRef is new System.Address; + Null_BasicBlockRef : constant BasicBlockRef := + BasicBlockRef (System.Null_Address); + type BasicBlockRefArray is + array (unsigned range <>) of BasicBlockRef; -- Ada + pragma Convention (C, BasicBlockRefArray); + + type BuilderRef is new System.Address; + + -- Used to provide a module to JIT or interpreter. + -- See the llvm::MemoryBuffer class. + type MemoryBufferRef is new System.Address; + + -- See the llvm::PassManagerBase class. + type PassManagerRef is new System.Address; + + type Attribute is new unsigned; + ZExtAttribute : constant Attribute := 2**0; + SExtAttribute : constant Attribute := 2**1; + NoReturnAttribute : constant Attribute := 2**2; + InRegAttribute : constant Attribute := 2**3; + StructRetAttribute : constant Attribute := 2**4; + NoUnwindAttribute : constant Attribute := 2**5; + NoAliasAttribute : constant Attribute := 2**6; + ByValAttribute : constant Attribute := 2**7; + NestAttribute : constant Attribute := 2**8; + ReadNoneAttribute : constant Attribute := 2**9; + ReadOnlyAttribute : constant Attribute := 2**10; + NoInlineAttribute : constant Attribute := 1**11; + AlwaysInlineAttribute : constant Attribute := 1**12; + OptimizeForSizeAttribute : constant Attribute := 1**13; + StackProtectAttribute : constant Attribute := 1**14; + StackProtectReqAttribute : constant Attribute := 1**15; + Alignment : constant Attribute := 31**16; + NoCaptureAttribute : constant Attribute := 1**21; + NoRedZoneAttribute : constant Attribute := 1**22; + NoImplicitFloatAttribute : constant Attribute := 1**23; + NakedAttribute : constant Attribute := 1**24; + InlineHintAttribute : constant Attribute := 1**25; + StackAlignment : constant Attribute := 7**26; + ReturnsTwice : constant Attribute := 1**29; + UWTable : constant Attribute := 1**30; + NonLazyBind : constant Attribute := 1**31; + + type TypeKind is + ( + VoidTypeKind, -- type with no size + HalfTypeKind, -- 16 bit floating point type + FloatTypeKind, -- 32 bit floating point type + DoubleTypeKind, -- 64 bit floating point type + X86_FP80TypeKind, -- 80 bit floating point type (X87) + FP128TypeKind, -- 128 bit floating point type (112-bit mantissa) + PPC_FP128TypeKind, -- 128 bit floating point type (two 64-bits) + LabelTypeKind, -- Labels + IntegerTypeKind, -- Arbitrary bit width integers + FunctionTypeKind, -- Functions + StructTypeKind, -- Structures + ArrayTypeKind, -- Arrays + PointerTypeKind, -- Pointers + VectorTypeKind, -- SIMD 'packed' format, or other vector type + MetadataTypeKind, -- Metadata + X86_MMXTypeKind -- X86 MMX + ); + pragma Convention (C, TypeKind); + + type Linkage is + ( + ExternalLinkage, -- Externally visible function + AvailableExternallyLinkage, + LinkOnceAnyLinkage, -- Keep one copy of function when linking (inline) + LinkOnceODRLinkage, -- Same, but only replaced by someth equivalent. + LinkOnceODRAutoHideLinkage, -- Obsolete + WeakAnyLinkage, -- Keep one copy of function when linking (weak) + WeakODRLinkage, -- Same, but only replaced by someth equivalent. + AppendingLinkage, -- Special purpose, only applies to global arrays + InternalLinkage, -- Rename collisions when linking (static func) + PrivateLinkage, -- Like Internal, but omit from symbol table + DLLImportLinkage, -- Obsolete + DLLExportLinkage, -- Obsolete + ExternalWeakLinkage,-- ExternalWeak linkage description + GhostLinkage, -- Obsolete + CommonLinkage, -- Tentative definitions + LinkerPrivateLinkage, -- Like Private, but linker removes. + LinkerPrivateWeakLinkage -- Like LinkerPrivate, but is weak. + ); + pragma Convention (C, Linkage); + + type Visibility is + ( + DefaultVisibility, -- The GV is visible + HiddenVisibility, -- The GV is hidden + ProtectedVisibility -- The GV is protected + ); + pragma Convention (C, Visibility); + + type CallConv is new unsigned; + CCallConv : constant CallConv := 0; + FastCallConv : constant CallConv := 8; + ColdCallConv : constant CallConv := 9; + X86StdcallCallConv : constant CallConv := 64; + X86FastcallCallConv : constant CallConv := 6; + + type IntPredicate is new unsigned; + IntEQ : constant IntPredicate := 32; -- equal + IntNE : constant IntPredicate := 33; -- not equal + IntUGT : constant IntPredicate := 34; -- unsigned greater than + IntUGE : constant IntPredicate := 35; -- unsigned greater or equal + IntULT : constant IntPredicate := 36; -- unsigned less than + IntULE : constant IntPredicate := 37; -- unsigned less or equal + IntSGT : constant IntPredicate := 38; -- signed greater than + IntSGE : constant IntPredicate := 39; -- signed greater or equal + IntSLT : constant IntPredicate := 40; -- signed less than + IntSLE : constant IntPredicate := 41; -- signed less or equal + + type RealPredicate is + ( + RealPredicateFalse, -- Always false (always folded) + RealOEQ, -- True if ordered and equal + RealOGT, -- True if ordered and greater than + RealOGE, -- True if ordered and greater than or equal + RealOLT, -- True if ordered and less than + RealOLE, -- True if ordered and less than or equal + RealONE, -- True if ordered and operands are unequal + RealORD, -- True if ordered (no nans) + RealUNO, -- True if unordered: isnan(X) | isnan(Y) + RealUEQ, -- True if unordered or equal + RealUGT, -- True if unordered or greater than + RealUGE, -- True if unordered, greater than, or equal + RealULT, -- True if unordered or less than + RealULE, -- True if unordered, less than, or equal + RealUNE, -- True if unordered or not equal + RealPredicateTrue -- Always true (always folded) + ); + + -- Error handling ---------------------------------------------------- + + procedure DisposeMessage (Message : Cstring); + + + -- Context + + -- Create a new context. + -- Every call to this function should be paired with a call to + -- LLVMContextDispose() or the context will leak memory. + function ContextCreate return ContextRef; + + -- Obtain the global context instance. + function GetGlobalContext return ContextRef; + + -- Destroy a context instance. + -- This should be called for every call to LLVMContextCreate() or memory + -- will be leaked. + procedure ContextDispose (C : ContextRef); + + function GetMDKindIDInContext + (C : ContextRef; Name : Cstring; Slen : unsigned) + return unsigned; + + function GetMDKindID(Name : String; Slen : unsigned) return unsigned; + + -- Modules ----------------------------------------------------------- + + -- Create and destroy modules. + -- See llvm::Module::Module. + function ModuleCreateWithName (ModuleID : Cstring) return ModuleRef; + + -- See llvm::Module::~Module. + procedure DisposeModule (M : ModuleRef); + + -- Data layout. See Module::getDataLayout. + function GetDataLayout(M : ModuleRef) return Cstring; + procedure SetDataLayout(M : ModuleRef; Triple : Cstring); + + -- Target triple. See Module::getTargetTriple. + function GetTarget (M : ModuleRef) return Cstring; + procedure SetTarget (M : ModuleRef; Triple : Cstring); + + -- See Module::dump. + procedure DumpModule(M : ModuleRef); + + -- Print a representation of a module to a file. The ErrorMessage needs to + -- be disposed with LLVMDisposeMessage. Returns 0 on success, 1 otherwise. + -- + -- @see Module::print() + function PrintModuleToFile(M : ModuleRef; + Filename : Cstring; + ErrorMessage : access Cstring) return Bool; + + + -- Types ------------------------------------------------------------- + + -- LLVM types conform to the following hierarchy: + -- + -- types: + -- integer type + -- real type + -- function type + -- sequence types: + -- array type + -- pointer type + -- vector type + -- void type + -- label type + -- opaque type + + -- See llvm::LLVMTypeKind::getTypeID. + function GetTypeKind (Ty : TypeRef) return TypeKind; + + -- Operations on integer types + function Int1Type return TypeRef; + function Int8Type return TypeRef; + function Int16Type return TypeRef; + function Int32Type return TypeRef; + function Int64Type return TypeRef; + function IntType(NumBits : unsigned) return TypeRef; + function GetIntTypeWidth(IntegerTy : TypeRef) return unsigned; + + function MetadataType return TypeRef; + + -- Operations on real types + function FloatType return TypeRef; + function DoubleType return TypeRef; + function X86FP80Type return TypeRef; + function FP128Type return TypeRef; + function PPCFP128Type return TypeRef; + + -- Operations on function types + function FunctionType(ReturnType : TypeRef; + ParamTypes : TypeRefArray; + ParamCount : unsigned; + IsVarArg : int) return TypeRef; + + function IsFunctionVarArg(FunctionTy : TypeRef) return int; + function GetReturnType(FunctionTy : TypeRef) return TypeRef; + function CountParamTypes(FunctionTy : TypeRef) return unsigned; + procedure GetParamTypes(FunctionTy : TypeRef; Dest : out TypeRefArray); + + -- Operations on struct types + function StructType(ElementTypes : TypeRefArray; + ElementCount : unsigned; + Packed : Bool) return TypeRef; + function StructCreateNamed(C : ContextRef; Name : Cstring) return TypeRef; + procedure StructSetBody(StructTy : TypeRef; + ElementTypes : TypeRefArray; + ElementCount : unsigned; + Packed : Bool); + function CountStructElementTypes(StructTy : TypeRef) return unsigned; + procedure GetStructElementTypes(StructTy : TypeRef; + Dest : out TypeRefArray); + function IsPackedStruct(StructTy : TypeRef) return Bool; + + + -- Operations on array, pointer, and vector types (sequence types) + function ArrayType(ElementType : TypeRef; ElementCount : unsigned) + return TypeRef; + function PointerType(ElementType : TypeRef; AddressSpace : unsigned := 0) + return TypeRef; + function VectorType(ElementType : TypeRef; ElementCount : unsigned) + return TypeRef; + + function GetElementType(Ty : TypeRef) return TypeRef; + function GetArrayLength(ArrayTy : TypeRef) return unsigned; + function GetPointerAddressSpace(PointerTy : TypeRef) return unsigned; + function GetVectorSize(VectorTy : TypeRef) return unsigned; + + -- Operations on other types. + function VoidType return TypeRef; + function LabelType return TypeRef; + + -- Values ------------------------------------------------------------ + -- The bulk of LLVM's object model consists of values, which comprise a very + -- rich type hierarchy. + -- + -- values: + -- constants: + -- scalar constants + -- composite contants + -- globals: + -- global variable + -- function + -- alias + -- basic blocks + + -- Operations on all values + function TypeOf(Val : ValueRef) return TypeRef; + function GetValueName(Val : ValueRef) return Cstring; + procedure SetValueName(Val : ValueRef; Name : Cstring); + procedure DumpValue(Val : ValueRef); + + -- Operations on constants of any type + function ConstNull(Ty : TypeRef) return ValueRef; -- All zero + function ConstAllOnes(Ty : TypeRef) return ValueRef; -- Int or Vec + function GetUndef(Ty : TypeRef) return ValueRef; + function IsConstant(Val : ValueRef) return int; + function IsNull(Val : ValueRef) return int; + function IsUndef(Val : ValueRef) return int; + + -- Convert value instances between types. + -- + -- Internally, an LLVMValueRef is "pinned" to a specific type. This + -- series of functions allows you to cast an instance to a specific + -- type. + -- + -- If the cast is not valid for the specified type, NULL is returned. + -- + -- @see llvm::dyn_cast_or_null<> + function IsAInstruction (Val : ValueRef) return ValueRef; + + -- Operations on scalar constants + function ConstInt(IntTy : TypeRef; N : Unsigned_64; SignExtend : int) + return ValueRef; + function ConstReal(RealTy : TypeRef; N : double) return ValueRef; + function ConstRealOfString(RealTy : TypeRef; Text : Cstring) + return ValueRef; + + + -- Obtain the zero extended value for an integer constant value. + -- @see llvm::ConstantInt::getZExtValue() + function ConstIntGetZExtValue (ConstantVal : ValueRef) return Unsigned_64; + + -- Operations on composite constants + function ConstString(Str : Cstring; + Length : unsigned; DontNullTerminate : int) + return ValueRef; + function ConstArray(ElementTy : TypeRef; + ConstantVals : ValueRefArray; Length : unsigned) + return ValueRef; + function ConstStruct(ConstantVals : ValueRefArray; + Count : unsigned; packed : int) return ValueRef; + + -- Create a non-anonymous ConstantStruct from values. + -- @see llvm::ConstantStruct::get() + function ConstNamedStruct(StructTy : TypeRef; + ConstantVals : ValueRefArray; + Count : unsigned) return ValueRef; + + function ConstVector(ScalarConstantVals : ValueRefArray; Size : unsigned) + return ValueRef; + + -- Constant expressions + function SizeOf(Ty : TypeRef) return ValueRef; + function AlignOf(Ty : TypeRef) return ValueRef; + + function ConstNeg(ConstantVal : ValueRef) return ValueRef; + function ConstNot(ConstantVal : ValueRef) return ValueRef; + function ConstAdd(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstSub(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstMul(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstUDiv(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstSDiv(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstFDiv(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstURem(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstSRem(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstFRem(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstAnd(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstOr(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstXor(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstICmp(Predicate : IntPredicate; + LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstFCmp(Predicate : RealPredicate; + LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstShl(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstLShr(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstAShr(LHSConstant : ValueRef; RHSConstant : ValueRef) + return ValueRef; + function ConstGEP(ConstantVal : ValueRef; + ConstantIndices : ValueRefArray; NumIndices : unsigned) + return ValueRef; + function ConstTrunc(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstSExt(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstZExt(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstFPTrunc(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstFPExt(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstUIToFP(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstSIToFP(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstFPToUI(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstFPToSI(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstPtrToInt(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstIntToPtr(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + function ConstBitCast(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + + function ConstTruncOrBitCast(ConstantVal : ValueRef; ToType : TypeRef) + return ValueRef; + + function ConstSelect(ConstantCondition : ValueRef; + ConstantIfTrue : ValueRef; + ConstantIfFalse : ValueRef) return ValueRef; + function ConstExtractElement(VectorConstant : ValueRef; + IndexConstant : ValueRef) return ValueRef; + function ConstInsertElement(VectorConstant : ValueRef; + ElementValueConstant : ValueRef; + IndexConstant : ValueRef) return ValueRef; + function ConstShuffleVector(VectorAConstant : ValueRef; + VectorBConstant : ValueRef; + MaskConstant : ValueRef) return ValueRef; + + -- Operations on global variables, functions, and aliases (globals) + function GetGlobalParent(Global : ValueRef) return ModuleRef; + function IsDeclaration(Global : ValueRef) return int; + function GetLinkage(Global : ValueRef) return Linkage; + procedure SetLinkage(Global : ValueRef; Link : Linkage); + function GetSection(Global : ValueRef) return Cstring; + procedure SetSection(Global : ValueRef; Section : Cstring); + function GetVisibility(Global : ValueRef) return Visibility; + procedure SetVisibility(Global : ValueRef; Viz : Visibility); + function GetAlignment(Global : ValueRef) return unsigned; + procedure SetAlignment(Global : ValueRef; Bytes : unsigned); + + -- Operations on global variables + function AddGlobal(M : ModuleRef; Ty : TypeRef; Name : Cstring) + return ValueRef; + function GetNamedGlobal(M : ModuleRef; Name : Cstring) return ValueRef; + function GetFirstGlobal(M : ModuleRef) return ValueRef; + function GetLastGlobal(M : ModuleRef) return ValueRef; + function GetNextGlobal(GlobalVar : ValueRef) return ValueRef; + function GetPreviousGlobal(GlobalVar : ValueRef) return ValueRef; + procedure DeleteGlobal(GlobalVar : ValueRef); + function GetInitializer(GlobalVar : ValueRef) return ValueRef; + procedure SetInitializer(GlobalVar : ValueRef; ConstantVal : ValueRef); + function IsThreadLocal(GlobalVar : ValueRef) return int; + procedure SetThreadLocal(GlobalVar : ValueRef; IsThreadLocal : int); + function IsGlobalConstant(GlobalVar : ValueRef) return int; + procedure SetGlobalConstant(GlobalVar : ValueRef; IsConstant : int); + + -- Obtain the number of operands for named metadata in a module. + -- @see llvm::Module::getNamedMetadata() + function GetNamedMetadataNumOperands(M : ModuleRef; Name : Cstring) + return unsigned; + + -- Obtain the named metadata operands for a module. + -- The passed LLVMValueRef pointer should refer to an array of + -- LLVMValueRef at least LLVMGetNamedMetadataNumOperands long. This + -- array will be populated with the LLVMValueRef instances. Each + -- instance corresponds to a llvm::MDNode. + -- @see llvm::Module::getNamedMetadata() + -- @see llvm::MDNode::getOperand() + procedure GetNamedMetadataOperands + (M : ModuleRef; Name : Cstring; Dest : ValueRefArray); + + -- Add an operand to named metadata. + -- @see llvm::Module::getNamedMetadata() + -- @see llvm::MDNode::addOperand() + procedure AddNamedMetadataOperand + (M : ModuleRef; Name : Cstring; Val : ValueRef); + + -- Operations on functions + function AddFunction(M : ModuleRef; Name : Cstring; FunctionTy : TypeRef) + return ValueRef; + function GetNamedFunction(M : ModuleRef; Name : Cstring) return ValueRef; + function GetFirstFunction(M : ModuleRef) return ValueRef; + function GetLastFunction(M : ModuleRef) return ValueRef; + function GetNextFunction(Fn : ValueRef) return ValueRef; + function GetPreviousFunction(Fn : ValueRef) return ValueRef; + procedure DeleteFunction(Fn : ValueRef); + function GetIntrinsicID(Fn : ValueRef) return unsigned; + function GetFunctionCallConv(Fn : ValueRef) return CallConv; + procedure SetFunctionCallConv(Fn : ValueRef; CC : CallConv); + function GetGC(Fn : ValueRef) return Cstring; + procedure SetGC(Fn : ValueRef; Name : Cstring); + + -- Add an attribute to a function. + -- @see llvm::Function::addAttribute() + procedure AddFunctionAttr (Fn : ValueRef; PA : Attribute); + + -- Add a target-dependent attribute to a fuction + -- @see llvm::AttrBuilder::addAttribute() + procedure AddTargetDependentFunctionAttr + (Fn : ValueRef; A : Cstring; V : Cstring); + + -- Obtain an attribute from a function. + -- @see llvm::Function::getAttributes() + function GetFunctionAttr (Fn : ValueRef) return Attribute; + + -- Remove an attribute from a function. + procedure RemoveFunctionAttr (Fn : ValueRef; PA : Attribute); + + -- Operations on parameters + function CountParams(Fn : ValueRef) return unsigned; + procedure GetParams(Fn : ValueRef; Params : ValueRefArray); + function GetParam(Fn : ValueRef; Index : unsigned) return ValueRef; + function GetParamParent(Inst : ValueRef) return ValueRef; + function GetFirstParam(Fn : ValueRef) return ValueRef; + function GetLastParam(Fn : ValueRef) return ValueRef; + function GetNextParam(Arg : ValueRef) return ValueRef; + function GetPreviousParam(Arg : ValueRef) return ValueRef; + procedure AddAttribute(Arg : ValueRef; PA : Attribute); + procedure RemoveAttribute(Arg : ValueRef; PA : Attribute); + procedure SetParamAlignment(Arg : ValueRef; align : unsigned); + + -- Metadata + + -- Obtain a MDString value from a context. + -- The returned instance corresponds to the llvm::MDString class. + -- The instance is specified by string data of a specified length. The + -- string content is copied, so the backing memory can be freed after + -- this function returns. + function MDStringInContext(C : ContextRef; Str : Cstring; Len : unsigned) + return ValueRef; + + -- Obtain a MDString value from the global context. + function MDString(Str : Cstring; Len : unsigned) return ValueRef; + + -- Obtain a MDNode value from a context. + -- The returned value corresponds to the llvm::MDNode class. + function MDNodeInContext + (C : ContextRef; Vals : ValueRefArray; Count : unsigned) + return ValueRef; + + -- Obtain a MDNode value from the global context. + function MDNode(Vals : ValueRefArray; Count : unsigned) return ValueRef; + + -- Obtain the underlying string from a MDString value. + -- @param V Instance to obtain string from. + -- @param Len Memory address which will hold length of returned string. + -- @return String data in MDString. + function GetMDString(V : ValueRef; Len : access unsigned) return Cstring; + + -- Obtain the number of operands from an MDNode value. + -- @param V MDNode to get number of operands from. + -- @return Number of operands of the MDNode. + function GetMDNodeNumOperands(V : ValueRef) return unsigned; + + -- Obtain the given MDNode's operands. + -- The passed LLVMValueRef pointer should point to enough memory to hold + -- all of the operands of the given MDNode (see LLVMGetMDNodeNumOperands) + -- as LLVMValueRefs. This memory will be populated with the LLVMValueRefs + -- of the MDNode's operands. + -- @param V MDNode to get the operands from. + -- @param Dest Destination array for operands. + procedure GetMDNodeOperands(V : ValueRef; Dest : ValueRefArray); + + procedure MDNodeReplaceOperandWith + (N : ValueRef; I : unsigned; V : ValueRef); + + -- Operations on basic blocks + function BasicBlockAsValue(BB : BasicBlockRef) return ValueRef; + function ValueIsBasicBlock(Val : ValueRef) return int; + function ValueAsBasicBlock(Val : ValueRef) return BasicBlockRef; + function GetBasicBlockParent(BB : BasicBlockRef) return ValueRef; + function CountBasicBlocks(Fn : ValueRef) return unsigned; + procedure GetBasicBlocks(Fn : ValueRef; BasicBlocks : BasicBlockRefArray); + function GetFirstBasicBlock(Fn : ValueRef) return BasicBlockRef; + function GetLastBasicBlock(Fn : ValueRef) return BasicBlockRef; + function GetNextBasicBlock(BB : BasicBlockRef) return BasicBlockRef; + function GetPreviousBasicBlock(BB : BasicBlockRef) return BasicBlockRef; + function GetEntryBasicBlock(Fn : ValueRef) return BasicBlockRef; + function AppendBasicBlock(Fn : ValueRef; Name : Cstring) + return BasicBlockRef; + function InsertBasicBlock(InsertBeforeBB : BasicBlockRef; + Name : Cstring) return BasicBlockRef; + procedure DeleteBasicBlock(BB : BasicBlockRef); + + -- Operations on instructions + + -- Determine whether an instruction has any metadata attached. + function HasMetadata(Val: ValueRef) return Bool; + + -- Return metadata associated with an instruction value. + function GetMetadata(Val : ValueRef; KindID : unsigned) return ValueRef; + + -- Set metadata associated with an instruction value. + procedure SetMetadata(Val : ValueRef; KindID : unsigned; Node : ValueRef); + + function GetInstructionParent(Inst : ValueRef) return BasicBlockRef; + function GetFirstInstruction(BB : BasicBlockRef) return ValueRef; + function GetLastInstruction(BB : BasicBlockRef) return ValueRef; + function GetNextInstruction(Inst : ValueRef) return ValueRef; + function GetPreviousInstruction(Inst : ValueRef) return ValueRef; + + -- Operations on call sites + procedure SetInstructionCallConv(Instr : ValueRef; CC : unsigned); + function GetInstructionCallConv(Instr : ValueRef) return unsigned; + procedure AddInstrAttribute(Instr : ValueRef; + index : unsigned; Attr : Attribute); + procedure RemoveInstrAttribute(Instr : ValueRef; + index : unsigned; Attr : Attribute); + procedure SetInstrParamAlignment(Instr : ValueRef; + index : unsigned; align : unsigned); + + -- Operations on call instructions (only) + function IsTailCall(CallInst : ValueRef) return int; + procedure SetTailCall(CallInst : ValueRef; IsTailCall : int); + + -- Operations on phi nodes + procedure AddIncoming(PhiNode : ValueRef; IncomingValues : ValueRefArray; + IncomingBlocks : BasicBlockRefArray; Count : unsigned); + function CountIncoming(PhiNode : ValueRef) return unsigned; + function GetIncomingValue(PhiNode : ValueRef; Index : unsigned) + return ValueRef; + function GetIncomingBlock(PhiNode : ValueRef; Index : unsigned) + return BasicBlockRef; + + -- Instruction builders ---------------------------------------------- + -- An instruction builder represents a point within a basic block, + -- and is the exclusive means of building instructions using the C + -- interface. + + function CreateBuilder return BuilderRef; + procedure PositionBuilder(Builder : BuilderRef; + Block : BasicBlockRef; Instr : ValueRef); + procedure PositionBuilderBefore(Builder : BuilderRef; Instr : ValueRef); + procedure PositionBuilderAtEnd(Builder : BuilderRef; Block : BasicBlockRef); + function GetInsertBlock(Builder : BuilderRef) return BasicBlockRef; + procedure DisposeBuilder(Builder : BuilderRef); + + -- Terminators + function BuildRetVoid(Builder : BuilderRef) return ValueRef; + function BuildRet(Builder : BuilderRef; V : ValueRef) return ValueRef; + function BuildBr(Builder : BuilderRef; Dest : BasicBlockRef) + return ValueRef; + function BuildCondBr(Builder : BuilderRef; + If_Br : ValueRef; + Then_Br : BasicBlockRef; Else_Br : BasicBlockRef) + return ValueRef; + function BuildSwitch(Builder : BuilderRef; + V : ValueRef; + Else_Br : BasicBlockRef; NumCases : unsigned) + return ValueRef; + function BuildInvoke(Builder : BuilderRef; + Fn : ValueRef; + Args : ValueRefArray; + NumArgs : unsigned; + Then_Br : BasicBlockRef; + Catch : BasicBlockRef; + Name : Cstring) return ValueRef; + function BuildUnwind(Builder : BuilderRef) return ValueRef; + function BuildUnreachable(Builder : BuilderRef) return ValueRef; + + -- Add a case to the switch instruction + procedure AddCase(Switch : ValueRef; + OnVal : ValueRef; Dest : BasicBlockRef); + + -- Arithmetic + function BuildAdd(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildNSWAdd(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildNUWAdd(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildFAdd(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + + function BuildSub(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildNSWSub(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildNUWSub(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildFSub(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + + function BuildMul(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildFMul(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + + function BuildUDiv(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildSDiv(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildFDiv(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildURem(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildSRem(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildFRem(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildShl(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildLShr(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildAShr(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildAnd(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildOr(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildXor(Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildNeg(Builder : BuilderRef; V : ValueRef; Name : Cstring) + return ValueRef; + function BuildFNeg(Builder : BuilderRef; V : ValueRef; Name : Cstring) + return ValueRef; + function BuildNot(Builder : BuilderRef; V : ValueRef; Name : Cstring) + return ValueRef; + + -- Memory + function BuildMalloc(Builder : BuilderRef; Ty : TypeRef; Name : Cstring) + return ValueRef; + function BuildArrayMalloc(Builder : BuilderRef; + Ty : TypeRef; Val : ValueRef; Name : Cstring) + return ValueRef; + function BuildAlloca(Builder : BuilderRef; Ty : TypeRef; Name : Cstring) + return ValueRef; + function BuildArrayAlloca(Builder : BuilderRef; + Ty : TypeRef; Val : ValueRef; Name : Cstring) + return ValueRef; + function BuildFree(Builder : BuilderRef; PointerVal : ValueRef) + return ValueRef; + function BuildLoad(Builder : BuilderRef; PointerVal : ValueRef; + Name : Cstring) return ValueRef; + function BuildStore(Builder : BuilderRef; Val : ValueRef; Ptr : ValueRef) + return ValueRef; + function BuildGEP(Builder : BuilderRef; + Pointer : ValueRef; + Indices : ValueRefArray; + NumIndices : unsigned; Name : Cstring) return ValueRef; + + -- Casts + function BuildTrunc(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildZExt(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildSExt(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildFPToUI(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildFPToSI(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildUIToFP(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildSIToFP(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildFPTrunc(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildFPExt(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildPtrToInt(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildIntToPtr(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + function BuildBitCast(Builder : BuilderRef; + Val : ValueRef; DestTy : TypeRef; Name : Cstring) + return ValueRef; + + -- Comparisons + function BuildICmp(Builder : BuilderRef; + Op : IntPredicate; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + function BuildFCmp(Builder : BuilderRef; + Op : RealPredicate; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + + -- Miscellaneous instructions + function BuildPhi(Builder : BuilderRef; Ty : TypeRef; Name : Cstring) + return ValueRef; + function BuildCall(Builder : BuilderRef; + Fn : ValueRef; + Args : ValueRefArray; NumArgs : unsigned; Name : Cstring) + return ValueRef; + function BuildSelect(Builder : BuilderRef; + If_Sel : ValueRef; + Then_Sel : ValueRef; + Else_Sel : ValueRef; + Name : Cstring) return ValueRef; + function BuildVAArg(Builder : BuilderRef; + List : ValueRef; Ty : TypeRef; Name : Cstring) + return ValueRef; + function BuildExtractElement(Builder : BuilderRef; + VecVal : ValueRef; + Index : ValueRef; + Name : Cstring) return ValueRef; + function BuildInsertElement(Builder : BuilderRef; + VecVal : ValueRef; + EltVal : ValueRef; + Index : ValueRef; + Name : Cstring) return ValueRef; + function BuildShuffleVector(Builder : BuilderRef; + V1 : ValueRef; + V2 : ValueRef; + Mask : ValueRef; + Name : Cstring) return ValueRef; + + -- Memory buffers ---------------------------------------------------- + + function CreateMemoryBufferWithContentsOfFile + (Path : Cstring; + OutMemBuf : access MemoryBufferRef; + OutMessage : access Cstring) return int; + function CreateMemoryBufferWithSTDIN + (OutMemBuf : access MemoryBufferRef; + OutMessage : access Cstring) return int; + procedure DisposeMemoryBuffer(MemBuf : MemoryBufferRef); + + + -- Pass Managers ----------------------------------------------------- + + -- Constructs a new whole-module pass pipeline. This type of pipeline is + -- suitable for link-time optimization and whole-module transformations. + -- See llvm::PassManager::PassManager. + function CreatePassManager return PassManagerRef; + + -- Constructs a new function-by-function pass pipeline over the module + -- provider. It does not take ownership of the module provider. This type of + -- pipeline is suitable for code generation and JIT compilation tasks. + -- See llvm::FunctionPassManager::FunctionPassManager. + function CreateFunctionPassManagerForModule(M : ModuleRef) + return PassManagerRef; + + -- Initializes, executes on the provided module, and finalizes all of the + -- passes scheduled in the pass manager. Returns 1 if any of the passes + -- modified the module, 0 otherwise. See llvm::PassManager::run(Module&). + function RunPassManager(PM : PassManagerRef; M : ModuleRef) + return int; + + -- Initializes all of the function passes scheduled in the function pass + -- manager. Returns 1 if any of the passes modified the module, 0 otherwise. + -- See llvm::FunctionPassManager::doInitialization. + function InitializeFunctionPassManager(FPM : PassManagerRef) + return int; + + -- Executes all of the function passes scheduled in the function + -- pass manager on the provided function. Returns 1 if any of the + -- passes modified the function, false otherwise. + -- See llvm::FunctionPassManager::run(Function&). + function RunFunctionPassManager (FPM : PassManagerRef; F : ValueRef) + return int; + + -- Finalizes all of the function passes scheduled in in the function pass + -- manager. Returns 1 if any of the passes modified the module, 0 otherwise. + -- See llvm::FunctionPassManager::doFinalization. + function FinalizeFunctionPassManager(FPM : PassManagerRef) + return int; + + -- Frees the memory of a pass pipeline. For function pipelines, + -- does not free the module provider. + -- See llvm::PassManagerBase::~PassManagerBase. + procedure DisposePassManager(PM : PassManagerRef); + +private + pragma Import (C, ContextCreate, "LLVMContextCreate"); + pragma Import (C, GetGlobalContext, "LLVMGetGlobalContext"); + pragma Import (C, ContextDispose, "LLVMContextDispose"); + + pragma Import (C, GetMDKindIDInContext, "LLVMGetMDKindIDInContext"); + pragma Import (C, GetMDKindID, "LLVMGetMDKindID"); + + pragma Import (C, DisposeMessage, "LLVMDisposeMessage"); + pragma Import (C, ModuleCreateWithName, "LLVMModuleCreateWithName"); + pragma Import (C, DisposeModule, "LLVMDisposeModule"); + pragma Import (C, GetDataLayout, "LLVMGetDataLayout"); + pragma Import (C, SetDataLayout, "LLVMSetDataLayout"); + pragma Import (C, GetTarget, "LLVMGetTarget"); + pragma Import (C, SetTarget, "LLVMSetTarget"); + pragma Import (C, DumpModule, "LLVMDumpModule"); + pragma Import (C, PrintModuleToFile, "LLVMPrintModuleToFile"); + pragma Import (C, GetTypeKind, "LLVMGetTypeKind"); + pragma Import (C, Int1Type, "LLVMInt1Type"); + pragma Import (C, Int8Type, "LLVMInt8Type"); + pragma Import (C, Int16Type, "LLVMInt16Type"); + pragma Import (C, Int32Type, "LLVMInt32Type"); + pragma Import (C, Int64Type, "LLVMInt64Type"); + pragma Import (C, IntType, "LLVMIntType"); + pragma Import (C, GetIntTypeWidth, "LLVMGetIntTypeWidth"); + pragma Import (C, MetadataType, "LLVMMetadataType_extra"); + + pragma Import (C, FloatType, "LLVMFloatType"); + pragma Import (C, DoubleType, "LLVMDoubleType"); + pragma Import (C, X86FP80Type, "LLVMX86FP80Type"); + pragma Import (C, FP128Type, "LLVMFP128Type"); + pragma Import (C, PPCFP128Type, "LLVMPPCFP128Type"); + + pragma Import (C, FunctionType, "LLVMFunctionType"); + pragma Import (C, IsFunctionVarArg, "LLVMIsFunctionVarArg"); + pragma Import (C, GetReturnType, "LLVMGetReturnType"); + pragma Import (C, CountParamTypes, "LLVMCountParamTypes"); + pragma Import (C, GetParamTypes, "LLVMGetParamTypes"); + + pragma Import (C, StructType, "LLVMStructType"); + pragma Import (C, StructCreateNamed, "LLVMStructCreateNamed"); + pragma Import (C, StructSetBody, "LLVMStructSetBody"); + pragma Import (C, CountStructElementTypes, "LLVMCountStructElementTypes"); + pragma Import (C, GetStructElementTypes, "LLVMGetStructElementTypes"); + pragma Import (C, IsPackedStruct, "LLVMIsPackedStruct"); + + pragma Import (C, ArrayType, "LLVMArrayType"); + pragma Import (C, PointerType, "LLVMPointerType"); + pragma Import (C, VectorType, "LLVMVectorType"); + pragma Import (C, GetElementType, "LLVMGetElementType"); + pragma Import (C, GetArrayLength, "LLVMGetArrayLength"); + pragma Import (C, GetPointerAddressSpace, "LLVMGetPointerAddressSpace"); + pragma Import (C, GetVectorSize, "LLVMGetVectorSize"); + + pragma Import (C, VoidType, "LLVMVoidType"); + pragma Import (C, LabelType, "LLVMLabelType"); + + pragma Import (C, TypeOf, "LLVMTypeOf"); + pragma Import (C, GetValueName, "LLVMGetValueName"); + pragma Import (C, SetValueName, "LLVMSetValueName"); + pragma Import (C, DumpValue, "LLVMDumpValue"); + + pragma Import (C, ConstNull, "LLVMConstNull"); + pragma Import (C, ConstAllOnes, "LLVMConstAllOnes"); + pragma Import (C, GetUndef, "LLVMGetUndef"); + pragma Import (C, IsConstant, "LLVMIsConstant"); + pragma Import (C, IsNull, "LLVMIsNull"); + pragma Import (C, IsUndef, "LLVMIsUndef"); + pragma Import (C, IsAInstruction, "LLVMIsAInstruction"); + + pragma Import (C, ConstInt, "LLVMConstInt"); + pragma Import (C, ConstReal, "LLVMConstReal"); + pragma Import (C, ConstIntGetZExtValue, "LLVMConstIntGetZExtValue"); + pragma Import (C, ConstRealOfString, "LLVMConstRealOfString"); + pragma Import (C, ConstString, "LLVMConstString"); + pragma Import (C, ConstArray, "LLVMConstArray"); + pragma Import (C, ConstStruct, "LLVMConstStruct"); + pragma Import (C, ConstNamedStruct, "LLVMConstNamedStruct"); + pragma Import (C, ConstVector, "LLVMConstVector"); + + pragma Import (C, SizeOf, "LLVMSizeOf"); + pragma Import (C, AlignOf, "LLVMAlignOf"); + pragma Import (C, ConstNeg, "LLVMConstNeg"); + pragma Import (C, ConstNot, "LLVMConstNot"); + pragma Import (C, ConstAdd, "LLVMConstAdd"); + pragma Import (C, ConstSub, "LLVMConstSub"); + pragma Import (C, ConstMul, "LLVMConstMul"); + pragma Import (C, ConstUDiv, "LLVMConstUDiv"); + pragma Import (C, ConstSDiv, "LLVMConstSDiv"); + pragma Import (C, ConstFDiv, "LLVMConstFDiv"); + pragma Import (C, ConstURem, "LLVMConstURem"); + pragma Import (C, ConstSRem, "LLVMConstSRem"); + pragma Import (C, ConstFRem, "LLVMConstFRem"); + pragma Import (C, ConstAnd, "LLVMConstAnd"); + pragma Import (C, ConstOr, "LLVMConstOr"); + pragma Import (C, ConstXor, "LLVMConstXor"); + pragma Import (C, ConstICmp, "LLVMConstICmp"); + pragma Import (C, ConstFCmp, "LLVMConstFCmp"); + pragma Import (C, ConstShl, "LLVMConstShl"); + pragma Import (C, ConstLShr, "LLVMConstLShr"); + pragma Import (C, ConstAShr, "LLVMConstAShr"); + pragma Import (C, ConstGEP, "LLVMConstGEP"); + pragma Import (C, ConstTrunc, "LLVMConstTrunc"); + pragma Import (C, ConstSExt, "LLVMConstSExt"); + pragma Import (C, ConstZExt, "LLVMConstZExt"); + pragma Import (C, ConstFPTrunc, "LLVMConstFPTrunc"); + pragma Import (C, ConstFPExt, "LLVMConstFPExt"); + pragma Import (C, ConstUIToFP, "LLVMConstUIToFP"); + pragma Import (C, ConstSIToFP, "LLVMConstSIToFP"); + pragma Import (C, ConstFPToUI, "LLVMConstFPToUI"); + pragma Import (C, ConstFPToSI, "LLVMConstFPToSI"); + pragma Import (C, ConstPtrToInt, "LLVMConstPtrToInt"); + pragma Import (C, ConstIntToPtr, "LLVMConstIntToPtr"); + pragma Import (C, ConstBitCast, "LLVMConstBitCast"); + pragma Import (C, ConstTruncOrBitCast, "LLVMConstTruncOrBitCast"); + pragma Import (C, ConstSelect, "LLVMConstSelect"); + pragma Import (C, ConstExtractElement, "LLVMConstExtractElement"); + pragma Import (C, ConstInsertElement, "LLVMConstInsertElement"); + pragma Import (C, ConstShuffleVector, "LLVMConstShuffleVector"); + + pragma Import (C, GetGlobalParent, "LLVMGetGlobalParent"); + pragma Import (C, IsDeclaration, "LLVMIsDeclaration"); + pragma Import (C, GetLinkage, "LLVMGetLinkage"); + pragma Import (C, SetLinkage, "LLVMSetLinkage"); + pragma Import (C, GetSection, "LLVMGetSection"); + pragma Import (C, SetSection, "LLVMSetSection"); + pragma Import (C, GetVisibility, "LLVMGetVisibility"); + pragma Import (C, SetVisibility, "LLVMSetVisibility"); + pragma Import (C, GetAlignment, "LLVMGetAlignment"); + pragma Import (C, SetAlignment, "LLVMSetAlignment"); + + pragma Import (C, AddGlobal, "LLVMAddGlobal"); + pragma Import (C, GetNamedGlobal, "LLVMGetNamedGlobal"); + pragma Import (C, GetFirstGlobal, "LLVMGetFirstGlobal"); + pragma Import (C, GetLastGlobal, "LLVMGetLastGlobal"); + pragma Import (C, GetNextGlobal, "LLVMGetNextGlobal"); + pragma Import (C, GetPreviousGlobal, "LLVMGetPreviousGlobal"); + pragma Import (C, DeleteGlobal, "LLVMDeleteGlobal"); + pragma Import (C, GetInitializer, "LLVMGetInitializer"); + pragma Import (C, SetInitializer, "LLVMSetInitializer"); + pragma Import (C, IsThreadLocal, "LLVMIsThreadLocal"); + pragma Import (C, SetThreadLocal, "LLVMSetThreadLocal"); + pragma Import (C, IsGlobalConstant, "LLVMIsGlobalConstant"); + pragma Import (C, SetGlobalConstant, "LLVMSetGlobalConstant"); + + pragma Import (C, GetNamedMetadataNumOperands, + "LLVMGetNamedMetadataNumOperands"); + pragma Import (C, GetNamedMetadataOperands, "LLVMGetNamedMetadataOperands"); + pragma Import (C, AddNamedMetadataOperand, "LLVMAddNamedMetadataOperand"); + + pragma Import (C, AddFunction, "LLVMAddFunction"); + pragma Import (C, GetNamedFunction, "LLVMGetNamedFunction"); + pragma Import (C, GetFirstFunction, "LLVMGetFirstFunction"); + pragma Import (C, GetLastFunction, "LLVMGetLastFunction"); + pragma Import (C, GetNextFunction, "LLVMGetNextFunction"); + pragma Import (C, GetPreviousFunction, "LLVMGetPreviousFunction"); + pragma Import (C, DeleteFunction, "LLVMDeleteFunction"); + pragma Import (C, GetIntrinsicID, "LLVMGetIntrinsicID"); + pragma Import (C, GetFunctionCallConv, "LLVMGetFunctionCallConv"); + pragma Import (C, SetFunctionCallConv, "LLVMSetFunctionCallConv"); + pragma Import (C, GetGC, "LLVMGetGC"); + pragma Import (C, SetGC, "LLVMSetGC"); + + pragma Import (C, AddFunctionAttr, "LLVMAddFunctionAttr"); + pragma import (C, AddTargetDependentFunctionAttr, + "LLVMAddTargetDependentFunctionAttr"); + pragma Import (C, GetFunctionAttr, "LLVMGetFunctionAttr"); + pragma Import (C, RemoveFunctionAttr, "LLVMRemoveFunctionAttr"); + + pragma Import (C, CountParams, "LLVMCountParams"); + pragma Import (C, GetParams, "LLVMGetParams"); + pragma Import (C, GetParam, "LLVMGetParam"); + pragma Import (C, GetParamParent, "LLVMGetParamParent"); + pragma Import (C, GetFirstParam, "LLVMGetFirstParam"); + pragma Import (C, GetLastParam, "LLVMGetLastParam"); + pragma Import (C, GetNextParam, "LLVMGetNextParam"); + pragma Import (C, GetPreviousParam, "LLVMGetPreviousParam"); + pragma Import (C, AddAttribute, "LLVMAddAttribute"); + pragma Import (C, RemoveAttribute, "LLVMRemoveAttribute"); + pragma Import (C, SetParamAlignment, "LLVMSetParamAlignment"); + + pragma Import (C, MDStringInContext, "LLVMMDStringInContext"); + pragma Import (C, MDString, "LLVMMDString"); + pragma Import (C, MDNodeInContext, "LLVMMDNodeInContext"); + pragma Import (C, MDNode, "LLVMMDNode"); + pragma Import (C, GetMDString, "LLVMGetMDString"); + pragma Import (C, GetMDNodeNumOperands, "LLVMGetMDNodeNumOperands"); + pragma Import (C, GetMDNodeOperands, "LLVMGetMDNodeOperands"); + pragma Import (C, MDNodeReplaceOperandWith, + "LLVMMDNodeReplaceOperandWith_extra"); + + pragma Import (C, BasicBlockAsValue, "LLVMBasicBlockAsValue"); + pragma Import (C, ValueIsBasicBlock, "LLVMValueIsBasicBlock"); + pragma Import (C, ValueAsBasicBlock, "LLVMValueAsBasicBlock"); + pragma Import (C, GetBasicBlockParent, "LLVMGetBasicBlockParent"); + pragma Import (C, CountBasicBlocks, "LLVMCountBasicBlocks"); + pragma Import (C, GetBasicBlocks, "LLVMGetBasicBlocks"); + pragma Import (C, GetFirstBasicBlock, "LLVMGetFirstBasicBlock"); + pragma Import (C, GetLastBasicBlock, "LLVMGetLastBasicBlock"); + pragma Import (C, GetNextBasicBlock, "LLVMGetNextBasicBlock"); + pragma Import (C, GetPreviousBasicBlock, "LLVMGetPreviousBasicBlock"); + pragma Import (C, GetEntryBasicBlock, "LLVMGetEntryBasicBlock"); + pragma Import (C, AppendBasicBlock, "LLVMAppendBasicBlock"); + pragma Import (C, InsertBasicBlock, "LLVMInsertBasicBlock"); + pragma Import (C, DeleteBasicBlock, "LLVMDeleteBasicBlock"); + + pragma Import (C, HasMetadata, "LLVMHasMetadata"); + pragma Import (C, GetMetadata, "LLVMGetMetadata"); + pragma Import (C, SetMetadata, "LLVMSetMetadata"); + + pragma Import (C, GetInstructionParent, "LLVMGetInstructionParent"); + pragma Import (C, GetFirstInstruction, "LLVMGetFirstInstruction"); + pragma Import (C, GetLastInstruction, "LLVMGetLastInstruction"); + pragma Import (C, GetNextInstruction, "LLVMGetNextInstruction"); + pragma Import (C, GetPreviousInstruction, "LLVMGetPreviousInstruction"); + + pragma Import (C, SetInstructionCallConv, "LLVMSetInstructionCallConv"); + pragma Import (C, GetInstructionCallConv, "LLVMGetInstructionCallConv"); + pragma Import (C, AddInstrAttribute, "LLVMAddInstrAttribute"); + pragma Import (C, RemoveInstrAttribute, "LLVMRemoveInstrAttribute"); + pragma Import (C, SetInstrParamAlignment, "LLVMSetInstrParamAlignment"); + + pragma Import (C, IsTailCall, "LLVMIsTailCall"); + pragma Import (C, SetTailCall, "LLVMSetTailCall"); + + pragma Import (C, AddIncoming, "LLVMAddIncoming"); + pragma Import (C, CountIncoming, "LLVMCountIncoming"); + pragma Import (C, GetIncomingValue, "LLVMGetIncomingValue"); + pragma Import (C, GetIncomingBlock, "LLVMGetIncomingBlock"); + + pragma Import (C, CreateBuilder, "LLVMCreateBuilder"); + pragma Import (C, PositionBuilder, "LLVMPositionBuilder"); + pragma Import (C, PositionBuilderBefore, "LLVMPositionBuilderBefore"); + pragma Import (C, PositionBuilderAtEnd, "LLVMPositionBuilderAtEnd"); + pragma Import (C, GetInsertBlock, "LLVMGetInsertBlock"); + pragma Import (C, DisposeBuilder, "LLVMDisposeBuilder"); + + -- Terminators + pragma Import (C, BuildRetVoid, "LLVMBuildRetVoid"); + pragma Import (C, BuildRet, "LLVMBuildRet"); + pragma Import (C, BuildBr, "LLVMBuildBr"); + pragma Import (C, BuildCondBr, "LLVMBuildCondBr"); + pragma Import (C, BuildSwitch, "LLVMBuildSwitch"); + pragma Import (C, BuildInvoke, "LLVMBuildInvoke"); + pragma Import (C, BuildUnwind, "LLVMBuildUnwind"); + pragma Import (C, BuildUnreachable, "LLVMBuildUnreachable"); + + -- Add a case to the switch instruction + pragma Import (C, AddCase, "LLVMAddCase"); + + -- Arithmetic + pragma Import (C, BuildAdd, "LLVMBuildAdd"); + pragma Import (C, BuildNSWAdd, "LLVMBuildNSWAdd"); + pragma Import (C, BuildNUWAdd, "LLVMBuildNUWAdd"); + pragma Import (C, BuildFAdd, "LLVMBuildFAdd"); + pragma Import (C, BuildSub, "LLVMBuildSub"); + pragma Import (C, BuildNSWSub, "LLVMBuildNSWSub"); + pragma Import (C, BuildNUWSub, "LLVMBuildNUWSub"); + pragma Import (C, BuildFSub, "LLVMBuildFSub"); + pragma Import (C, BuildMul, "LLVMBuildMul"); + pragma Import (C, BuildFMul, "LLVMBuildFMul"); + pragma Import (C, BuildUDiv, "LLVMBuildUDiv"); + pragma Import (C, BuildSDiv, "LLVMBuildSDiv"); + pragma Import (C, BuildFDiv, "LLVMBuildFDiv"); + pragma Import (C, BuildURem, "LLVMBuildURem"); + pragma Import (C, BuildSRem, "LLVMBuildSRem"); + pragma Import (C, BuildFRem, "LLVMBuildFRem"); + pragma Import (C, BuildShl, "LLVMBuildShl"); + pragma Import (C, BuildLShr, "LLVMBuildLShr"); + pragma Import (C, BuildAShr, "LLVMBuildAShr"); + pragma Import (C, BuildAnd, "LLVMBuildAnd"); + pragma Import (C, BuildOr, "LLVMBuildOr"); + pragma Import (C, BuildXor, "LLVMBuildXor"); + pragma Import (C, BuildNeg, "LLVMBuildNeg"); + pragma Import (C, BuildFNeg, "LLVMBuildFNeg"); + pragma Import (C, BuildNot, "LLVMBuildNot"); + + -- Memory + pragma Import (C, BuildMalloc, "LLVMBuildMalloc"); + pragma Import (C, BuildArrayMalloc, "LLVMBuildArrayMalloc"); + pragma Import (C, BuildAlloca, "LLVMBuildAlloca"); + pragma Import (C, BuildArrayAlloca, "LLVMBuildArrayAlloca"); + pragma Import (C, BuildFree, "LLVMBuildFree"); + pragma Import (C, BuildLoad, "LLVMBuildLoad"); + pragma Import (C, BuildStore, "LLVMBuildStore"); + pragma Import (C, BuildGEP, "LLVMBuildGEP"); + + -- Casts + pragma Import (C, BuildTrunc, "LLVMBuildTrunc"); + pragma Import (C, BuildZExt, "LLVMBuildZExt"); + pragma Import (C, BuildSExt, "LLVMBuildSExt"); + pragma Import (C, BuildFPToUI, "LLVMBuildFPToUI"); + pragma Import (C, BuildFPToSI, "LLVMBuildFPToSI"); + pragma Import (C, BuildUIToFP, "LLVMBuildUIToFP"); + pragma Import (C, BuildSIToFP, "LLVMBuildSIToFP"); + pragma Import (C, BuildFPTrunc, "LLVMBuildFPTrunc"); + pragma Import (C, BuildFPExt, "LLVMBuildFPExt"); + pragma Import (C, BuildPtrToInt, "LLVMBuildPtrToInt"); + pragma Import (C, BuildIntToPtr, "LLVMBuildIntToPtr"); + pragma Import (C, BuildBitCast, "LLVMBuildBitCast"); + + -- Comparisons + pragma Import (C, BuildICmp, "LLVMBuildICmp"); + pragma Import (C, BuildFCmp, "LLVMBuildFCmp"); + + -- Miscellaneous instructions + pragma Import (C, BuildPhi, "LLVMBuildPhi"); + pragma Import (C, BuildCall, "LLVMBuildCall"); + pragma Import (C, BuildSelect, "LLVMBuildSelect"); + pragma Import (C, BuildVAArg, "LLVMBuildVAArg"); + pragma Import (C, BuildExtractElement, "LLVMBuildExtractElement"); + pragma Import (C, BuildInsertElement, "LLVMBuildInsertElement"); + pragma Import (C, BuildShuffleVector, "LLVMBuildShuffleVector"); + + -- Memory buffers ---------------------------------------------------- + pragma Import (C, CreateMemoryBufferWithContentsOfFile, + "LLVMCreateMemoryBufferWithContentsOfFile"); + pragma Import (C, CreateMemoryBufferWithSTDIN, + "LLVMCreateMemoryBufferWithSTDIN"); + pragma Import (C, DisposeMemoryBuffer, "LLVMDisposeMemoryBuffer"); + + -- Pass Managers ----------------------------------------------------- + pragma Import (C, CreatePassManager, "LLVMCreatePassManager"); + pragma Import (C, CreateFunctionPassManagerForModule, + "LLVMCreateFunctionPassManagerForModule"); + pragma Import (C, RunPassManager, "LLVMRunPassManager"); + pragma Import (C, InitializeFunctionPassManager, + "LLVMInitializeFunctionPassManager"); + pragma Import (C, RunFunctionPassManager, + "LLVMRunFunctionPassManager"); + pragma Import (C, FinalizeFunctionPassManager, + "LLVMFinalizeFunctionPassManager"); + pragma Import (C, DisposePassManager, "LLVMDisposePassManager"); + +end LLVM.Core; diff --git a/src/ortho/llvm/llvm-executionengine.ads b/src/ortho/llvm/llvm-executionengine.ads new file mode 100644 index 000000000..72d4cda2f --- /dev/null +++ b/src/ortho/llvm/llvm-executionengine.ads @@ -0,0 +1,163 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with System; use System; +with Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with LLVM.Core; use LLVM.Core; +with LLVM.Target; use LLVM.Target; + +package LLVM.ExecutionEngine is + type GenericValueRef is new Address; + type GenericValueRefArray is array (unsigned range <>) of GenericValueRef; + pragma Convention (C, GenericValueRefArray); + type ExecutionEngineRef is new Address; + + procedure LinkInJIT; + procedure LinkInMCJIT; + procedure LinkInInterpreter; + + -- Operations on generic values -------------------------------------- + + function CreateGenericValueOfInt(Ty : TypeRef; + N : Unsigned_64; + IsSigned : Integer) + return GenericValueRef; + + function CreateGenericValueOfPointer(P : System.Address) + return GenericValueRef; + + function CreateGenericValueOfFloat(Ty : TypeRef; N : double) + return GenericValueRef; + + function GenericValueIntWidth(GenValRef : GenericValueRef) + return unsigned; + + function GenericValueToInt(GenVal : GenericValueRef; + IsSigned : Integer) return Unsigned_64; + + function GenericValueToPointer(GenVal : GenericValueRef) + return System.Address; + + function GenericValueToFloat(TyRef : TypeRef; GenVal : GenericValueRef) + return double; + + procedure DisposeGenericValue(GenVal : GenericValueRef); + + -- Operations on execution engines ----------------------------------- + + function CreateExecutionEngineForModule + (EE : access ExecutionEngineRef; M : ModuleRef; Error : access Cstring) + return Bool; + + function CreateInterpreterForModule (Interp : access ExecutionEngineRef; + M : ModuleRef; + Error : access Cstring) + return Bool; + + function CreateJITCompilerForModule (JIT : access ExecutionEngineRef; + M : ModuleRef; + OptLevel : unsigned; + Error : access Cstring) + return Bool; + + + procedure DisposeExecutionEngine(EE : ExecutionEngineRef); + + procedure RunStaticConstructors(EE : ExecutionEngineRef); + + procedure RunStaticDestructors(EE : ExecutionEngineRef); + + function RunFunctionAsMain(EE : ExecutionEngineRef; + F : ValueRef; + ArgC : unsigned; Argv : Address; EnvP : Address) + return Integer; + + function RunFunction(EE : ExecutionEngineRef; + F : ValueRef; + NumArgs : unsigned; + Args : GenericValueRefArray) + return GenericValueRef; + + procedure FreeMachineCodeForFunction(EE : ExecutionEngineRef; F : ValueRef); + + procedure AddModule(EE : ExecutionEngineRef; M : ModuleRef); + + function RemoveModule(EE : ExecutionEngineRef; + M : ModuleRef; + OutMod : access ModuleRef; + OutError : access Cstring) return Bool; + + function FindFunction(EE : ExecutionEngineRef; Name : Cstring; + OutFn : access ValueRef) + return Integer; + + function GetExecutionEngineTargetData(EE : ExecutionEngineRef) + return TargetDataRef; + + procedure AddGlobalMapping(EE : ExecutionEngineRef; Global : ValueRef; + Addr : Address); + + function GetPointerToGlobal (EE : ExecutionEngineRef; GV : ValueRef) + return Address; + function GetPointerToFunctionOrStub (EE : ExecutionEngineRef; + Func : ValueRef) + return Address; + +private + pragma Import (C, LinkInJIT, "LLVMLinkInJIT"); + pragma Import (C, LinkInMCJIT, "LLVMLinkInMCJIT"); + pragma Import (C, LinkInInterpreter, "LLVMLinkInInterpreter"); + + pragma Import (C, CreateGenericValueOfInt, "LLVMCreateGenericValueOfInt"); + pragma Import (C, CreateGenericValueOfPointer, + "LLVMCreateGenericValueOfPointer"); + pragma Import (C, CreateGenericValueOfFloat, + "LLVMCreateGenericValueOfFloat"); + pragma Import (C, GenericValueIntWidth, "LLVMGenericValueIntWidth"); + pragma Import (C, GenericValueToInt, "LLVMGenericValueToInt"); + pragma Import (C, GenericValueToPointer, "LLVMGenericValueToPointer"); + pragma Import (C, GenericValueToFloat, "LLVMGenericValueToFloat"); + pragma Import (C, DisposeGenericValue, "LLVMDisposeGenericValue"); + + -- Operations on execution engines ----------------------------------- + + pragma Import (C, CreateExecutionEngineForModule, + "LLVMCreateExecutionEngineForModule"); + pragma Import (C, CreateInterpreterForModule, + "LLVMCreateInterpreterForModule"); + pragma Import (C, CreateJITCompilerForModule, + "LLVMCreateJITCompilerForModule"); + pragma Import (C, DisposeExecutionEngine, "LLVMDisposeExecutionEngine"); + pragma Import (C, RunStaticConstructors, "LLVMRunStaticConstructors"); + pragma Import (C, RunStaticDestructors, "LLVMRunStaticDestructors"); + pragma Import (C, RunFunctionAsMain, "LLVMRunFunctionAsMain"); + pragma Import (C, RunFunction, "LLVMRunFunction"); + pragma Import (C, FreeMachineCodeForFunction, + "LLVMFreeMachineCodeForFunction"); + pragma Import (C, AddModule, "LLVMAddModule"); + pragma Import (C, RemoveModule, "LLVMRemoveModule"); + pragma Import (C, FindFunction, "LLVMFindFunction"); + pragma Import (C, GetExecutionEngineTargetData, + "LLVMGetExecutionEngineTargetData"); + pragma Import (C, AddGlobalMapping, "LLVMAddGlobalMapping"); + + pragma Import (C, GetPointerToFunctionOrStub, + "LLVMGetPointerToFunctionOrStub"); + pragma Import (C, GetPointerToGlobal, + "LLVMGetPointerToGlobal"); +end LLVM.ExecutionEngine; diff --git a/src/ortho/llvm/llvm-target.ads b/src/ortho/llvm/llvm-target.ads new file mode 100644 index 000000000..b7c35848a --- /dev/null +++ b/src/ortho/llvm/llvm-target.ads @@ -0,0 +1,84 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with System; +with Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with LLVM.Core; use LLVM.Core; + +package LLVM.Target is + + type TargetDataRef is new System.Address; + + -- LLVMInitializeNativeTarget - The main program should call this function + -- to initialize the native target corresponding to the host. This is + -- useful for JIT applications to ensure that the target gets linked in + -- correctly. + procedure InitializeNativeTarget; + pragma Import (C, InitializeNativeTarget, + "LLVMInitializeNativeTarget_noinline"); + + -- LLVMInitializeNativeTargetAsmPrinter - The main program should call this + -- function to initialize the printer for the native target corresponding + -- to the host. + procedure InitializeNativeAsmPrinter; + pragma Import (C, InitializeNativeAsmPrinter, + "LLVMInitializeNativeAsmPrinter_noinline"); + + -- Creates target data from a target layout string. + -- See the constructor llvm::DataLayout::DataLayout. + function CreateTargetData (StringRep : Cstring) return TargetDataRef; + pragma Import (C, CreateTargetData, "LLVMCreateTargetData"); + + -- Adds target data information to a pass manager. This does not take + -- ownership of the target data. + -- See the method llvm::PassManagerBase::add. + procedure AddTargetData(TD : TargetDataRef; PM : PassManagerRef); + pragma Import (C, AddTargetData, "LLVMAddTargetData"); + + -- Converts target data to a target layout string. The string must be + -- disposed with LLVMDisposeMessage. + -- See the constructor llvm::DataLayout::DataLayout. */ + function CopyStringRepOfTargetData(TD :TargetDataRef) return Cstring; + pragma Import (C, CopyStringRepOfTargetData, + "LLVMCopyStringRepOfTargetData"); + + -- Returns the pointer size in bytes for a target. + -- See the method llvm::DataLayout::getPointerSize. + function PointerSize(TD : TargetDataRef) return unsigned; + pragma Import (C, PointerSize, "LLVMPointerSize"); + + -- Computes the ABI size of a type in bytes for a target. + -- See the method llvm::DataLayout::getTypeAllocSize. + function ABISizeOfType (TD : TargetDataRef; Ty: TypeRef) return Unsigned_64; + pragma Import (C, ABISizeOfType, "LLVMABISizeOfType"); + + -- Computes the ABI alignment of a type in bytes for a target. + -- See the method llvm::DataLayout::getTypeABISize. + function ABIAlignmentOfType (TD : TargetDataRef; Ty: TypeRef) + return Unsigned_32; + pragma Import (C, ABIAlignmentOfType, "LLVMABIAlignmentOfType"); + + -- Computes the byte offset of the indexed struct element for a target. + -- See the method llvm::StructLayout::getElementContainingOffset. + function OffsetOfElement(TD : TargetDataRef; + StructTy : TypeRef; + Element : Unsigned_32) + return Unsigned_64; + pragma Import (C, OffsetOfElement, "LLVMOffsetOfElement"); + +end LLVM.Target; diff --git a/src/ortho/llvm/llvm-targetmachine.ads b/src/ortho/llvm/llvm-targetmachine.ads new file mode 100644 index 000000000..cbf074940 --- /dev/null +++ b/src/ortho/llvm/llvm-targetmachine.ads @@ -0,0 +1,122 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with System; +with LLVM.Core; use LLVM.Core; +with LLVM.Target; use LLVM.Target; + +package LLVM.TargetMachine is + + type TargetMachineRef is new System.Address; + Null_TargetMachineRef : constant TargetMachineRef := + TargetMachineRef (System.Null_Address); + + type TargetRef is new System.Address; + Null_TargetRef : constant TargetRef := TargetRef (System.Null_Address); + + type CodeGenOptLevel is (CodeGenLevelNone, + CodeGenLevelLess, + CodeGenLevelDefault, + CodeGenLevelAggressive); + pragma Convention (C, CodeGenOptLevel); + + type RelocMode is (RelocDefault, + RelocStatic, + RelocPIC, + RelocDynamicNoPic); + pragma Convention (C, RelocMode); + + type CodeModel is (CodeModelDefault, + CodeModelJITDefault, + CodeModelSmall, + CodeModelKernel, + CodeModelMedium, + CodeModelLarge); + pragma Convention (C, CodeModel); + + type CodeGenFileType is (AssemblyFile, + ObjectFile); + pragma Convention (C, CodeGenFileType); + + -- Returns the first llvm::Target in the registered targets list. + function GetFirstTarget return TargetRef; + pragma Import (C, GetFirstTarget, "LLVMGetFirstTarget"); + + -- Returns the next llvm::Target given a previous one (or null if there's + -- none) */ + function GetNextTarget(T : TargetRef) return TargetRef; + pragma Import (C, GetNextTarget, "LLVMGetNextTarget"); + + -- Target + + -- Finds the target corresponding to the given name and stores it in T. + -- Returns 0 on success. + function GetTargetFromName (Name : Cstring) return TargetRef; + pragma Import (C, GetTargetFromName, "LLVMGetTargetFromName"); + + -- Finds the target corresponding to the given triple and stores it in T. + -- Returns 0 on success. Optionally returns any error in ErrorMessage. + -- Use LLVMDisposeMessage to dispose the message. + -- Ada: ErrorMessage is the address of a Cstring. + function GetTargetFromTriple + (Triple : Cstring; T : access TargetRef; ErrorMessage : access Cstring) + return Bool; + pragma Import (C, GetTargetFromTriple, "LLVMGetTargetFromTriple"); + + -- Returns the name of a target. See llvm::Target::getName + function GetTargetName (T: TargetRef) return Cstring; + pragma Import (C, GetTargetName, "LLVMGetTargetName"); + + -- Returns the description of a target. See llvm::Target::getDescription + function GetTargetDescription (T : TargetRef) return Cstring; + pragma Import (C, GetTargetDescription, "LLVMGetTargetDescription"); + + -- Target Machine ---------------------------------------------------- + + -- Creates a new llvm::TargetMachine. See llvm::Target::createTargetMachine + + function CreateTargetMachine(T : TargetRef; + Triple : Cstring; + CPU : Cstring; + Features : Cstring; + Level : CodeGenOptLevel; + Reloc : RelocMode; + CM : CodeModel) + return TargetMachineRef; + pragma Import (C, CreateTargetMachine, "LLVMCreateTargetMachine"); + + -- Returns the llvm::DataLayout used for this llvm:TargetMachine. + function GetTargetMachineData(T : TargetMachineRef) return TargetDataRef; + pragma Import (C, GetTargetMachineData, "LLVMGetTargetMachineData"); + + -- Emits an asm or object file for the given module to the filename. This + -- wraps several c++ only classes (among them a file stream). Returns any + -- error in ErrorMessage. Use LLVMDisposeMessage to dispose the message. + function TargetMachineEmitToFile(T : TargetMachineRef; + M : ModuleRef; + Filename : Cstring; + Codegen : CodeGenFileType; + ErrorMessage : access Cstring) + return Bool; + pragma Import (C, TargetMachineEmitToFile, + "LLVMTargetMachineEmitToFile"); + + -- Get a triple for the host machine as a string. The result needs to be + -- disposed with LLVMDisposeMessage. + function GetDefaultTargetTriple return Cstring; + pragma Import (C, GetDefaultTargetTriple, "LLVMGetDefaultTargetTriple"); +end LLVM.TargetMachine; diff --git a/src/ortho/llvm/llvm-transforms-scalar.ads b/src/ortho/llvm/llvm-transforms-scalar.ads new file mode 100644 index 000000000..0f23ce87e --- /dev/null +++ b/src/ortho/llvm/llvm-transforms-scalar.ads @@ -0,0 +1,169 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with LLVM.Core; use LLVM.Core; + +package LLVM.Transforms.Scalar is + -- See llvm::createAggressiveDCEPass function. + procedure AddAggressiveDCEPass(PM : PassManagerRef); + pragma Import (C, AddAggressiveDCEPass, "LLVMAddAggressiveDCEPass"); + + -- See llvm::createCFGSimplificationPass function. + procedure AddCFGSimplificationPass(PM : PassManagerRef); + pragma Import (C, AddCFGSimplificationPass, "LLVMAddCFGSimplificationPass"); + + -- See llvm::createDeadStoreEliminationPass function. + procedure AddDeadStoreEliminationPass(PM : PassManagerRef); + pragma Import (C, AddDeadStoreEliminationPass, + "LLVMAddDeadStoreEliminationPass"); + + -- See llvm::createScalarizerPass function. + procedure AddScalarizerPass(PM : PassManagerRef); + pragma Import (C, AddScalarizerPass, "LLVMAddScalarizerPass"); + + -- See llvm::createGVNPass function. + procedure AddGVNPass(PM : PassManagerRef); + pragma Import (C, AddGVNPass, "LLVMAddGVNPass"); + + -- See llvm::createIndVarSimplifyPass function. + procedure AddIndVarSimplifyPass(PM : PassManagerRef); + pragma Import (C, AddIndVarSimplifyPass, "LLVMAddIndVarSimplifyPass"); + + -- See llvm::createInstructionCombiningPass function. + procedure AddInstructionCombiningPass(PM : PassManagerRef); + pragma Import (C, AddInstructionCombiningPass, + "LLVMAddInstructionCombiningPass"); + + -- See llvm::createJumpThreadingPass function. + procedure AddJumpThreadingPass(PM : PassManagerRef); + pragma Import (C, AddJumpThreadingPass, "LLVMAddJumpThreadingPass"); + + -- See llvm::createLICMPass function. + procedure AddLICMPass(PM : PassManagerRef); + pragma Import (C, AddLICMPass, "LLVMAddLICMPass"); + + -- See llvm::createLoopDeletionPass function. + procedure AddLoopDeletionPass(PM : PassManagerRef); + pragma Import (C, AddLoopDeletionPass, "LLVMAddLoopDeletionPass"); + + -- See llvm::createLoopIdiomPass function + procedure AddLoopIdiomPass(PM : PassManagerRef); + pragma Import (C, AddLoopIdiomPass, "LLVMAddLoopIdiomPass"); + + -- See llvm::createLoopRotatePass function. + procedure AddLoopRotatePass(PM : PassManagerRef); + pragma Import (C, AddLoopRotatePass, "LLVMAddLoopRotatePass"); + + -- See llvm::createLoopRerollPass function. + procedure AddLoopRerollPass(PM : PassManagerRef); + pragma Import (C, AddLoopRerollPass, "LLVMAddLoopRerollPass"); + + -- See llvm::createLoopUnrollPass function. + procedure AddLoopUnrollPass(PM : PassManagerRef); + pragma Import (C, AddLoopUnrollPass, "LLVMAddLoopUnrollPass"); + + -- See llvm::createLoopUnswitchPass function. + procedure AddLoopUnswitchPass(PM : PassManagerRef); + pragma Import (C, AddLoopUnswitchPass, "LLVMAddLoopUnswitchPass"); + + -- See llvm::createMemCpyOptPass function. + procedure AddMemCpyOptPass(PM : PassManagerRef); + pragma Import (C, AddMemCpyOptPass, "LLVMAddMemCpyOptPass"); + + -- See llvm::createPartiallyInlineLibCallsPass function. + procedure AddPartiallyInlineLibCallsPass(PM : PassManagerRef); + pragma Import (C, AddPartiallyInlineLibCallsPass, + "LLVMAddPartiallyInlineLibCallsPass"); + + -- See llvm::createPromoteMemoryToRegisterPass function. + procedure AddPromoteMemoryToRegisterPass(PM : PassManagerRef); + pragma Import (C, AddPromoteMemoryToRegisterPass, + "LLVMAddPromoteMemoryToRegisterPass"); + + -- See llvm::createReassociatePass function. + procedure AddReassociatePass(PM : PassManagerRef); + pragma Import (C, AddReassociatePass, "LLVMAddReassociatePass"); + + -- See llvm::createSCCPPass function. + procedure AddSCCPPass(PM : PassManagerRef); + pragma Import (C, AddSCCPPass, "LLVMAddSCCPPass"); + + -- See llvm::createScalarReplAggregatesPass function. + procedure AddScalarReplAggregatesPass(PM : PassManagerRef); + pragma Import (C, AddScalarReplAggregatesPass, + "LLVMAddScalarReplAggregatesPass"); + + -- See llvm::createScalarReplAggregatesPass function. + procedure AddScalarReplAggregatesPassSSA(PM : PassManagerRef); + pragma Import (C, AddScalarReplAggregatesPassSSA, + "LLVMAddScalarReplAggregatesPassSSA"); + + -- See llvm::createScalarReplAggregatesPass function. + procedure AddScalarReplAggregatesPassWithThreshold + (PM : PassManagerRef; Threshold : Integer); + pragma Import (C, AddScalarReplAggregatesPassWithThreshold, + "LLVMAddScalarReplAggregatesPassWithThreshold"); + + -- See llvm::createSimplifyLibCallsPass function. + procedure AddSimplifyLibCallsPass(PM : PassManagerRef); + pragma Import (C, AddSimplifyLibCallsPass, "LLVMAddSimplifyLibCallsPass"); + + -- See llvm::createTailCallEliminationPass function. + procedure AddTailCallEliminationPass(PM : PassManagerRef); + pragma Import (C, AddTailCallEliminationPass, + "LLVMAddTailCallEliminationPass"); + + -- See llvm::createConstantPropagationPass function. + procedure AddConstantPropagationPass(PM : PassManagerRef); + pragma Import (C, AddConstantPropagationPass, + "LLVMAddConstantPropagationPass"); + + -- See llvm::demotePromoteMemoryToRegisterPass function. + procedure AddDemoteMemoryToRegisterPass(PM : PassManagerRef); + pragma Import (C, AddDemoteMemoryToRegisterPass, + "LLVMAddDemoteMemoryToRegisterPass"); + + -- See llvm::createVerifierPass function. + procedure AddVerifierPass(PM : PassManagerRef); + pragma Import (C, AddVerifierPass, "LLVMAddVerifierPass"); + + -- See llvm::createCorrelatedValuePropagationPass function + procedure AddCorrelatedValuePropagationPass(PM : PassManagerRef); + pragma Import (C, AddCorrelatedValuePropagationPass, + "LLVMAddCorrelatedValuePropagationPass"); + + -- See llvm::createEarlyCSEPass function + procedure AddEarlyCSEPass(PM : PassManagerRef); + pragma Import (C, AddEarlyCSEPass, "LLVMAddEarlyCSEPass"); + + -- See llvm::createLowerExpectIntrinsicPass function + procedure AddLowerExpectIntrinsicPass(PM : PassManagerRef); + pragma Import (C, AddLowerExpectIntrinsicPass, + "LLVMAddLowerExpectIntrinsicPass"); + + -- See llvm::createTypeBasedAliasAnalysisPass function + procedure AddTypeBasedAliasAnalysisPass(PM : PassManagerRef); + pragma Import (C, AddTypeBasedAliasAnalysisPass, + "LLVMAddTypeBasedAliasAnalysisPass"); + + -- See llvm::createBasicAliasAnalysisPass function + procedure AddBasicAliasAnalysisPass(PM : PassManagerRef); + pragma Import (C, AddBasicAliasAnalysisPass, + "LLVMAddBasicAliasAnalysisPass"); +end LLVM.Transforms.Scalar; + + diff --git a/src/ortho/llvm/llvm-transforms.ads b/src/ortho/llvm/llvm-transforms.ads new file mode 100644 index 000000000..d5a8011ce --- /dev/null +++ b/src/ortho/llvm/llvm-transforms.ads @@ -0,0 +1,21 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. + +package LLVM.Transforms is + pragma Pure (LLVM.Transforms); +end LLVM.Transforms; diff --git a/src/ortho/llvm/llvm.ads b/src/ortho/llvm/llvm.ads new file mode 100644 index 000000000..80d036b84 --- /dev/null +++ b/src/ortho/llvm/llvm.ads @@ -0,0 +1,21 @@ +-- LLVM binding +-- Copyright (C) 2014 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 GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. + +package LLVM is + pragma Pure (LLVM); +end LLVM; diff --git a/src/ortho/llvm/ortho_code_main.adb b/src/ortho/llvm/ortho_code_main.adb new file mode 100644 index 000000000..300bb32d1 --- /dev/null +++ b/src/ortho/llvm/ortho_code_main.adb @@ -0,0 +1,391 @@ +-- LLVM back-end for ortho - Main subprogram. +-- Copyright (C) 2014 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.Command_Line; use Ada.Command_Line; +with Ada.Unchecked_Deallocation; +with Ada.Unchecked_Conversion; +with Ada.Text_IO; use Ada.Text_IO; + +with Ortho_Front; use Ortho_Front; +with LLVM.BitWriter; +with LLVM.Core; use LLVM.Core; +with LLVM.ExecutionEngine; use LLVM.ExecutionEngine; +with LLVM.Target; use LLVM.Target; +with LLVM.TargetMachine; use LLVM.TargetMachine; +with LLVM.Analysis; +with LLVM.Transforms.Scalar; +with Ortho_LLVM; use Ortho_LLVM; +with Interfaces; +with Interfaces.C; use Interfaces.C; + +procedure Ortho_Code_Main is + -- Name of the output filename (given by option '-o'). + Output : String_Acc := null; + + type Output_Kind_Type is (Output_Llvm, Output_Bytecode, + Output_Assembly, Output_Object); + Output_Kind : Output_Kind_Type := Output_Llvm; + + -- True if the LLVM output must be displayed (set by '--dump-llvm') + Flag_Dump_Llvm : Boolean := False; + + -- Index of the first file argument. + First_File : Natural; + + -- Set by '--exec': function to call and its argument (an integer) + Exec_Func : String_Acc := null; + Exec_Val : Integer := 0; + + -- Current option index. + Optind : Natural; + + -- Number of arguments. + Argc : constant Natural := Argument_Count; + + -- Name of the module. + Module_Name : String := "ortho" & Ascii.Nul; + + -- Target triple. + Triple : Cstring := Empty_Cstring; + + -- Execution engine + Engine : aliased ExecutionEngineRef; + + Target : aliased TargetRef; + + CPU : constant Cstring := Empty_Cstring; + Features : constant Cstring := Empty_Cstring; + Reloc : constant RelocMode := RelocDefault; + + procedure Dump_Llvm + is + use LLVM.Analysis; + Msg : aliased Cstring; + begin + DumpModule (Module); + if LLVM.Analysis.VerifyModule + (Module, PrintMessageAction, Msg'Access) /= 0 + then + null; + end if; + end Dump_Llvm; + + function To_String (C : Cstring) return String is + function Strlen (C : Cstring) return Natural; + pragma Import (C, Strlen); + + subtype Fat_String is String (Positive); + type Fat_String_Acc is access Fat_String; + + function To_Fat_String_Acc is new + Ada.Unchecked_Conversion (Cstring, Fat_String_Acc); + begin + return To_Fat_String_Acc (C)(1 .. Strlen (C)); + end To_String; + + Codegen : CodeGenFileType := ObjectFile; + + Msg : aliased Cstring; +begin + Ortho_Front.Init; + + -- Decode options. + First_File := Natural'Last; + Optind := 1; + while Optind <= Argc loop + declare + Arg : constant String := Argument (Optind); + begin + if Arg (1) = '-' then + if Arg = "--dump-llvm" then + Flag_Dump_Llvm := True; + elsif Arg = "-o" then + if Optind = Argc then + Put_Line (Standard_Error, "error: missing filename to '-o'"); + return; + end if; + Output := new String'(Argument (Optind + 1) & ASCII.Nul); + Optind := Optind + 1; + elsif Arg = "-quiet" then + -- Skip silently. + null; + elsif Arg = "-S" then + Output_Kind := Output_Assembly; + Codegen := AssemblyFile; + elsif Arg = "-c" then + Output_Kind := Output_Object; + Codegen := ObjectFile; + elsif Arg = "-O0" then + Optimization := CodeGenLevelNone; + elsif Arg = "-O1" then + Optimization := CodeGenLevelLess; + elsif Arg = "-O2" then + Optimization := CodeGenLevelDefault; + elsif Arg = "-O3" then + Optimization := CodeGenLevelAggressive; + elsif Arg = "--emit-llvm" then + Output_Kind := Output_Llvm; + elsif Arg = "--emit-bc" then + Output_Kind := Output_Bytecode; + elsif Arg = "--exec" then + if Optind + 1 >= Argc then + Put_Line (Standard_Error, + "error: missing function name to '--exec'"); + return; + end if; + Exec_Func := new String'(Argument (Optind + 1)); + Exec_Val := Integer'Value (Argument (Optind + 2)); + Optind := Optind + 2; + elsif Arg = "-g" then + Flag_Debug := True; + else + -- This is really an argument. + declare + procedure Unchecked_Deallocation is + new Ada.Unchecked_Deallocation + (Name => String_Acc, Object => String); + + Opt : String_Acc := new String'(Arg); + Opt_Arg : String_Acc; + Res : Natural; + begin + if Optind < Argument_Count then + Opt_Arg := new String'(Argument (Optind + 1)); + else + Opt_Arg := null; + end if; + Res := Ortho_Front.Decode_Option (Opt, Opt_Arg); + case Res is + when 0 => + Put_Line (Standard_Error, + "unknown option '" & Arg & "'"); + return; + when 1 => + null; + when 2 => + Optind := Optind + 1; + when others => + raise Program_Error; + end case; + Unchecked_Deallocation (Opt); + Unchecked_Deallocation (Opt_Arg); + end; + end if; + else + First_File := Optind; + exit; + end if; + end; + Optind := Optind + 1; + end loop; + + -- Link with LLVM libraries. + InitializeNativeTarget; + InitializeNativeAsmPrinter; + + LinkInJIT; + + Module := ModuleCreateWithName (Module_Name'Address); + + if Output = null and then Exec_Func /= null then + -- Now we going to create JIT + if CreateExecutionEngineForModule + (Engine'Access, Module, Msg'Access) /= 0 + then + Put_Line (Standard_Error, + "cannot create execute: " & To_String (Msg)); + raise Program_Error; + end if; + + Target_Data := GetExecutionEngineTargetData (Engine); + else + -- Extract target triple + Triple := GetDefaultTargetTriple; + SetTarget (Module, Triple); + + -- Get Target + if GetTargetFromTriple (Triple, Target'Access, Msg'Access) /= 0 then + raise Program_Error; + end if; + + -- Create a target machine + Target_Machine := CreateTargetMachine + (Target, Triple, CPU, Features, Optimization, Reloc, CodeModelDefault); + + Target_Data := GetTargetMachineData (Target_Machine); + end if; + + SetDataLayout (Module, CopyStringRepOfTargetData (Target_Data)); + + if False then + declare + Targ : TargetRef; + begin + Put_Line ("Triple: " & To_String (Triple)); + New_Line; + Put_Line ("Targets:"); + Targ := GetFirstTarget; + while Targ /= Null_TargetRef loop + Put_Line (" " & To_String (GetTargetName (Targ)) + & ": " & To_String (GetTargetDescription (Targ))); + Targ := GetNextTarget (Targ); + end loop; + end; + -- Target_Data := CreateTargetData (Triple); + end if; + + Ortho_LLVM.Init; + + Set_Exit_Status (Failure); + + if First_File > Argument_Count then + begin + if not Parse (null) then + return; + end if; + exception + when others => + return; + end; + else + for I in First_File .. Argument_Count loop + declare + Filename : constant String_Acc := + new String'(Argument (First_File)); + begin + if not Parse (Filename) then + return; + end if; + exception + when others => + return; + end; + end loop; + end if; + + if Flag_Debug then + Ortho_LLVM.Finish_Debug; + end if; + + -- Ortho_Mcode.Finish; + + if Flag_Dump_Llvm then + Dump_Llvm; + end if; + + -- Verify module. + if LLVM.Analysis.VerifyModule + (Module, LLVM.Analysis.PrintMessageAction, Msg'Access) /= 0 + then + DisposeMessage (Msg); + raise Program_Error; + end if; + + if Optimization > CodeGenLevelNone then + declare + use LLVM.Transforms.Scalar; + Global_Manager : constant Boolean := False; + Pass_Manager : PassManagerRef; + Res : Bool; + pragma Unreferenced (Res); + A_Func : ValueRef; + begin + if Global_Manager then + Pass_Manager := CreatePassManager; + else + Pass_Manager := CreateFunctionPassManagerForModule (Module); + end if; + + LLVM.Target.AddTargetData (Target_Data, Pass_Manager); + AddPromoteMemoryToRegisterPass (Pass_Manager); + AddCFGSimplificationPass (Pass_Manager); + + if Global_Manager then + Res := RunPassManager (Pass_Manager, Module); + else + A_Func := GetFirstFunction (Module); + while A_Func /= Null_ValueRef loop + Res := RunFunctionPassManager (Pass_Manager, A_Func); + A_Func := GetNextFunction (A_Func); + end loop; + end if; + end; + end if; + + if Output /= null then + declare + Error : Boolean; + begin + Msg := Empty_Cstring; + + case Output_Kind is + when Output_Assembly + | Output_Object => + Error := LLVM.TargetMachine.TargetMachineEmitToFile + (Target_Machine, Module, + Output.all'Address, Codegen, Msg'Access) /= 0; + when Output_Bytecode => + Error := LLVM.BitWriter.WriteBitcodeToFile + (Module, Output.all'Address) /= 0; + when Output_Llvm => + Error := PrintModuleToFile + (Module, Output.all'Address, Msg'Access) /= 0; + end case; + if Error then + Put_Line (Standard_Error, + "error while writing to " & Output.all); + if Msg /= Empty_Cstring then + Put_Line (Standard_Error, + "message: " & To_String (Msg)); + DisposeMessage (Msg); + end if; + Set_Exit_Status (2); + return; + end if; + end; + elsif Exec_Func /= null then + declare + use Interfaces; + Res : GenericValueRef; + Vals : GenericValueRefArray (0 .. 0); + Func : aliased ValueRef; + begin + if FindFunction (Engine, Exec_Func.all'Address, Func'Access) /= 0 then + raise Program_Error; + end if; + + -- Call the function with argument n: + Vals (0) := CreateGenericValueOfInt + (Int32Type, Unsigned_64 (Exec_Val), 0); + Res := RunFunction (Engine, Func, 1, Vals); + + -- import result of execution + Put_Line ("Result is " + & Unsigned_64'Image (GenericValueToInt (Res, 0))); + + end; + else + Dump_Llvm; + end if; + + Set_Exit_Status (Success); +exception + when others => + Set_Exit_Status (2); + raise; +end Ortho_Code_Main; diff --git a/src/ortho/llvm/ortho_ident.adb b/src/ortho/llvm/ortho_ident.adb new file mode 100644 index 000000000..e7b650539 --- /dev/null +++ b/src/ortho/llvm/ortho_ident.adb @@ -0,0 +1,134 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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. + +package body Ortho_Ident is + type Chunk (Max : Positive); + type Chunk_Acc is access Chunk; + + type Chunk (Max : Positive) is record + Prev : Chunk_Acc; + Len : Natural := 0; + S : String (1 .. Max); + end record; + + Cur_Chunk : Chunk_Acc := null; + + subtype Fat_String is String (Positive); + + function Get_Identifier (Str : String) return O_Ident + is + Len : constant Natural := Str'Length; + Max : Positive; + Org : Positive; + begin + if Cur_Chunk = null or else Cur_Chunk.Len + Len >= Cur_Chunk.Max then + if Cur_Chunk = null then + Max := 32 * 1024; + else + Max := 2 * Cur_Chunk.Max; + end if; + if Len + 2 > Max then + Max := 2 * (Len + 2); + end if; + declare + New_Chunk : Chunk_Acc; + begin + -- Do not use allocator by expression, as we don't want to + -- initialize S. + New_Chunk := new Chunk (Max); + New_Chunk.Len := 0; + New_Chunk.Prev := Cur_Chunk; + Cur_Chunk := New_Chunk; + end; + end if; + + Org := Cur_Chunk.Len + 1; + Cur_Chunk.S (Org .. Org + Len - 1) := Str; + Cur_Chunk.S (Org + Len) := ASCII.NUL; + Cur_Chunk.Len := Org + Len; + + return (Addr => Cur_Chunk.S (Org)'Address); + end Get_Identifier; + + function Is_Equal (L, R : O_Ident) return Boolean + is + begin + return L = R; + end Is_Equal; + + function Get_String_Length (Id : O_Ident) return Natural + is + Str : Fat_String; + pragma Import (Ada, Str); + for Str'Address use Id.Addr; + begin + for I in Str'Range loop + if Str (I) = ASCII.NUL then + return I - 1; + end if; + end loop; + raise Program_Error; + end Get_String_Length; + + function Get_String (Id : O_Ident) return String + is + Str : Fat_String; + pragma Import (Ada, Str); + for Str'Address use Id.Addr; + begin + for I in Str'Range loop + if Str (I) = ASCII.NUL then + return Str (1 .. I - 1); + end if; + end loop; + raise Program_Error; + end Get_String; + + function Get_Cstring (Id : O_Ident) return System.Address is + begin + return Id.Addr; + end Get_Cstring; + + function Is_Equal (Id : O_Ident; Str : String) return Boolean + is + Istr : Fat_String; + pragma Import (Ada, Istr); + for Istr'Address use Id.Addr; + + Str_Len : constant Natural := Str'Length; + begin + for I in Istr'Range loop + if Istr (I) = ASCII.NUL then + return I - 1 = Str_Len; + end if; + if I > Str_Len then + return False; + end if; + if Istr (I) /= Str (Str'First + I - 1) then + return False; + end if; + end loop; + raise Program_Error; + end Is_Equal; + + function Is_Nul (Id : O_Ident) return Boolean is + begin + return Id = O_Ident_Nul; + end Is_Nul; + +end Ortho_Ident; diff --git a/src/ortho/llvm/ortho_ident.ads b/src/ortho/llvm/ortho_ident.ads new file mode 100644 index 000000000..7d3955c02 --- /dev/null +++ b/src/ortho/llvm/ortho_ident.ads @@ -0,0 +1,42 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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 System; + +package Ortho_Ident is + type O_Ident is private; + + function Get_Identifier (Str : String) return O_Ident; + function Is_Equal (L, R : O_Ident) return Boolean; + function Is_Equal (Id : O_Ident; Str : String) return Boolean; + function Is_Nul (Id : O_Ident) return Boolean; + function Get_String (Id : O_Ident) return String; + function Get_String_Length (Id : O_Ident) return Natural; + + -- Note: the address is always valid. + function Get_Cstring (Id : O_Ident) return System.Address; + + O_Ident_Nul : constant O_Ident; + +private + type O_Ident is record + Addr : System.Address; + end record; + O_Ident_Nul : constant O_Ident := (Addr => System.Null_Address); + + pragma Inline (Get_Cstring); +end Ortho_Ident; diff --git a/src/ortho/llvm/ortho_jit.adb b/src/ortho/llvm/ortho_jit.adb new file mode 100644 index 000000000..fdda667d9 --- /dev/null +++ b/src/ortho/llvm/ortho_jit.adb @@ -0,0 +1,151 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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 GNAT.OS_Lib; use GNAT.OS_Lib; +with Ada.Text_IO; use Ada.Text_IO; + +with Ortho_LLVM; use Ortho_LLVM; +with Ortho_LLVM.Jit; + +with LLVM.Core; use LLVM.Core; +with LLVM.Target; use LLVM.Target; +-- with LLVM.TargetMachine; use LLVM.TargetMachine; +with LLVM.ExecutionEngine; use LLVM.ExecutionEngine; +with LLVM.Analysis; +-- with Interfaces; +with Interfaces.C; use Interfaces.C; + +package body Ortho_Jit is + -- Snap_Filename : GNAT.OS_Lib.String_Access := null; + + Flag_Dump_Llvm : Boolean := False; + + -- Name of the module. + Module_Name : String := "ortho" & Ascii.Nul; + + -- procedure DisableLazyCompilation (EE : ExecutionEngineRef; + -- Disable : int); + -- pragma Import (C, DisableLazyCompilation, + -- "LLVMDisableLazyCompilation"); + + -- Initialize the whole engine. + procedure Init + is + Msg : aliased Cstring; + begin + InitializeNativeTarget; + InitializeNativeAsmPrinter; + + LinkInJIT; + + Module := ModuleCreateWithName (Module_Name'Address); + + -- Now we going to create JIT + if CreateExecutionEngineForModule + (Ortho_LLVM.Jit.Engine'Access, Module, Msg'Access) /= 0 + then + Put_Line (Standard_Error, "cannot create execution engine"); + raise Program_Error; + end if; + + Target_Data := GetExecutionEngineTargetData (Ortho_LLVM.Jit.Engine); + SetDataLayout (Module, CopyStringRepOfTargetData (Target_Data)); + + Ortho_LLVM.Init; + end Init; + + procedure Set_Address (Decl : O_Dnode; Addr : Address) + renames Ortho_LLVM.Jit.Set_Address; + + function Get_Address (Decl : O_Dnode) return Address + renames Ortho_LLVM.Jit.Get_Address; + + -- procedure InstallLazyFunctionCreator (EE : ExecutionEngineRef; + -- Func : Address); + -- pragma Import (C, InstallLazyFunctionCreator, + -- "LLVMInstallLazyFunctionCreator"); + + -- Do link. + procedure Link (Status : out Boolean) + is + use LLVM.Analysis; + Msg : aliased Cstring; + begin + if Flag_Debug then + Ortho_LLVM.Finish_Debug; + end if; + + if Flag_Dump_Llvm then + DumpModule (Module); + end if; + + -- Verify module. + if LLVM.Analysis.VerifyModule + (Module, LLVM.Analysis.PrintMessageAction, Msg'Access) /= 0 + then + DisposeMessage (Msg); + Status := False; + return; + end if; + + -- FIXME: optim + end Link; + + procedure Finish + is + -- F : ValueRef; + -- Addr : Address; + -- pragma Unreferenced (Addr); + begin + null; + + -- if No_Lazy then + -- -- Be sure all functions code has been generated. + -- F := GetFirstFunction (Module); + -- while F /= Null_ValueRef loop + -- if GetFirstBasicBlock (F) /= Null_BasicBlockRef then + -- -- Only care about defined functions. + -- Addr := GetPointerToFunction (EE, F); + -- end if; + -- F := GetNextFunction (F); + -- end loop; + -- end if; + end Finish; + + function Decode_Option (Option : String) return Boolean + is + Opt : constant String (1 .. Option'Length) := Option; + begin + if Opt = "--llvm-dump" then + Flag_Dump_Llvm := True; + return True; + end if; + return False; + end Decode_Option; + + procedure Disp_Help is + begin + null; + end Disp_Help; + + function Get_Jit_Name return String is + begin + return "LLVM"; + end Get_Jit_Name; + +end Ortho_Jit; diff --git a/src/ortho/llvm/ortho_llvm-jit.adb b/src/ortho/llvm/ortho_llvm-jit.adb new file mode 100644 index 000000000..9155a02c7 --- /dev/null +++ b/src/ortho/llvm/ortho_llvm-jit.adb @@ -0,0 +1,55 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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. + +package body Ortho_LLVM.Jit is + -- procedure AddExternalFunction (Name : Cstring; Val : Address); + -- pragma Import (C, AddExternalFunction, "ortho_AddExternalFunction"); + + function GetPointerToFunction (EE : ExecutionEngineRef; Func : ValueRef) + return Address; + pragma Import (C, GetPointerToFunction, "LLVMGetPointerToFunction"); + + -- Set address of non-defined global variables or functions. + procedure Set_Address (Decl : O_Dnode; Addr : Address) is + begin + case Decl.Kind is + when ON_Var_Decl | ON_Const_Decl => + AddGlobalMapping (Engine, Decl.LLVM, Addr); + when ON_Subprg_Decl => + null; + -- AddExternalFunction (GetValueName (Decl.LLVM), Addr); + when others => + raise Program_Error; + end case; + end Set_Address; + + -- Get address of a global. + function Get_Address (Decl : O_Dnode) return Address + is + begin + case Decl.Kind is + when ON_Var_Decl | ON_Const_Decl => + return GetPointerToGlobal (Engine, Decl.LLVM); + when ON_Subprg_Decl => + return GetPointerToFunction (Engine, Decl.LLVM); + when others => + raise Program_Error; + end case; + end Get_Address; + +end Ortho_LLVM.Jit; diff --git a/src/ortho/llvm/ortho_llvm-jit.ads b/src/ortho/llvm/ortho_llvm-jit.ads new file mode 100644 index 000000000..5296e2ed8 --- /dev/null +++ b/src/ortho/llvm/ortho_llvm-jit.ads @@ -0,0 +1,31 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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 System; use System; +with LLVM.ExecutionEngine; use LLVM.ExecutionEngine; + +package Ortho_LLVM.Jit is + -- Set address of non-defined global variables or functions. + procedure Set_Address (Decl : O_Dnode; Addr : Address); + -- Get address of a global. + function Get_Address (Decl : O_Dnode) return Address; + + -- Execution engine + Engine : aliased ExecutionEngineRef; + +end Ortho_LLVM.Jit; diff --git a/src/ortho/llvm/ortho_llvm.adb b/src/ortho/llvm/ortho_llvm.adb new file mode 100644 index 000000000..dd8e64971 --- /dev/null +++ b/src/ortho/llvm/ortho_llvm.adb @@ -0,0 +1,2881 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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.Unchecked_Conversion; +with Ada.Unchecked_Deallocation; +with LLVM.Target; use LLVM.Target; +with GNAT.Directory_Operations; + +package body Ortho_LLVM is + -- The current function for LLVM (needed to add new basic blocks). + Cur_Func : ValueRef; + + -- The current function node (needed for return type). + Cur_Func_Decl : O_Dnode; + + -- Wether the code is currently unreachable. LLVM doesn't accept basic + -- blocks that cannot be reached (using trivial rules). So we need to + -- discard instructions after a return, a next or an exit statement. + Unreach : Boolean; + + -- Builder for statements. + Builder : BuilderRef; + + -- Builder for declarations (local variables). + Decl_Builder : BuilderRef; + + -- Temporary builder. + Extra_Builder : BuilderRef; + + -- Declaration of llvm.dbg.declare + Llvm_Dbg_Declare : ValueRef; + + Debug_ID : unsigned; + + Current_Directory : constant String := + GNAT.Directory_Operations.Get_Current_Dir; + + -- Additional data for declare blocks. + type Declare_Block_Type; + type Declare_Block_Acc is access Declare_Block_Type; + + type Declare_Block_Type is record + -- First basic block of the declare. + Stmt_Bb : BasicBlockRef; + + -- Stack pointer at entry of the block. This value has to be restore + -- when leaving the block (either normally or via exit/next). Set only + -- if New_Alloca was used. + -- FIXME: TODO: restore stack pointer on exit/next stmts. + Stack_Value : ValueRef; + + -- Debug data for the scope of the declare block. + Dbg_Scope : ValueRef; + + -- Previous element in the stack. + Prev : Declare_Block_Acc; + end record; + + -- Current declare block. + Cur_Declare_Block : Declare_Block_Acc; + + -- Chain of unused blocks to be recycled. + Old_Declare_Block : Declare_Block_Acc; + + Stacksave_Fun : ValueRef; + Stacksave_Name : constant String := "llvm.stacksave" & ASCII.NUL; + Stackrestore_Fun : ValueRef; + Stackrestore_Name : constant String := "llvm.stackrestore" & ASCII.NUL; + + -- For debugging + + DW_Version : constant := 16#c_0000#; + DW_TAG_Array_Type : constant := DW_Version + 16#01#; + DW_TAG_Enumeration_Type : constant := DW_Version + 16#04#; + DW_TAG_Lexical_Block : constant := DW_Version + 16#0b#; + DW_TAG_Member : constant := DW_Version + 16#0d#; + DW_TAG_Pointer_Type : constant := DW_Version + 16#0f#; + DW_TAG_Compile_Unit : constant := DW_Version + 16#11#; + DW_TAG_Structure_Type : constant := DW_Version + 16#13#; + DW_TAG_Subroutine_Type : constant := DW_Version + 16#15#; + DW_TAG_Subrange_Type : constant := DW_Version + 16#21#; + DW_TAG_Base_Type : constant := DW_Version + 16#24#; + DW_TAG_Enumerator : constant := DW_Version + 16#28#; + DW_TAG_File_Type : constant := DW_Version + 16#29#; + DW_TAG_Subprogram : constant := DW_Version + 16#2e#; + DW_TAG_Variable : constant := DW_Version + 16#34#; + + DW_TAG_Auto_Variable : constant := DW_Version + 16#100#; + DW_TAG_Arg_Variable : constant := DW_Version + 16#101#; + + DW_ATE_address : constant := 16#01#; + DW_ATE_boolean : constant := 16#02#; + DW_ATE_float : constant := 16#04#; + DW_ATE_signed : constant := 16#05#; + DW_ATE_unsigned : constant := 16#07#; + pragma Unreferenced (DW_ATE_address, DW_ATE_boolean); + + -- File + Dir metadata + Dbg_Current_Filedir : ValueRef; + Dbg_Current_File : ValueRef; -- The DW_TAG_File_Type + + Dbg_Current_Line : unsigned := 0; + + Dbg_Current_Scope : ValueRef; + Scope_Uniq_Id : Unsigned_64 := 0; + + -- Metadata for the instruction + Dbg_Insn_MD : ValueRef; + Dbg_Insn_MD_Line : unsigned := 0; + + procedure Free is new Ada.Unchecked_Deallocation + (ValueRefArray, ValueRefArray_Acc); + + package Dbg_Utils is + type Dyn_MDNode is private; + + procedure Append (D : in out Dyn_MDNode; Val : ValueRef); + function Get_Value (D : Dyn_MDNode) return ValueRef; + + -- Reset D. FIXME: should be done automatically within Get_Value. + procedure Clear (D : out Dyn_MDNode); + private + Chunk_Length : constant unsigned := 32; + type MD_Chunk; + type MD_Chunk_Acc is access MD_Chunk; + + type MD_Chunk is record + Vals : ValueRefArray (1 .. Chunk_Length); + Next : MD_Chunk_Acc; + end record; + + type Dyn_MDNode is record + First : MD_Chunk_Acc; + Last : MD_Chunk_Acc; + Nbr : unsigned := 0; + end record; + end Dbg_Utils; + + package body Dbg_Utils is + procedure Append (D : in out Dyn_MDNode; Val : ValueRef) is + Chunk : MD_Chunk_Acc; + Pos : constant unsigned := D.Nbr rem Chunk_Length; + begin + if Pos = 0 then + Chunk := new MD_Chunk; + if D.First = null then + D.First := Chunk; + else + D.Last.Next := Chunk; + end if; + D.Last := Chunk; + else + Chunk := D.Last; + end if; + Chunk.Vals (Pos + 1) := Val; + D.Nbr := D.Nbr + 1; + end Append; + + procedure Free is new Ada.Unchecked_Deallocation + (MD_Chunk, MD_Chunk_Acc); + + function Get_Value (D : Dyn_MDNode) return ValueRef + is + Vals : ValueRefArray (1 .. D.Nbr); + Pos : unsigned; + Chunk : MD_Chunk_Acc := D.First; + Next_Chunk : MD_Chunk_Acc; + Nbr : constant unsigned := D.Nbr; + begin + Pos := 0; + -- Copy by chunks + while Pos + Chunk_Length < Nbr loop + Vals (Pos + 1 .. Pos + Chunk_Length) := Chunk.Vals; + Pos := Pos + Chunk_Length; + Next_Chunk := Chunk.Next; + Free (Chunk); + Chunk := Next_Chunk; + end loop; + -- Last chunk + if Pos < Nbr then + Vals (Pos + 1 .. Pos + Nbr - Pos) := Chunk.Vals (1 .. Nbr - Pos); + Free (Chunk); + end if; + return MDNode (Vals, Vals'Length); + end Get_Value; + + procedure Clear (D : out Dyn_MDNode) is + begin + D := (null, null, 0); + end Clear; + end Dbg_Utils; + + use Dbg_Utils; + + -- List of debug info for subprograms. + Subprg_Nodes: Dyn_MDNode; + + -- List of literals for enumerated type + Enum_Nodes : Dyn_MDNode; + + -- List of global variables + Global_Nodes : Dyn_MDNode; + + -- Create a MDString from an Ada string. + function MDString (Str : String) return ValueRef is + begin + return MDString (Str'Address, Str'Length); + end MDString; + + function MDString (Id : O_Ident) return ValueRef is + begin + return MDString (Get_Cstring (Id), unsigned (Get_String_Length (Id))); + end MDString; + + function Dbg_Size (Atype : TypeRef) return ValueRef is + begin + return ConstInt (Int64Type, 8 * ABISizeOfType (Target_Data, Atype), 0); + end Dbg_Size; + + function Dbg_Align (Atype : TypeRef) return ValueRef is + begin + return ConstInt + (Int64Type, + Unsigned_64 (8 * ABIAlignmentOfType (Target_Data, Atype)), 0); + end Dbg_Align; + + function Dbg_Line return ValueRef is + begin + return ConstInt (Int32Type, Unsigned_64 (Dbg_Current_Line), 0); + end Dbg_Line; + + -- Set debug metadata on instruction INSN. + -- FIXME: check if INSN is really an instruction + procedure Set_Insn_Dbg (Insn : ValueRef) is + begin + if Flag_Debug then + if Dbg_Current_Line /= Dbg_Insn_MD_Line then + declare + Vals : ValueRefArray (0 .. 3); + begin + Vals := (Dbg_Line, + ConstInt (Int32Type, 0, 0), -- col + Dbg_Current_Scope, -- context + Null_ValueRef); -- inline + Dbg_Insn_MD := MDNode (Vals, Vals'Length); + Dbg_Insn_MD_Line := Dbg_Current_Line; + end; + end if; + SetMetadata (Insn, Debug_ID, Dbg_Insn_MD); + end if; + end Set_Insn_Dbg; + + procedure Dbg_Create_Variable (Tag : Unsigned_32; + Ident : O_Ident; + Vtype : O_Tnode; + Argno : Natural; + Addr : ValueRef) + is + Vals : ValueRefArray (0 .. 7); + Str : constant ValueRef := MDString (Ident); + Call_Vals : ValueRefArray (0 .. 1); + Call : ValueRef; + begin + Vals := (ConstInt (Int32Type, Unsigned_64 (Tag), 0), + Dbg_Current_Scope, + Str, + Dbg_Current_File, + ConstInt (Int32Type, + Unsigned_64 (Dbg_Current_Line) + + Unsigned_64 (Argno) * 2 ** 24, 0), + Vtype.Dbg, + ConstInt (Int32Type, 0, 0), -- flags + ConstInt (Int32Type, 0, 0)); + + Call_Vals := (MDNode ((0 => Addr), 1), + MDNode (Vals, Vals'Length)); + Call := BuildCall (Decl_Builder, Llvm_Dbg_Declare, + Call_Vals, Call_Vals'Length, Empty_Cstring); + Set_Insn_Dbg (Call); + end Dbg_Create_Variable; + + procedure Create_Declare_Block + is + Res : Declare_Block_Acc; + begin + -- Try to recycle an unused record. + if Old_Declare_Block /= null then + Res := Old_Declare_Block; + Old_Declare_Block := Res.Prev; + else + -- Create a new one if no unused records. + Res := new Declare_Block_Type; + end if; + + -- Chain. + Res.all := (Stmt_Bb => Null_BasicBlockRef, + Stack_Value => Null_ValueRef, + Dbg_Scope => Null_ValueRef, + Prev => Cur_Declare_Block); + Cur_Declare_Block := Res; + + if not Unreach then + Res.Stmt_Bb := AppendBasicBlock (Cur_Func, Empty_Cstring); + end if; + end Create_Declare_Block; + + procedure Destroy_Declare_Block + is + Blk : constant Declare_Block_Acc := Cur_Declare_Block; + begin + -- Unchain. + Cur_Declare_Block := Blk.Prev; + + -- Put on the recyle list. + Blk.Prev := Old_Declare_Block; + Old_Declare_Block := Blk; + end Destroy_Declare_Block; + + ----------------------- + -- Start_Record_Type -- + ----------------------- + + procedure Start_Record_Type (Elements : out O_Element_List) is + begin + Elements := (Nbr_Elements => 0, + Rec_Type => O_Tnode_Null, + Size => 0, + Align => 0, + Align_Type => Null_TypeRef, + First_Elem => null, + Last_Elem => null); + end Start_Record_Type; + + ---------------------- + -- New_Record_Field -- + ---------------------- + + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode) + is + O_El : O_Element_Acc; + begin + El := (Kind => OF_Record, + Index => Elements.Nbr_Elements, + Ftype => Etype); + Elements.Nbr_Elements := Elements.Nbr_Elements + 1; + O_El := new O_Element'(Next => null, + Etype => Etype, + Ident => Ident); + if Elements.First_Elem = null then + Elements.First_Elem := O_El; + else + Elements.Last_Elem.Next := O_El; + end if; + Elements.Last_Elem := O_El; + end New_Record_Field; + + ------------------------ + -- Finish_Record_Type -- + ------------------------ + + procedure Finish_Record_Type + (Elements : in out O_Element_List; + Res : out O_Tnode) + is + procedure Free is new Ada.Unchecked_Deallocation + (O_Element, O_Element_Acc); + + Count : constant unsigned := unsigned (Elements.Nbr_Elements); + El : O_Element_Acc; + Next_El : O_Element_Acc; + Types : TypeRefArray (1 .. Count); + begin + El := Elements.First_Elem; + for I in Types'Range loop + Types (I) := Get_LLVM_Type (El.Etype); + El := El.Next; + end loop; + + if Elements.Rec_Type /= null then + -- Completion + StructSetBody (Elements.Rec_Type.LLVM, Types, Count, 0); + Res := Elements.Rec_Type; + else + Res := new O_Tnode_Type'(Kind => ON_Record_Type, + LLVM => StructType (Types, Count, 0), + Dbg => Null_ValueRef); + end if; + + if Flag_Debug then + declare + Fields : ValueRefArray (1 .. Count); + Vals : ValueRefArray (0 .. 9); + Ftype : TypeRef; + Fields_Arr : ValueRef; + begin + El := Elements.First_Elem; + for I in Fields'Range loop + Ftype := Get_LLVM_Type (El.Etype); + Vals := + (ConstInt (Int32Type, DW_TAG_Member, 0), + Dbg_Current_File, + Null_ValueRef, + MDString (El.Ident), + ConstInt (Int32Type, 0, 0), -- linenum + Dbg_Size (Ftype), + Dbg_Align (Ftype), + ConstInt + (Int32Type, + 8 * OffsetOfElement (Target_Data, + Res.LLVM, Unsigned_32 (I - 1)), 0), + ConstInt (Int32Type, 0, 0), -- Flags + El.Etype.Dbg); + Fields (I) := MDNode (Vals, Vals'Length); + El := El.Next; + end loop; + Fields_Arr := MDNode (Fields, Fields'Length); + if Elements.Rec_Type /= null then + -- Completion + MDNodeReplaceOperandWith (Res.Dbg, 10, Fields_Arr); + MDNodeReplaceOperandWith (Res.Dbg, 5, Dbg_Size (Res.LLVM)); + MDNodeReplaceOperandWith (Res.Dbg, 6, Dbg_Align (Res.LLVM)); + else + -- Temporary borrowed. + Res.Dbg := Fields_Arr; + end if; + end; + end if; + + -- Free elements + El := Elements.First_Elem; + for I in Types'Range loop + Next_El := El.Next; + Free (El); + El := Next_El; + end loop; + end Finish_Record_Type; + + -------------------------------- + -- New_Uncomplete_Record_Type -- + -------------------------------- + + procedure New_Uncomplete_Record_Type (Res : out O_Tnode) is + begin + -- LLVM type will be created when the type is declared. + Res := new O_Tnode_Type'(Kind => ON_Incomplete_Record_Type, + LLVM => Null_TypeRef, + Dbg => Null_ValueRef); + end New_Uncomplete_Record_Type; + + ---------------------------------- + -- Start_Uncomplete_Record_Type -- + ---------------------------------- + + procedure Start_Uncomplete_Record_Type + (Res : O_Tnode; + Elements : out O_Element_List) + is + begin + if Res.Kind /= ON_Incomplete_Record_Type then + raise Program_Error; + end if; + Elements := (Nbr_Elements => 0, + Rec_Type => Res, + Size => 0, + Align => 0, + Align_Type => Null_TypeRef, + First_Elem => null, + Last_Elem => null); + end Start_Uncomplete_Record_Type; + + ---------------------- + -- Start_Union_Type -- + ---------------------- + + procedure Start_Union_Type (Elements : out O_Element_List) is + begin + Elements := (Nbr_Elements => 0, + Rec_Type => O_Tnode_Null, + Size => 0, + Align => 0, + Align_Type => Null_TypeRef, + First_Elem => null, + Last_Elem => null); + end Start_Union_Type; + + --------------------- + -- New_Union_Field -- + --------------------- + + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode) + is + pragma Unreferenced (Ident); + + El_Type : constant TypeRef := Get_LLVM_Type (Etype); + Size : constant unsigned := + unsigned (ABISizeOfType (Target_Data, El_Type)); + Align : constant Unsigned_32 := + ABIAlignmentOfType (Target_Data, El_Type); + begin + El := (Kind => OF_Union, Utype => El_Type, Ftype => Etype); + if Size > Elements.Size then + Elements.Size := Size; + end if; + if Elements.Align_Type = Null_TypeRef or else Align > Elements.Align then + Elements.Align := Align; + Elements.Align_Type := El_Type; + end if; + end New_Union_Field; + + ----------------------- + -- Finish_Union_Type -- + ----------------------- + + procedure Finish_Union_Type + (Elements : in out O_Element_List; + Res : out O_Tnode) + is + Count : unsigned; + Types : TypeRefArray (1 .. 2); + Pad : unsigned; + begin + if Elements.Align_Type = Null_TypeRef then + -- An empty union. Is it allowed ? + Count := 0; + else + -- The first element is the field with the biggest alignment + Types (1) := Elements.Align_Type; + -- Possibly complete with an array of bytes. + Pad := Elements.Size + - unsigned (ABISizeOfType (Target_Data, Elements.Align_Type)); + if Pad /= 0 then + Types (2) := ArrayType (Int8Type, Pad); + Count := 2; + else + Count := 1; + end if; + end if; + Res := new O_Tnode_Type'(Kind => ON_Union_Type, + LLVM => StructType (Types, Count, 0), + Dbg => Null_ValueRef, + Un_Size => Elements.Size, + Un_Main_Field => Elements.Align_Type); + end Finish_Union_Type; + + --------------------- + -- New_Access_Type -- + --------------------- + + function New_Access_Type (Dtype : O_Tnode) return O_Tnode is + begin + if Dtype = O_Tnode_Null then + -- LLVM type will be built by New_Type_Decl, so that the name + -- can be used for the structure. + return new O_Tnode_Type'(Kind => ON_Incomplete_Access_Type, + LLVM => Null_TypeRef, + Dbg => Null_ValueRef, + Acc_Type => O_Tnode_Null); + else + return new O_Tnode_Type'(Kind => ON_Access_Type, + LLVM => PointerType (Get_LLVM_Type (Dtype)), + Dbg => Null_ValueRef, + Acc_Type => Dtype); + end if; + end New_Access_Type; + + ------------------------ + -- Finish_Access_Type -- + ------------------------ + + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode) + is + Types : TypeRefArray (1 .. 1); + begin + if Atype.Kind /= ON_Incomplete_Access_Type then + -- Not an incomplete access type. + raise Program_Error; + end if; + if Atype.Acc_Type /= O_Tnode_Null then + -- Already completed. + raise Program_Error; + end if; + -- Completion + Types (1) := Get_LLVM_Type (Dtype); + StructSetBody (GetElementType (Atype.LLVM), Types, Types'Length, 0); + Atype.Acc_Type := Dtype; + + -- Debug. + -- FIXME. + end Finish_Access_Type; + + -------------------- + -- New_Array_Type -- + -------------------- + + function Dbg_Array (El_Type : O_Tnode; Len : ValueRef; Atype : O_Tnode) + return ValueRef + is + Rng : ValueRefArray (0 .. 2); + Rng_Arr : ValueRefArray (0 .. 0); + Vals : ValueRefArray (0 .. 14); + begin + Rng := (ConstInt (Int32Type, DW_TAG_Subrange_Type, 0), + ConstInt (Int64Type, 0, 0), -- Lo + Len); -- Count + Rng_Arr := (0 => MDNode (Rng, Rng'Length)); + Vals := (ConstInt (Int32Type, DW_TAG_Array_Type, 0), + Null_ValueRef, + Null_ValueRef, -- context + Null_ValueRef, + ConstInt (Int32Type, 0, 0), -- line + Dbg_Size (Atype.LLVM), + Dbg_Align (Atype.LLVM), + ConstInt (Int32Type, 0, 0), -- Offset + ConstInt (Int32Type, 0, 0), -- Flags + El_Type.Dbg, -- element type + MDNode (Rng_Arr, Rng_Arr'Length), -- subscript + ConstInt (Int32Type, 0, 0), + Null_ValueRef, + Null_ValueRef, + Null_ValueRef); -- Runtime lang + return MDNode (Vals, Vals'Length); + end Dbg_Array; + + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode + is + pragma Unreferenced (Index_Type); + Res : O_Tnode; + begin + Res := new O_Tnode_Type' + (Kind => ON_Array_Type, + LLVM => ArrayType (Get_LLVM_Type (El_Type), 0), + Dbg => Null_ValueRef, + Arr_El_Type => El_Type); + + if Flag_Debug then + Res.Dbg := Dbg_Array + (El_Type, ConstInt (Int64Type, Unsigned_64'Last, 1), Res); + end if; + + return Res; + end New_Array_Type; + + -------------------------------- + -- New_Constrained_Array_Type -- + -------------------------------- + + function New_Constrained_Array_Type + (Atype : O_Tnode; Length : O_Cnode) return O_Tnode + is + Res : O_Tnode; + Len : constant unsigned := unsigned (ConstIntGetZExtValue (Length.LLVM)); + begin + Res := new O_Tnode_Type' + (Kind => ON_Array_Sub_Type, + LLVM => ArrayType (GetElementType (Get_LLVM_Type (Atype)), Len), + Dbg => Null_ValueRef, + Arr_El_Type => Atype.Arr_El_Type); + + if Flag_Debug then + Res.Dbg := Dbg_Array + (Atype.Arr_El_Type, + ConstInt (Int64Type, Unsigned_64 (Len), 0), Res); + end if; + + return Res; + end New_Constrained_Array_Type; + + ----------------------- + -- New_Unsigned_Type -- + ----------------------- + + function Size_To_Llvm (Size : Natural) return TypeRef is + Llvm : TypeRef; + begin + case Size is + when 8 => + Llvm := Int8Type; + when 32 => + Llvm := Int32Type; + when 64 => + Llvm := Int64Type; + when others => + raise Program_Error; + end case; + return Llvm; + end Size_To_Llvm; + + function New_Unsigned_Type (Size : Natural) return O_Tnode is + begin + return new O_Tnode_Type'(Kind => ON_Unsigned_Type, + LLVM => Size_To_Llvm (Size), + Dbg => Null_ValueRef, + Scal_Size => Size); + end New_Unsigned_Type; + + --------------------- + -- New_Signed_Type -- + --------------------- + + function New_Signed_Type (Size : Natural) return O_Tnode is + begin + return new O_Tnode_Type'(Kind => ON_Signed_Type, + LLVM => Size_To_Llvm (Size), + Dbg => Null_ValueRef, + Scal_Size => Size); + end New_Signed_Type; + + -------------------- + -- New_Float_Type -- + -------------------- + + function New_Float_Type return O_Tnode is + begin + return new O_Tnode_Type'(Kind => ON_Float_Type, + LLVM => DoubleType, + Dbg => Null_ValueRef, + Scal_Size => 64); + end New_Float_Type; + + procedure Dbg_Add_Enumeration (Id : O_Ident; Val : Unsigned_64) is + Vals : ValueRefArray (0 .. 2); + begin + Vals := (ConstInt (Int32Type, DW_TAG_Enumerator, 0), + MDString (Id), + ConstInt (Int64Type, Val, 0)); + -- FIXME: make it local to List ? + Append (Enum_Nodes, MDNode (Vals, Vals'Length)); + end Dbg_Add_Enumeration; + + ---------------------- + -- New_Boolean_Type -- + ---------------------- + + procedure New_Boolean_Type + (Res : out O_Tnode; + False_Id : O_Ident; False_E : out O_Cnode; + True_Id : O_Ident; True_E : out O_Cnode) + is + begin + Res := new O_Tnode_Type'(Kind => ON_Boolean_Type, + LLVM => Int1Type, + Dbg => Null_ValueRef, + Scal_Size => 1); + False_E := O_Cnode'(LLVM => ConstInt (Res.LLVM, 0, 0), + Ctype => Res); + True_E := O_Cnode'(LLVM => ConstInt (Res.LLVM, 1, 0), + Ctype => Res); + if Flag_Debug then + Dbg_Add_Enumeration (False_Id, 0); + Dbg_Add_Enumeration (True_Id, 1); + end if; + end New_Boolean_Type; + + --------------------- + -- Start_Enum_Type -- + --------------------- + + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural) + is + LLVM : constant TypeRef := Size_To_Llvm (Size); + begin + List := (LLVM => LLVM, + Num => 0, + Etype => new O_Tnode_Type'(Kind => ON_Enum_Type, + LLVM => LLVM, + Scal_Size => Size, + Dbg => Null_ValueRef)); + + end Start_Enum_Type; + + ---------------------- + -- New_Enum_Literal -- + ---------------------- + + procedure New_Enum_Literal + (List : in out O_Enum_List; Ident : O_Ident; Res : out O_Cnode) + is + begin + Res := O_Cnode'(LLVM => ConstInt (List.LLVM, Unsigned_64 (List.Num), 0), + Ctype => List.Etype); + if Flag_Debug then + Dbg_Add_Enumeration (Ident, Unsigned_64 (List.Num)); + end if; + + List.Num := List.Num + 1; + end New_Enum_Literal; + + ---------------------- + -- Finish_Enum_Type -- + ---------------------- + + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode) is + begin + Res := List.Etype; + end Finish_Enum_Type; + + ------------------------ + -- New_Signed_Literal -- + ------------------------ + + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode + is + function To_Unsigned_64 is new Ada.Unchecked_Conversion + (Integer_64, Unsigned_64); + begin + return O_Cnode'(LLVM => ConstInt (Get_LLVM_Type (Ltype), + To_Unsigned_64 (Value), 1), + Ctype => Ltype); + end New_Signed_Literal; + + -------------------------- + -- New_Unsigned_Literal -- + -------------------------- + + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode is + begin + return O_Cnode'(LLVM => ConstInt (Get_LLVM_Type (Ltype), Value, 0), + Ctype => Ltype); + end New_Unsigned_Literal; + + ----------------------- + -- New_Float_Literal -- + ----------------------- + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode is + begin + return O_Cnode'(LLVM => ConstReal (Get_LLVM_Type (Ltype), + Interfaces.C.double (Value)), + Ctype => Ltype); + end New_Float_Literal; + + --------------------- + -- New_Null_Access -- + --------------------- + + function New_Null_Access (Ltype : O_Tnode) return O_Cnode is + begin + return O_Cnode'(LLVM => ConstNull (Get_LLVM_Type (Ltype)), + Ctype => Ltype); + end New_Null_Access; + + ----------------------- + -- Start_Record_Aggr -- + ----------------------- + + procedure Start_Record_Aggr + (List : out O_Record_Aggr_List; + Atype : O_Tnode) + is + Llvm : constant TypeRef := Get_LLVM_Type (Atype); + begin + List := + (Len => 0, + Vals => new ValueRefArray (1 .. CountStructElementTypes (Llvm)), + Atype => Atype); + end Start_Record_Aggr; + + ------------------------ + -- New_Record_Aggr_El -- + ------------------------ + + procedure New_Record_Aggr_El + (List : in out O_Record_Aggr_List; Value : O_Cnode) + is + begin + List.Len := List.Len + 1; + List.Vals (List.Len) := Value.LLVM; + end New_Record_Aggr_El; + + ------------------------ + -- Finish_Record_Aggr -- + ------------------------ + + procedure Finish_Record_Aggr + (List : in out O_Record_Aggr_List; + Res : out O_Cnode) + is + begin + Res := (LLVM => ConstStruct (List.Vals.all, List.Len, 0), + Ctype => List.Atype); + Free (List.Vals); + end Finish_Record_Aggr; + + ---------------------- + -- Start_Array_Aggr -- + ---------------------- + + procedure Start_Array_Aggr + (List : out O_Array_Aggr_List; + Atype : O_Tnode) + is + Llvm : constant TypeRef := Get_LLVM_Type (Atype); + begin + List := (Len => 0, + Vals => new ValueRefArray (1 .. GetArrayLength (Llvm)), + El_Type => GetElementType (Llvm), + Atype => Atype); + end Start_Array_Aggr; + + ----------------------- + -- New_Array_Aggr_El -- + ----------------------- + + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode) + is + begin + List.Len := List.Len + 1; + List.Vals (List.Len) := Value.LLVM; + end New_Array_Aggr_El; + + ----------------------- + -- Finish_Array_Aggr -- + ----------------------- + + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode) + is + begin + Res := (LLVM => ConstArray (List.El_Type, + List.Vals.all, List.Len), + Ctype => List.Atype); + Free (List.Vals); + end Finish_Array_Aggr; + + -------------------- + -- New_Union_Aggr -- + -------------------- + + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode + is + Values : ValueRefArray (1 .. 2); + Count : unsigned; + Size : constant unsigned := + unsigned (ABISizeOfType (Target_Data, Field.Utype)); + + begin + Values (1) := Value.LLVM; + if Size < Atype.Un_Size then + Values (2) := GetUndef (ArrayType (Int8Type, Atype.Un_Size - Size)); + Count := 2; + else + Count := 1; + end if; + + -- If `FIELD` is the main field of the union, create a struct using + -- the same type as the union (and possibly pad). + if Field.Utype = Atype.Un_Main_Field then + return O_Cnode' + (LLVM => ConstNamedStruct (Atype.LLVM, Values, Count), + Ctype => Atype); + else + -- Create an on-the-fly record. + return O_Cnode'(LLVM => ConstStruct (Values, Count, 0), + Ctype => Atype); + end if; + end New_Union_Aggr; + + ---------------- + -- New_Sizeof -- + ---------------- + + -- Return VAL with type RTYPE (either unsigned or access) + function Const_To_Cnode (Rtype : O_Tnode; Val : Unsigned_64) return O_Cnode + is + Tmp : ValueRef; + begin + case Rtype.Kind is + when ON_Scalar_Types => + -- Well, unsigned in fact. + return O_Cnode'(LLVM => ConstInt (Rtype.LLVM, Val, 0), + Ctype => Rtype); + when ON_Access_Type => + Tmp := ConstInt (Int64Type, Val, 0); + return O_Cnode'(LLVM => ConstIntToPtr (Tmp, Rtype.LLVM), + Ctype => Rtype); + when others => + raise Program_Error; + end case; + end Const_To_Cnode; + + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode is + begin + return Const_To_Cnode + (Rtype, ABISizeOfType (Target_Data, Get_LLVM_Type (Atype))); + end New_Sizeof; + + ----------------- + -- New_Alignof -- + ----------------- + + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode is + begin + return Const_To_Cnode + (Rtype, + Unsigned_64 + (ABIAlignmentOfType (Target_Data, Get_LLVM_Type (Atype)))); + end New_Alignof; + + ------------------ + -- New_Offsetof -- + ------------------ + + function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode is + begin + return Const_To_Cnode + (Rtype, + OffsetOfElement (Target_Data, + Get_LLVM_Type (Atype), + Unsigned_32 (Field.Index))); + end New_Offsetof; + + ---------------------------- + -- New_Subprogram_Address -- + ---------------------------- + + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode is + begin + return O_Cnode' + (LLVM => ConstBitCast (Subprg.LLVM, Get_LLVM_Type (Atype)), + Ctype => Atype); + end New_Subprogram_Address; + + ------------------------ + -- New_Global_Address -- + ------------------------ + + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode is + begin + return O_Cnode'(LLVM => ConstBitCast (Decl.LLVM, Get_LLVM_Type (Atype)), + Ctype => Atype); + end New_Global_Address; + + ---------------------------------- + -- New_Global_Unchecked_Address -- + ---------------------------------- + + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode + is + begin + return O_Cnode'(LLVM => ConstBitCast (Decl.LLVM, Get_LLVM_Type (Atype)), + Ctype => Atype); + end New_Global_Unchecked_Address; + + ------------- + -- New_Lit -- + ------------- + + function New_Lit (Lit : O_Cnode) return O_Enode is + begin + return O_Enode'(LLVM => Lit.LLVM, + Etype => Lit.Ctype); + end New_Lit; + + ------------------- + -- New_Dyadic_Op -- + ------------------- + + function New_Smod (L, R : ValueRef; Res_Type : TypeRef) + return ValueRef + is + Cond : ValueRef; + Br : ValueRef; + pragma Unreferenced (Br); + + -- The result of 'L rem R'. + Rm : ValueRef; + + -- Rm + R + Rm_Plus_R : ValueRef; + + -- The result of 'L xor R'. + R_Xor : ValueRef; + + Adj : ValueRef; + Phi : ValueRef; + + -- Basic basic for the non-overflow branch + Normal_Bb : constant BasicBlockRef := + AppendBasicBlock (Cur_Func, Empty_Cstring); + + Adjust_Bb : constant BasicBlockRef := + AppendBasicBlock (Cur_Func, Empty_Cstring); + + -- Basic block after the result + Next_Bb : constant BasicBlockRef := + AppendBasicBlock (Cur_Func, Empty_Cstring); + + Vals : ValueRefArray (1 .. 3); + BBs : BasicBlockRefArray (1 .. 3); + begin + -- Avoid overflow with -1: + -- if R = -1 then + -- result := 0; + -- else + -- ... + Cond := BuildICmp + (Builder, IntEQ, R, ConstAllOnes (Res_Type), Empty_Cstring); + Br := BuildCondBr (Builder, Cond, Next_Bb, Normal_Bb); + Vals (1) := ConstNull (Res_Type); + BBs (1) := GetInsertBlock (Builder); + + -- Rm := Left rem Right + PositionBuilderAtEnd (Builder, Normal_Bb); + Rm := BuildSRem (Builder, L, R, Empty_Cstring); + + -- if R = 0 then + -- result := 0 + -- else + Cond := BuildICmp + (Builder, IntEQ, Rm, ConstNull (Res_Type), Empty_Cstring); + Br := BuildCondBr (Builder, Cond, Next_Bb, Adjust_Bb); + Vals (2) := ConstNull (Res_Type); + BBs (2) := Normal_Bb; + + -- if L xor R < 0 then + -- result := Rm + R + -- else + -- result := Rm; + -- end if; + PositionBuilderAtEnd (Builder, Adjust_Bb); + R_Xor := BuildXor (Builder, L, R, Empty_Cstring); + Cond := BuildICmp + (Builder, IntSLT, R_Xor, ConstNull (Res_Type), Empty_Cstring); + Rm_Plus_R := BuildAdd (Builder, Rm, R, Empty_Cstring); + Adj := BuildSelect (Builder, Cond, Rm_Plus_R, Rm, Empty_Cstring); + Br := BuildBr (Builder, Next_Bb); + Vals (3) := Adj; + BBs (3) := Adjust_Bb; + + -- The Phi node + PositionBuilderAtEnd (Builder, Next_Bb); + Phi := BuildPhi (Builder, Res_Type, Empty_Cstring); + AddIncoming (Phi, Vals, BBs, Vals'Length); + + return Phi; + end New_Smod; + + type Dyadic_Builder_Acc is access + function (Builder : BuilderRef; + LHS : ValueRef; RHS : ValueRef; Name : Cstring) + return ValueRef; + pragma Convention (C, Dyadic_Builder_Acc); + + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode + is + Build : Dyadic_Builder_Acc := null; + Res : ValueRef := Null_ValueRef; + begin + if Unreach then + return O_Enode'(LLVM => Null_ValueRef, Etype => Left.Etype); + end if; + + case Left.Etype.Kind is + when ON_Integer_Types => + case Kind is + when ON_And => + Build := BuildAnd'Access; + when ON_Or => + Build := BuildOr'Access; + when ON_Xor => + Build := BuildXor'Access; + + when ON_Add_Ov => + Build := BuildAdd'Access; + when ON_Sub_Ov => + Build := BuildSub'Access; + when ON_Mul_Ov => + Build := BuildMul'Access; + + when ON_Div_Ov => + case Left.Etype.Kind is + when ON_Unsigned_Type => + Build := BuildUDiv'Access; + when ON_Signed_Type => + Build := BuildSDiv'Access; + when others => + null; + end case; + + when ON_Mod_Ov + | ON_Rem_Ov => -- FIXME... + case Left.Etype.Kind is + when ON_Unsigned_Type => + Build := BuildURem'Access; + when ON_Signed_Type => + if Kind = ON_Rem_Ov then + Build := BuildSRem'Access; + else + Res := New_Smod + (Left.LLVM, Right.LLVM, Left.Etype.LLVM); + end if; + when others => + null; + end case; + end case; + + when ON_Float_Type => + case Kind is + when ON_Add_Ov => + Build := BuildFAdd'Access; + when ON_Sub_Ov => + Build := BuildFSub'Access; + when ON_Mul_Ov => + Build := BuildFMul'Access; + when ON_Div_Ov => + Build := BuildFDiv'Access; + + when others => + null; + end case; + + when others => + null; + end case; + + if Build /= null then + pragma Assert (Res = Null_ValueRef); + Res := Build.all (Builder, Left.LLVM, Right.LLVM, Empty_Cstring); + end if; + + if Res = Null_ValueRef then + raise Program_Error with "Unimplemented New_Dyadic_Op " + & ON_Dyadic_Op_Kind'Image (Kind) + & " for type " + & ON_Type_Kind'Image (Left.Etype.Kind); + end if; + + Set_Insn_Dbg (Res); + + return O_Enode'(LLVM => Res, Etype => Left.Etype); + end New_Dyadic_Op; + + -------------------- + -- New_Monadic_Op -- + -------------------- + + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode + is + Res : ValueRef; + begin + case Operand.Etype.Kind is + when ON_Integer_Types => + case Kind is + when ON_Not => + Res := BuildNot (Builder, Operand.LLVM, Empty_Cstring); + when ON_Neg_Ov => + Res := BuildNeg (Builder, Operand.LLVM, Empty_Cstring); + when ON_Abs_Ov => + Res := BuildSelect + (Builder, + BuildICmp (Builder, IntSLT, + Operand.LLVM, + ConstInt (Get_LLVM_Type (Operand.Etype), 0, 0), + Empty_Cstring), + BuildNeg (Builder, Operand.LLVM, Empty_Cstring), + Operand.LLVM, + Empty_Cstring); + end case; + when ON_Float_Type => + case Kind is + when ON_Not => + raise Program_Error; + when ON_Neg_Ov => + Res := BuildFNeg (Builder, Operand.LLVM, Empty_Cstring); + when ON_Abs_Ov => + Res := BuildSelect + (Builder, + BuildFCmp (Builder, RealOLT, + Operand.LLVM, + ConstReal (Get_LLVM_Type (Operand.Etype), 0.0), + Empty_Cstring), + BuildFNeg (Builder, Operand.LLVM, Empty_Cstring), + Operand.LLVM, + Empty_Cstring); + end case; + when others => + raise Program_Error; + end case; + + if IsAInstruction (Res) /= Null_ValueRef then + Set_Insn_Dbg (Res); + end if; + + return O_Enode'(LLVM => Res, Etype => Operand.Etype); + end New_Monadic_Op; + + -------------------- + -- New_Compare_Op -- + -------------------- + + type Compare_Op_Entry is record + Signed_Pred : IntPredicate; + Unsigned_Pred : IntPredicate; + Real_Pred : RealPredicate; + end record; + + type Compare_Op_Table_Type is array (ON_Compare_Op_Kind) of + Compare_Op_Entry; + + Compare_Op_Table : constant Compare_Op_Table_Type := + (ON_Eq => (IntEQ, IntEQ, RealOEQ), + ON_Neq => (IntNE, IntNE, RealONE), + ON_Le => (IntSLE, IntULE, RealOLE), + ON_Lt => (IntSLT, IntULT, RealOLT), + ON_Ge => (IntSGE, IntUGE, RealOGE), + ON_Gt => (IntSGT, IntUGT, RealOGT)); + + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; + Left, Right : O_Enode; + Ntype : O_Tnode) + return O_Enode + is + Res : ValueRef; + begin + case Left.Etype.Kind is + when ON_Unsigned_Type + | ON_Boolean_Type + | ON_Enum_Type + | ON_Access_Type + | ON_Incomplete_Access_Type => + Res := BuildICmp (Builder, Compare_Op_Table (Kind).Unsigned_Pred, + Left.LLVM, Right.LLVM, Empty_Cstring); + when ON_Signed_Type => + Res := BuildICmp (Builder, Compare_Op_Table (Kind).Signed_Pred, + Left.LLVM, Right.LLVM, Empty_Cstring); + when ON_Float_Type => + Res := BuildFCmp (Builder, Compare_Op_Table (Kind).Real_Pred, + Left.LLVM, Right.LLVM, Empty_Cstring); + when ON_Array_Type + | ON_Array_Sub_Type + | ON_Record_Type + | ON_Incomplete_Record_Type + | ON_Union_Type + | ON_No_Type => + raise Program_Error; + end case; + Set_Insn_Dbg (Res); + return O_Enode'(LLVM => Res, Etype => Ntype); + end New_Compare_Op; + + ------------------------- + -- New_Indexed_Element -- + ------------------------- + + function New_Indexed_Element (Arr : O_Lnode; Index : O_Enode) return O_Lnode + is + Idx : constant ValueRefArray (1 .. 2) := + (ConstInt (Int32Type, 0, 0), + Index.LLVM); + begin + return O_Lnode' + (Direct => False, + LLVM => BuildGEP (Builder, Arr.LLVM, Idx, Idx'Length, Empty_Cstring), + Ltype => Arr.Ltype.Arr_El_Type); + end New_Indexed_Element; + + --------------- + -- New_Slice -- + --------------- + + function New_Slice (Arr : O_Lnode; Res_Type : O_Tnode; Index : O_Enode) + return O_Lnode + is + Idx : constant ValueRefArray (1 .. 2) := + (ConstInt (Int32Type, 0, 0), + Index.LLVM); + Tmp : ValueRef; + begin + Tmp := BuildGEP (Builder, Arr.LLVM, Idx, Idx'Length, Empty_Cstring); + Tmp := BuildBitCast + (Builder, Tmp, PointerType (Get_LLVM_Type (Res_Type)), Empty_Cstring); + return O_Lnode'(Direct => False, LLVM => Tmp, Ltype => Res_Type); + end New_Slice; + + -------------------------- + -- New_Selected_Element -- + -------------------------- + + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode + is + Res : ValueRef; + begin + if Unreach then + Res := Null_ValueRef; + else + declare + Idx : constant ValueRefArray (1 .. 2) := + (ConstInt (Int32Type, 0, 0), + ConstInt (Int32Type, Unsigned_64 (El.Index), 0)); + begin + Res := BuildGEP (Builder, Rec.LLVM, Idx, 2, Empty_Cstring); + end; + end if; + return O_Lnode'(Direct => False, LLVM => Res, Ltype => El.Ftype); + end New_Selected_Element; + + ------------------------ + -- New_Access_Element -- + ------------------------ + + function New_Access_Element (Acc : O_Enode) return O_Lnode + is + Res : ValueRef; + begin + case Acc.Etype.Kind is + when ON_Access_Type => + Res := Acc.LLVM; + when ON_Incomplete_Access_Type => + -- Unwrap the structure + declare + Idx : constant ValueRefArray (1 .. 2) := + (ConstInt (Int32Type, 0, 0), ConstInt (Int32Type, 0, 0)); + begin + Res := BuildGEP (Builder, Acc.LLVM, Idx, 2, Empty_Cstring); + end; + when others => + raise Program_Error; + end case; + return O_Lnode'(Direct => False, + LLVM => Res, + Ltype => Acc.Etype.Acc_Type); + end New_Access_Element; + + -------------------- + -- New_Convert_Ov -- + -------------------- + + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode + is + Res : ValueRef := Null_ValueRef; + begin + if Rtype = Val.Etype then + -- Convertion to itself: nothing to do. + return Val; + end if; + if Rtype.LLVM = Val.Etype.LLVM then + -- Same underlying LLVM type: nothing to do. + return Val; + end if; + + case Rtype.Kind is + when ON_Integer_Types => + case Val.Etype.Kind is + when ON_Integer_Types => + -- Int to Int + if Val.Etype.Scal_Size > Rtype.Scal_Size then + -- Truncate + Res := BuildTrunc + (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + elsif Val.Etype.Scal_Size < Rtype.Scal_Size then + if Val.Etype.Kind = ON_Signed_Type then + Res := BuildSExt + (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + else + -- Unsigned, enum + Res := BuildZExt + (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + end if; + else + Res := BuildBitCast + (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + end if; + + when ON_Float_Type => + -- Float to Int + if Rtype.Kind = ON_Signed_Type then + Res := BuildFPToSI + (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + end if; + + when others => + null; + end case; + + when ON_Float_Type => + if Val.Etype.Kind = ON_Signed_Type then + Res := BuildSIToFP + (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + elsif Val.Etype.Kind = ON_Unsigned_Type then + Res := BuildUIToFP + (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + end if; + + when ON_Access_Type + | ON_Incomplete_Access_Type => + if GetTypeKind (TypeOf (Val.LLVM)) /= PointerTypeKind then + raise Program_Error; + end if; + Res := BuildBitCast (Builder, Val.LLVM, Get_LLVM_Type (Rtype), + Empty_Cstring); + + when others => + null; + end case; + if Res /= Null_ValueRef then + -- FIXME: only if insn was generated + -- Set_Insn_Dbg (Res); + return O_Enode'(LLVM => Res, Etype => Rtype); + else + raise Program_Error with "New_Convert_Ov: not implemented for " + & ON_Type_Kind'Image (Val.Etype.Kind) + & " -> " + & ON_Type_Kind'Image (Rtype.Kind); + end if; + end New_Convert_Ov; + + ----------------- + -- New_Address -- + ----------------- + + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode is + begin + return O_Enode' + (LLVM => BuildBitCast (Builder, Lvalue.LLVM, Get_LLVM_Type (Atype), + Empty_Cstring), + Etype => Atype); + end New_Address; + + --------------------------- + -- New_Unchecked_Address -- + --------------------------- + + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode + is + begin + return O_Enode' + (LLVM => BuildBitCast (Builder, Lvalue.LLVM, Get_LLVM_Type (Atype), + Empty_Cstring), + Etype => Atype); + end New_Unchecked_Address; + + --------------- + -- New_Value -- + --------------- + + function New_Value (Lvalue : O_Lnode) return O_Enode + is + Res : ValueRef; + begin + if Unreach then + Res := Null_ValueRef; + else + Res := Lvalue.LLVM; + if not Lvalue.Direct then + Res := BuildLoad (Builder, Res, Empty_Cstring); + Set_Insn_Dbg (Res); + end if; + end if; + return O_Enode'(LLVM => Res, Etype => Lvalue.Ltype); + end New_Value; + + ------------------- + -- New_Obj_Value -- + ------------------- + + function New_Obj_Value (Obj : O_Dnode) return O_Enode is + begin + return New_Value (New_Obj (Obj)); + end New_Obj_Value; + + ------------- + -- New_Obj -- + ------------- + + function New_Obj (Obj : O_Dnode) return O_Lnode is + begin + case Obj.Kind is + when ON_Const_Decl + | ON_Var_Decl + | ON_Local_Decl => + return O_Lnode'(Direct => False, + LLVM => Obj.LLVM, + Ltype => Obj.Dtype); + + when ON_Interface_Decl => + if Flag_Debug then + -- The argument was allocated. + return O_Lnode'(Direct => False, + LLVM => Obj.Inter.Ival, + Ltype => Obj.Dtype); + else + return O_Lnode'(Direct => True, + LLVM => Obj.Inter.Ival, + Ltype => Obj.Dtype); + end if; + + when ON_Type_Decl + | ON_Completed_Type_Decl + | ON_Subprg_Decl + | ON_No_Decl => + raise Program_Error; + end case; + end New_Obj; + + ---------------- + -- New_Alloca -- + ---------------- + + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode + is + Res : ValueRef; + begin + if Unreach then + Res := Null_ValueRef; + else + if Cur_Declare_Block.Stack_Value = Null_ValueRef + and then Cur_Declare_Block.Prev /= null + then + -- Save stack pointer at entry of block + PositionBuilderBefore + (Extra_Builder, GetFirstInstruction (Cur_Declare_Block.Stmt_Bb)); + Cur_Declare_Block.Stack_Value := + BuildCall (Extra_Builder, Stacksave_Fun, + (1 .. 0 => Null_ValueRef), 0, Empty_Cstring); + end if; + + Res := BuildArrayAlloca + (Builder, Int8Type, Size.LLVM, Empty_Cstring); + Set_Insn_Dbg (Res); + + Res := BuildBitCast + (Builder, Res, Get_LLVM_Type (Rtype), Empty_Cstring); + Set_Insn_Dbg (Res); + end if; + + return O_Enode'(LLVM => Res, Etype => Rtype); + end New_Alloca; + + ------------------- + -- New_Type_Decl -- + ------------------- + + function Add_Dbg_Basic_Type (Id : O_Ident; Btype : O_Tnode; Enc : Natural) + return ValueRef + is + Vals : ValueRefArray (0 .. 9); + begin + Vals := (ConstInt (Int32Type, DW_TAG_Base_Type, 0), + Null_ValueRef, + Null_ValueRef, + MDString (Id), + ConstInt (Int32Type, 0, 0), -- linenum + Dbg_Size (Btype.LLVM), + Dbg_Align (Btype.LLVM), + ConstInt (Int32Type, 0, 0), -- Offset + ConstInt (Int32Type, 0, 0), -- Flags + ConstInt (Int32Type, Unsigned_64 (Enc), 0)); -- Encoding + return MDNode (Vals, Vals'Length); + end Add_Dbg_Basic_Type; + + function Add_Dbg_Enum_Type (Id : O_Ident; Etype : O_Tnode) return ValueRef + is + Vals : ValueRefArray (0 .. 14); + begin + Vals := (ConstInt (Int32Type, DW_TAG_Enumeration_Type, 0), + Dbg_Current_Filedir, + Null_ValueRef, -- context + MDString (Id), + Dbg_Line, + Dbg_Size (Etype.LLVM), + Dbg_Align (Etype.LLVM), + ConstInt (Int32Type, 0, 0), -- Offset + ConstInt (Int32Type, 0, 0), -- Flags + Null_ValueRef, + Get_Value (Enum_Nodes), + ConstInt (Int32Type, 0, 0), + Null_ValueRef, + Null_ValueRef, + Null_ValueRef); -- Runtime lang + Clear (Enum_Nodes); + return MDNode (Vals, Vals'Length); + end Add_Dbg_Enum_Type; + + function Add_Dbg_Pointer_Type (Id : O_Ident; Ptype : O_Tnode) + return ValueRef + is + Vals : ValueRefArray (0 .. 9); + begin + pragma Assert (Ptype.Acc_Type.Dbg /= Null_ValueRef); + + Vals := (ConstInt (Int32Type, DW_TAG_Pointer_Type, 0), + Dbg_Current_Filedir, + Null_ValueRef, -- context + MDString (Id), + Dbg_Line, + Dbg_Size (Ptype.LLVM), + Dbg_Align (Ptype.LLVM), + ConstInt (Int32Type, 0, 0), -- Offset + ConstInt (Int32Type, 1024, 0), -- Flags + Ptype.Acc_Type.Dbg); + return MDNode (Vals, Vals'Length); + end Add_Dbg_Pointer_Type; + + function Add_Dbg_Record_Type (Id : O_Ident; Rtype : O_Tnode) + return ValueRef + is + Vals : ValueRefArray (0 .. 14); + begin + Vals := (ConstInt (Int32Type, DW_TAG_Structure_Type, 0), + Dbg_Current_Filedir, + Null_ValueRef, -- context + MDString (Id), + Dbg_Line, + Null_ValueRef, -- 5: Size + Null_ValueRef, -- 6: Align + ConstInt (Int32Type, 0, 0), -- Offset + ConstInt (Int32Type, 1024, 0), -- Flags + Null_ValueRef, + Null_ValueRef, -- 10 + ConstInt (Int32Type, 0, 0), -- Runtime lang + Null_ValueRef, -- Vtable Holder + Null_ValueRef, -- ? + Null_ValueRef); -- Uniq Id + if Rtype /= O_Tnode_Null then + Vals (5) := Dbg_Size (Rtype.LLVM); + Vals (6) := Dbg_Align (Rtype.LLVM); + Vals (10) := Rtype.Dbg; + end if; + + return MDNode (Vals, Vals'Length); + end Add_Dbg_Record_Type; + + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode) is + begin + case Atype.Kind is + when ON_Incomplete_Record_Type => + Atype.LLVM := + StructCreateNamed (GetGlobalContext, Get_Cstring (Ident)); + when ON_Incomplete_Access_Type => + Atype.LLVM := PointerType + (StructCreateNamed (GetGlobalContext, Get_Cstring (Ident))); + when others => + null; + end case; + + -- Emit debug info + if Flag_Debug then + case Atype.Kind is + when ON_Unsigned_Type => + Atype.Dbg := Add_Dbg_Basic_Type (Ident, Atype, DW_ATE_unsigned); + when ON_Signed_Type => + Atype.Dbg := Add_Dbg_Basic_Type (Ident, Atype, DW_ATE_signed); + when ON_Float_Type => + Atype.Dbg := Add_Dbg_Basic_Type (Ident, Atype, DW_ATE_float); + when ON_Enum_Type => + Atype.Dbg := Add_Dbg_Enum_Type (Ident, Atype); + when ON_Boolean_Type => + Atype.Dbg := Add_Dbg_Enum_Type (Ident, Atype); + when ON_Access_Type => + Atype.Dbg := Add_Dbg_Pointer_Type (Ident, Atype); + when ON_Record_Type => + Atype.Dbg := Add_Dbg_Record_Type (Ident, Atype); + when ON_Incomplete_Record_Type => + Atype.Dbg := Add_Dbg_Record_Type (Ident, O_Tnode_Null); + when ON_Array_Type + | ON_Array_Sub_Type => + -- FIXME: typedef + null; + when ON_Incomplete_Access_Type => + -- FIXME: todo + null; + when ON_Union_Type => + -- FIXME: todo + null; + when ON_No_Type => + raise Program_Error; + end case; + end if; + end New_Type_Decl; + + ----------------------------- + -- New_Debug_Filename_Decl -- + ----------------------------- + + procedure New_Debug_Filename_Decl (Filename : String) is + Vals : ValueRefArray (1 .. 2); + begin + if Flag_Debug then + Vals := (MDString (Filename), + MDString (Current_Directory)); + Dbg_Current_Filedir := MDNode (Vals, 2); + + Vals := (ConstInt (Int32Type, DW_TAG_File_Type, 0), + Dbg_Current_Filedir); + Dbg_Current_File := MDNode (Vals, 2); + end if; + end New_Debug_Filename_Decl; + + ------------------------- + -- New_Debug_Line_Decl -- + ------------------------- + + procedure New_Debug_Line_Decl (Line : Natural) is + begin + Dbg_Current_Line := unsigned (Line); + end New_Debug_Line_Decl; + + ---------------------------- + -- New_Debug_Comment_Decl -- + ---------------------------- + + procedure New_Debug_Comment_Decl (Comment : String) is + begin + null; + end New_Debug_Comment_Decl; + + -------------------- + -- New_Const_Decl -- + -------------------- + + procedure Dbg_Add_Global_Var (Id : O_Ident; + Atype : O_Tnode; + Storage : O_Storage; + Decl : O_Dnode) + is + pragma Assert (Atype.Dbg /= Null_ValueRef); + Vals : ValueRefArray (0 .. 12); + Name : constant ValueRef := MDString (Id); + Is_Local : constant Boolean := Storage = O_Storage_Private; + Is_Def : constant Boolean := Storage /= O_Storage_External; + begin + Vals := + (ConstInt (Int32Type, DW_TAG_Variable, 0), + Null_ValueRef, + Null_ValueRef, -- context + Name, + Name, + Null_ValueRef, -- linkageName + Dbg_Current_File, + Dbg_Line, + Atype.Dbg, + ConstInt (Int1Type, Boolean'Pos (Is_Local), 0), -- isLocal + ConstInt (Int1Type, Boolean'Pos (Is_Def), 0), -- isDef + Decl.LLVM, + Null_ValueRef); + Append (Global_Nodes, MDNode (Vals, Vals'Length)); + end Dbg_Add_Global_Var; + + procedure New_Const_Decl + (Res : out O_Dnode; Ident : O_Ident; Storage : O_Storage; Atype : O_Tnode) + is + Decl : ValueRef; + begin + if Storage = O_Storage_External then + Decl := GetNamedGlobal (Module, Get_Cstring (Ident)); + else + Decl := Null_ValueRef; + end if; + if Decl = Null_ValueRef then + Decl := AddGlobal + (Module, Get_LLVM_Type (Atype), Get_Cstring (Ident)); + end if; + + Res := (Kind => ON_Const_Decl, LLVM => Decl, Dtype => Atype); + SetGlobalConstant (Res.LLVM, 1); + if Storage = O_Storage_Private then + SetLinkage (Res.LLVM, InternalLinkage); + end if; + if Flag_Debug then + Dbg_Add_Global_Var (Ident, Atype, Storage, Res); + end if; + end New_Const_Decl; + + ----------------------- + -- Start_Const_Value -- + ----------------------- + + procedure Start_Const_Value (Const : in out O_Dnode) is + begin + null; + end Start_Const_Value; + + ------------------------ + -- Finish_Const_Value -- + ------------------------ + + procedure Finish_Const_Value (Const : in out O_Dnode; Val : O_Cnode) is + begin + SetInitializer (Const.LLVM, Val.LLVM); + end Finish_Const_Value; + + ------------------ + -- New_Var_Decl -- + ------------------ + + procedure New_Var_Decl + (Res : out O_Dnode; Ident : O_Ident; Storage : O_Storage; Atype : O_Tnode) + is + Decl : ValueRef; + begin + if Storage = O_Storage_Local then + Res := (Kind => ON_Local_Decl, + LLVM => BuildAlloca + (Decl_Builder, Get_LLVM_Type (Atype), Get_Cstring (Ident)), + Dtype => Atype); + if Flag_Debug then + Dbg_Create_Variable (DW_TAG_Auto_Variable, + Ident, Atype, 0, Res.LLVM); + end if; + else + if Storage = O_Storage_External then + Decl := GetNamedGlobal (Module, Get_Cstring (Ident)); + else + Decl := Null_ValueRef; + end if; + if Decl = Null_ValueRef then + Decl := AddGlobal + (Module, Get_LLVM_Type (Atype), Get_Cstring (Ident)); + end if; + + Res := (Kind => ON_Var_Decl, LLVM => Decl, Dtype => Atype); + + -- Set linkage. + case Storage is + when O_Storage_Private => + SetLinkage (Res.LLVM, InternalLinkage); + when O_Storage_Public + | O_Storage_External => + null; + when O_Storage_Local => + raise Program_Error; + end case; + + -- Set initializer. + case Storage is + when O_Storage_Private + | O_Storage_Public => + SetInitializer (Res.LLVM, ConstNull (Get_LLVM_Type (Atype))); + when O_Storage_External => + null; + when O_Storage_Local => + raise Program_Error; + end case; + + if Flag_Debug then + Dbg_Add_Global_Var (Ident, Atype, Storage, Res); + end if; + end if; + end New_Var_Decl; + + ------------------------- + -- Start_Function_Decl -- + ------------------------- + + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode) + is + begin + Interfaces := (Ident => Ident, + Storage => Storage, + Res_Type => Rtype, + Nbr_Inter => 0, + First_Inter => null, + Last_Inter => null); + end Start_Function_Decl; + + -------------------------- + -- Start_Procedure_Decl -- + -------------------------- + + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage) + is + begin + Interfaces := (Ident => Ident, + Storage => Storage, + Res_Type => O_Tnode_Null, + Nbr_Inter => 0, + First_Inter => null, + Last_Inter => null); + end Start_Procedure_Decl; + + ------------------------ + -- New_Interface_Decl -- + ------------------------ + + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode) + is + Inter : constant O_Inter_Acc := new O_Inter'(Itype => Atype, + Ival => Null_ValueRef, + Ident => Ident, + Next => null); + begin + Res := (Kind => ON_Interface_Decl, + Dtype => Atype, + LLVM => Null_ValueRef, + Inter => Inter); + Interfaces.Nbr_Inter := Interfaces.Nbr_Inter + 1; + if Interfaces.First_Inter = null then + Interfaces.First_Inter := Inter; + else + Interfaces.Last_Inter.Next := Inter; + end if; + Interfaces.Last_Inter := Inter; + end New_Interface_Decl; + + ---------------------------- + -- Finish_Subprogram_Decl -- + ---------------------------- + + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode) + is + Count : constant unsigned := unsigned (Interfaces.Nbr_Inter); + Inter : O_Inter_Acc; + Types : TypeRefArray (1 .. Count); + Ftype : TypeRef; + Rtype : TypeRef; + Decl : ValueRef; + Id : constant Cstring := Get_Cstring (Interfaces.Ident); + begin + -- Fill Types (from interfaces list) + Inter := Interfaces.First_Inter; + for I in 1 .. Count loop + Types (I) := Inter.Itype.LLVM; + Inter := Inter.Next; + end loop; + + -- Build function type. + if Interfaces.Res_Type = O_Tnode_Null then + Rtype := VoidType; + else + Rtype := Interfaces.Res_Type.LLVM; + end if; + Ftype := FunctionType (Rtype, Types, Count, 0); + + if Interfaces.Storage = O_Storage_External then + Decl := GetNamedFunction (Module, Id); + else + Decl := Null_ValueRef; + end if; + if Decl = Null_ValueRef then + Decl := AddFunction (Module, Id, Ftype); + end if; + + Res := (Kind => ON_Subprg_Decl, + Dtype => Interfaces.Res_Type, + Subprg_Id => Interfaces.Ident, + Nbr_Args => Count, + Subprg_Inters => Interfaces.First_Inter, + LLVM => Decl); + SetFunctionCallConv (Res.LLVM, CCallConv); + + -- Translate interfaces. + Inter := Interfaces.First_Inter; + for I in 1 .. Count loop + Inter.Ival := GetParam (Res.LLVM, I - 1); + SetValueName (Inter.Ival, Get_Cstring (Inter.Ident)); + Inter := Inter.Next; + end loop; + end Finish_Subprogram_Decl; + + --------------------------- + -- Start_Subprogram_Body -- + --------------------------- + + procedure Start_Subprogram_Body (Func : O_Dnode) + is + -- Basic block at function entry that contains all the declarations. + Decl_BB : BasicBlockRef; + begin + if Cur_Func /= Null_ValueRef then + -- No support for nested subprograms. + raise Program_Error; + end if; + + Cur_Func := Func.LLVM; + Cur_Func_Decl := Func; + Unreach := False; + + Decl_BB := AppendBasicBlock (Cur_Func, Empty_Cstring); + PositionBuilderAtEnd (Decl_Builder, Decl_BB); + + Create_Declare_Block; + + PositionBuilderAtEnd (Builder, Cur_Declare_Block.Stmt_Bb); + + if Flag_Debug then + declare + Type_Vals : ValueRefArray (0 .. Func.Nbr_Args); + Vals : ValueRefArray (0 .. 14); + Arg : O_Inter_Acc; + Subprg_Type : ValueRef; + + Subprg_Vals : ValueRefArray (0 .. 19); + Name : ValueRef; + begin + Arg := Func.Subprg_Inters; + if Func.Dtype /= O_Tnode_Null then + Type_Vals (0) := Func.Dtype.Dbg; + else + -- Void + Type_Vals (0) := Null_ValueRef; + end if; + for I in 1 .. Type_Vals'Last loop + Type_Vals (I) := Arg.Itype.Dbg; + Arg := Arg.Next; + end loop; + Vals := + (ConstInt (Int32Type, DW_TAG_Subroutine_Type, 0), + ConstInt (Int32Type, 0, 0), -- 1 ?? + Null_ValueRef, -- 2 Context + MDString (Empty_Cstring, 0), -- 3 name + ConstInt (Int32Type, 0, 0), -- 4 linenum + ConstInt (Int64Type, 0, 0), -- 5 size + ConstInt (Int64Type, 0, 0), -- 6 align + ConstInt (Int64Type, 0, 0), -- 7 offset + ConstInt (Int32Type, 0, 0), -- 8 flags + Null_ValueRef, -- 9 derived from + MDNode (Type_Vals, Type_Vals'Length), -- 10 type + ConstInt (Int32Type, 0, 0), -- 11 runtime lang + Null_ValueRef, -- 12 containing type + Null_ValueRef, -- 13 template params + Null_ValueRef); -- 14 ?? + Subprg_Type := MDNode (Vals, Vals'Length); + + -- Create TAG_subprogram. + Name := MDString (Func.Subprg_Id); + + Subprg_Vals := + (ConstInt (Int32Type, DW_TAG_Subprogram, 0), + Dbg_Current_Filedir, -- 1 loc + Dbg_Current_File, -- 2 context + Name, -- 3 name + Name, -- 4 display name + Null_ValueRef, -- 5 linkage name + Dbg_Line, -- 6 line num + Subprg_Type, -- 7 type + ConstInt (Int1Type, 0, 0), -- 8 islocal (FIXME) + ConstInt (Int1Type, 1, 0), -- 9 isdef (FIXME) + ConstInt (Int32Type, 0, 0), -- 10 virtuality + ConstInt (Int32Type, 0, 0), -- 11 virtual index + Null_ValueRef, -- 12 containing type + ConstInt (Int32Type, 256, 0), -- 13 flags: prototyped + ConstInt (Int1Type, 0, 0), -- 14 isOpt (FIXME) + Cur_Func, -- 15 function + Null_ValueRef, -- 16 template param + Null_ValueRef, -- 17 function decl + Null_ValueRef, -- 18 variables ??? + Dbg_Line); -- 19 scope ln + Cur_Declare_Block.Dbg_Scope := + MDNode (Subprg_Vals, Subprg_Vals'Length); + Append (Subprg_Nodes, Cur_Declare_Block.Dbg_Scope); + Dbg_Current_Scope := Cur_Declare_Block.Dbg_Scope; + end; + + -- Create local variables for arguments. + declare + Arg : O_Inter_Acc; + Tmp : ValueRef; + St : ValueRef; + pragma Unreferenced (St); + Argno : Natural; + begin + Arg := Func.Subprg_Inters; + Argno := 1; + while Arg /= null loop + Tmp := BuildAlloca (Decl_Builder, Get_LLVM_Type (Arg.Itype), + Empty_Cstring); + Dbg_Create_Variable (DW_TAG_Arg_Variable, + Arg.Ident, Arg.Itype, Argno, Tmp); + St := BuildStore (Decl_Builder, Arg.Ival, Tmp); + Arg.Ival := Tmp; + + Arg := Arg.Next; + Argno := Argno + 1; + end loop; + end; + end if; + end Start_Subprogram_Body; + + ---------------------------- + -- Finish_Subprogram_Body -- + ---------------------------- + + procedure Finish_Subprogram_Body is + Ret : ValueRef; + pragma Unreferenced (Ret); + begin + -- Add a jump from the declare basic block to the first statement BB. + Ret := BuildBr (Decl_Builder, Cur_Declare_Block.Stmt_Bb); + + -- Terminate the statement BB. + if not Unreach then + if Cur_Func_Decl.Dtype = O_Tnode_Null then + Ret := BuildRetVoid (Builder); + else + Ret := BuildUnreachable (Builder); + end if; + end if; + + Destroy_Declare_Block; + + Cur_Func := Null_ValueRef; + Dbg_Current_Scope := Null_ValueRef; + end Finish_Subprogram_Body; + + ------------------------- + -- New_Debug_Line_Stmt -- + ------------------------- + + procedure New_Debug_Line_Stmt (Line : Natural) is + begin + Dbg_Current_Line := unsigned (Line); + end New_Debug_Line_Stmt; + + ---------------------------- + -- New_Debug_Comment_Stmt -- + ---------------------------- + + procedure New_Debug_Comment_Stmt (Comment : String) is + begin + null; + end New_Debug_Comment_Stmt; + + ------------------------ + -- Start_Declare_Stmt -- + ------------------------ + + procedure Start_Declare_Stmt + is + Br : ValueRef; + pragma Unreferenced (Br); + begin + Create_Declare_Block; + + if Unreach then + return; + end if; + + -- Add a jump to the new BB. + Br := BuildBr (Builder, Cur_Declare_Block.Stmt_Bb); + + PositionBuilderAtEnd (Builder, Cur_Declare_Block.Stmt_Bb); + + if Flag_Debug then + declare + Vals : ValueRefArray (0 .. 5); + begin + Vals := + (ConstInt (Int32Type, DW_TAG_Lexical_Block, 0), + Dbg_Current_Filedir, -- 1 loc + Dbg_Current_Scope, -- 2 context + Dbg_Line, -- 3 line num + ConstInt (Int32Type, 0, 0), -- 4 col + ConstInt (Int32Type, Scope_Uniq_Id, 0)); + Cur_Declare_Block.Dbg_Scope := MDNode (Vals, Vals'Length); + Dbg_Current_Scope := Cur_Declare_Block.Dbg_Scope; + Scope_Uniq_Id := Scope_Uniq_Id + 1; + end; + end if; + end Start_Declare_Stmt; + + ------------------------- + -- Finish_Declare_Stmt -- + ------------------------- + + procedure Finish_Declare_Stmt + is + Bb : BasicBlockRef; + Br : ValueRef; + Tmp : ValueRef; + pragma Unreferenced (Br, Tmp); + begin + if not Unreach then + -- Create a basic block for the statements after the declare. + Bb := AppendBasicBlock (Cur_Func, Empty_Cstring); + + if Cur_Declare_Block.Stack_Value /= Null_ValueRef then + -- Restore stack pointer. + Tmp := BuildCall (Builder, Stackrestore_Fun, + (1 .. 1 => Cur_Declare_Block.Stack_Value), 1, + Empty_Cstring); + end if; + + -- Execution will continue on the next statement + Br := BuildBr (Builder, Bb); + + PositionBuilderAtEnd (Builder, Bb); + end if; + + -- Do not reset Unread. + + Destroy_Declare_Block; + + Dbg_Current_Scope := Cur_Declare_Block.Dbg_Scope; + end Finish_Declare_Stmt; + + ----------------------- + -- Start_Association -- + ----------------------- + + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode) + is + begin + Assocs := (Subprg => Subprg, + Idx => 0, + Vals => new ValueRefArray (1 .. Subprg.Nbr_Args)); + end Start_Association; + + --------------------- + -- New_Association -- + --------------------- + + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode) is + begin + Assocs.Idx := Assocs.Idx + 1; + Assocs.Vals (Assocs.Idx) := Val.LLVM; + end New_Association; + + ----------------------- + -- New_Function_Call -- + ----------------------- + + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode + is + Res : ValueRef; + Old_Vals : ValueRefArray_Acc; + begin + Res := BuildCall (Builder, Assocs.Subprg.LLVM, + Assocs.Vals.all, Assocs.Vals'Last, Empty_Cstring); + Old_Vals := Assocs.Vals; + Free (Old_Vals); + Set_Insn_Dbg (Res); + return O_Enode'(LLVM => Res, Etype => Assocs.Subprg.Dtype); + end New_Function_Call; + + ------------------------ + -- New_Procedure_Call -- + ------------------------ + + procedure New_Procedure_Call (Assocs : in out O_Assoc_List) + is + Res : ValueRef; + begin + if not Unreach then + Res := BuildCall (Builder, Assocs.Subprg.LLVM, + Assocs.Vals.all, Assocs.Vals'Last, Empty_Cstring); + Set_Insn_Dbg (Res); + end if; + Free (Assocs.Vals); + end New_Procedure_Call; + + --------------------- + -- New_Assign_Stmt -- + --------------------- + + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode) + is + Res : ValueRef; + begin + if Target.Direct then + raise Program_Error; + end if; + if not Unreach then + Res := BuildStore (Builder, Value.LLVM, Target.LLVM); + Set_Insn_Dbg (Res); + end if; + end New_Assign_Stmt; + + --------------------- + -- New_Return_Stmt -- + --------------------- + + procedure New_Return_Stmt (Value : O_Enode) is + Res : ValueRef; + begin + if Unreach then + return; + end if; + Res := BuildRet (Builder, Value.LLVM); + Set_Insn_Dbg (Res); + Unreach := True; + end New_Return_Stmt; + + --------------------- + -- New_Return_Stmt -- + --------------------- + + procedure New_Return_Stmt is + Res : ValueRef; + begin + if Unreach then + return; + end if; + Res := BuildRetVoid (Builder); + Set_Insn_Dbg (Res); + Unreach := True; + end New_Return_Stmt; + + ------------------- + -- Start_If_Stmt -- + ------------------- + + procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode) is + Res : ValueRef; + Bb_Then : BasicBlockRef; + begin + -- FIXME: check Unreach + Bb_Then := AppendBasicBlock (Cur_Func, Empty_Cstring); + Block := (Bb => AppendBasicBlock (Cur_Func, Empty_Cstring)); + Res := BuildCondBr (Builder, Cond.LLVM, Bb_Then, Block.Bb); + Set_Insn_Dbg (Res); + + PositionBuilderAtEnd (Builder, Bb_Then); + end Start_If_Stmt; + + ------------------- + -- New_Else_Stmt -- + ------------------- + + procedure New_Else_Stmt (Block : in out O_If_Block) is + Res : ValueRef; + pragma Unreferenced (Res); + Bb_Next : BasicBlockRef; + begin + if not Unreach then + Bb_Next := AppendBasicBlock (Cur_Func, Empty_Cstring); + Res := BuildBr (Builder, Bb_Next); + else + Bb_Next := Null_BasicBlockRef; + end if; + + PositionBuilderAtEnd (Builder, Block.Bb); + + Block := (Bb => Bb_Next); + Unreach := False; + end New_Else_Stmt; + + -------------------- + -- Finish_If_Stmt -- + -------------------- + + procedure Finish_If_Stmt (Block : in out O_If_Block) is + Res : ValueRef; + pragma Unreferenced (Res); + Bb_Next : BasicBlockRef; + begin + if not Unreach then + -- The branch can continue. + if Block.Bb = Null_BasicBlockRef then + Bb_Next := AppendBasicBlock (Cur_Func, Empty_Cstring); + else + Bb_Next := Block.Bb; + end if; + Res := BuildBr (Builder, Bb_Next); + PositionBuilderAtEnd (Builder, Bb_Next); + else + -- The branch doesn't continue. + if Block.Bb /= Null_BasicBlockRef then + -- There is a fall-through (either from the then branch, or + -- there is no else). + Unreach := False; + PositionBuilderAtEnd (Builder, Block.Bb); + else + Unreach := True; + end if; + end if; + end Finish_If_Stmt; + + --------------------- + -- Start_Loop_Stmt -- + --------------------- + + procedure Start_Loop_Stmt (Label : out O_Snode) + is + Res : ValueRef; + pragma Unreferenced (Res); + begin + -- FIXME: check Unreach + Label := (Bb_Entry => AppendBasicBlock (Cur_Func, Empty_Cstring), + Bb_Exit => AppendBasicBlock (Cur_Func, Empty_Cstring)); + Res := BuildBr (Builder, Label.Bb_Entry); + PositionBuilderAtEnd (Builder, Label.Bb_Entry); + end Start_Loop_Stmt; + + ---------------------- + -- Finish_Loop_Stmt -- + ---------------------- + + procedure Finish_Loop_Stmt (Label : in out O_Snode) is + Res : ValueRef; + pragma Unreferenced (Res); + begin + if not Unreach then + Res := BuildBr (Builder, Label.Bb_Entry); + end if; + if Label.Bb_Exit /= Null_BasicBlockRef then + -- FIXME: always true... + PositionBuilderAtEnd (Builder, Label.Bb_Exit); + Unreach := False; + else + Unreach := True; + end if; + end Finish_Loop_Stmt; + + ------------------- + -- New_Exit_Stmt -- + ------------------- + + procedure New_Exit_Stmt (L : O_Snode) is + Res : ValueRef; + begin + if not Unreach then + Res := BuildBr (Builder, L.Bb_Exit); + Set_Insn_Dbg (Res); + Unreach := True; + end if; + end New_Exit_Stmt; + + ------------------- + -- New_Next_Stmt -- + ------------------- + + procedure New_Next_Stmt (L : O_Snode) is + Res : ValueRef; + begin + if not Unreach then + Res := BuildBr (Builder, L.Bb_Entry); + Set_Insn_Dbg (Res); + Unreach := True; + end if; + end New_Next_Stmt; + + --------------------- + -- Start_Case_Stmt -- + --------------------- + + procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode) is + begin + Block := (BB_Prev => GetInsertBlock (Builder), + Value => Value.LLVM, + Vtype => Value.Etype, + BB_Next => Null_BasicBlockRef, + BB_Others => Null_BasicBlockRef, + BB_Choice => Null_BasicBlockRef, + Nbr_Choices => 0, + Choices => new O_Choice_Array (1 .. 8)); + end Start_Case_Stmt; + + ------------------ + -- Start_Choice -- + ------------------ + + procedure Finish_Branch (Block : in out O_Case_Block) is + Res : ValueRef; + pragma Unreferenced (Res); + begin + -- Close previous branch. + if not Unreach then + if Block.BB_Next = Null_BasicBlockRef then + Block.BB_Next := AppendBasicBlock (Cur_Func, Empty_Cstring); + end if; + Res := BuildBr (Builder, Block.BB_Next); + end if; + end Finish_Branch; + + procedure Start_Choice (Block : in out O_Case_Block) is + Res : ValueRef; + pragma Unreferenced (Res); + begin + if Block.BB_Choice /= Null_BasicBlockRef then + -- Close previous branch. + Finish_Branch (Block); + end if; + + Unreach := False; + Block.BB_Choice := AppendBasicBlock (Cur_Func, Empty_Cstring); + PositionBuilderAtEnd (Builder, Block.BB_Choice); + end Start_Choice; + + --------------------- + -- New_Expr_Choice -- + --------------------- + + procedure Free is new Ada.Unchecked_Deallocation + (O_Choice_Array, O_Choice_Array_Acc); + + procedure New_Choice (Block : in out O_Case_Block; + Low, High : ValueRef) + is + Choices : O_Choice_Array_Acc; + begin + if Block.Nbr_Choices = Block.Choices'Last then + Choices := new O_Choice_Array (1 .. Block.Choices'Last * 2); + Choices (1 .. Block.Choices'Last) := Block.Choices.all; + Free (Block.Choices); + Block.Choices := Choices; + end if; + Block.Nbr_Choices := Block.Nbr_Choices + 1; + Block.Choices (Block.Nbr_Choices) := (Low => Low, + High => High, + Bb => Block.BB_Choice); + end New_Choice; + + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode) is + begin + New_Choice (Block, Expr.LLVM, Null_ValueRef); + end New_Expr_Choice; + + ---------------------- + -- New_Range_Choice -- + ---------------------- + + procedure New_Range_Choice + (Block : in out O_Case_Block; Low, High : O_Cnode) + is + begin + New_Choice (Block, Low.LLVM, High.LLVM); + end New_Range_Choice; + + ------------------------ + -- New_Default_Choice -- + ------------------------ + + procedure New_Default_Choice (Block : in out O_Case_Block) is + begin + Block.BB_Others := Block.BB_Choice; + end New_Default_Choice; + + ------------------- + -- Finish_Choice -- + ------------------- + + procedure Finish_Choice (Block : in out O_Case_Block) is + begin + null; + end Finish_Choice; + + ---------------------- + -- Finish_Case_Stmt -- + ---------------------- + + procedure Finish_Case_Stmt (Block : in out O_Case_Block) + is + Bb_Default : constant BasicBlockRef := + AppendBasicBlock (Cur_Func, Empty_Cstring); + Bb_Default_Last : BasicBlockRef; + Nbr_Cases : unsigned := 0; + GE, LE : IntPredicate; + Res : ValueRef; + begin + if Block.BB_Choice /= Null_BasicBlockRef then + -- Close previous branch. + Finish_Branch (Block); + end if; + + -- Strategy: use a switch instruction for simple choices, put range + -- choices in the default using if statements. + case Block.Vtype.Kind is + when ON_Unsigned_Type + | ON_Enum_Type + | ON_Boolean_Type => + GE := IntUGE; + LE := IntULE; + when ON_Signed_Type => + GE := IntSGE; + LE := IntSLE; + when others => + raise Program_Error; + end case; + + -- BB for the default case of the LLVM switch. + PositionBuilderAtEnd (Builder, Bb_Default); + Bb_Default_Last := Bb_Default; + + for I in 1 .. Block.Nbr_Choices loop + declare + C : O_Choice_Type renames Block.Choices (I); + begin + if C.High /= Null_ValueRef then + Bb_Default_Last := AppendBasicBlock (Cur_Func, Empty_Cstring); + Res := BuildCondBr (Builder, + BuildAnd (Builder, + BuildICmp (Builder, GE, + Block.Value, C.Low, + Empty_Cstring), + BuildICmp (Builder, LE, + Block.Value, C.High, + Empty_Cstring), + Empty_Cstring), + C.Bb, Bb_Default_Last); + PositionBuilderAtEnd (Builder, Bb_Default_Last); + else + Nbr_Cases := Nbr_Cases + 1; + end if; + end; + end loop; + + -- Insert the switch + PositionBuilderAtEnd (Builder, Block.BB_Prev); + Res := BuildSwitch (Builder, Block.Value, Bb_Default, Nbr_Cases); + for I in 1 .. Block.Nbr_Choices loop + declare + C : O_Choice_Type renames Block.Choices (I); + begin + if C.High = Null_ValueRef then + AddCase (Res, C.Low, C.Bb); + end if; + end; + end loop; + + -- Insert the others. + PositionBuilderAtEnd (Builder, Bb_Default_Last); + if Block.BB_Others /= Null_BasicBlockRef then + Res := BuildBr (Builder, Block.BB_Others); + else + Res := BuildUnreachable (Builder); + end if; + + if Block.BB_Next /= Null_BasicBlockRef then + Unreach := False; + PositionBuilderAtEnd (Builder, Block.BB_Next); + else + Unreach := True; + end if; + + Free (Block.Choices); + end Finish_Case_Stmt; + + function Get_LLVM_Type (Atype : O_Tnode) return TypeRef is + begin + case Atype.Kind is + when ON_Incomplete_Record_Type + | ON_Incomplete_Access_Type => + if Atype.LLVM = Null_TypeRef then + raise Program_Error with "early use of incomplete type"; + end if; + return Atype.LLVM; + when ON_Union_Type + | ON_Scalar_Types + | ON_Access_Type + | ON_Array_Type + | ON_Array_Sub_Type + | ON_Record_Type => + return Atype.LLVM; + when others => + raise Program_Error; + end case; + end Get_LLVM_Type; + + procedure Finish_Debug is + begin + declare + Dbg_Cu : constant String := "llvm.dbg.cu" & ASCII.NUL; + Producer : constant String := "ortho llvm"; + Vals : ValueRefArray (0 .. 12); + begin + Vals := + (ConstInt (Int32Type, DW_TAG_Compile_Unit, 0), + Dbg_Current_Filedir, -- 1 file+dir + ConstInt (Int32Type, 1, 0), -- 2 language (C) + MDString (Producer), -- 3 producer + ConstInt (Int1Type, 0, 0), -- 4 isOpt + MDString (""), -- 5 flags + ConstInt (Int32Type, 0, 0), -- 6 runtime version + Null_ValueRef, -- 7 enum types + Null_ValueRef, -- 8 retained types + Get_Value (Subprg_Nodes), -- 9 subprograms + Get_Value (Global_Nodes), -- 10 global var + Null_ValueRef, -- 11 imported entities + Null_ValueRef); -- 12 split debug + + AddNamedMetadataOperand + (Module, Dbg_Cu'Address, MDNode (Vals, Vals'Length)); + end; + + declare + Module_Flags : constant String := "llvm.module.flags" & ASCII.NUL; + Flags1 : ValueRefArray (0 .. 2); + Flags2 : ValueRefArray (0 .. 2); + begin + Flags1 := (ConstInt (Int32Type, 1, 0), + MDString ("Debug Info Version"), + ConstInt (Int32Type, 1, 0)); + AddNamedMetadataOperand + (Module, Module_Flags'Address, MDNode (Flags1, Flags1'Length)); + Flags2 := (ConstInt (Int32Type, 2, 0), + MDString ("Dwarf Version"), + ConstInt (Int32Type, 2, 0)); + AddNamedMetadataOperand + (Module, Module_Flags'Address, MDNode (Flags2, Flags2'Length)); + end; + end Finish_Debug; + + Dbg_Str : constant String := "dbg"; + + procedure Init is + -- Some predefined types and functions. + I8_Ptr_Type : TypeRef; + begin + Builder := CreateBuilder; + Decl_Builder := CreateBuilder; + Extra_Builder := CreateBuilder; + + -- Create type i8 *. + I8_Ptr_Type := PointerType (Int8Type); + + -- Create intrinsic 'i8 *stacksave (void)'. + Stacksave_Fun := AddFunction + (Module, Stacksave_Name'Address, + FunctionType (I8_Ptr_Type, (1 .. 0 => Null_TypeRef), 0, 0)); + + -- Create intrinsic 'void stackrestore (i8 *)'. + Stackrestore_Fun := AddFunction + (Module, Stackrestore_Name'Address, + FunctionType (VoidType, (1 => I8_Ptr_Type), 1, 0)); + + if Flag_Debug then + Debug_ID := GetMDKindID (Dbg_Str, Dbg_Str'Length); + + declare + Atypes : TypeRefArray (1 .. 2); + Ftype : TypeRef; + Name : String := "llvm.dbg.declare" & ASCII.NUL; + begin + Atypes := (MetadataType, MetadataType); + Ftype := FunctionType (VoidType, Atypes, Atypes'Length, 0); + Llvm_Dbg_Declare := AddFunction (Module, Name'Address, Ftype); + AddFunctionAttr (Llvm_Dbg_Declare, + NoUnwindAttribute + ReadNoneAttribute); + end; + end if; + end Init; + +end Ortho_LLVM; diff --git a/src/ortho/llvm/ortho_llvm.ads b/src/ortho/llvm/ortho_llvm.ads new file mode 100644 index 000000000..8e68eb139 --- /dev/null +++ b/src/ortho/llvm/ortho_llvm.ads @@ -0,0 +1,737 @@ +-- DO NOT MODIFY - this file was generated from: +-- ortho_nodes.common.ads and ortho_llvm.private.ads +-- +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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 Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with Ortho_Ident; use Ortho_Ident; +with LLVM.Core; use LLVM.Core; +with LLVM.TargetMachine; +with LLVM.Target; + +-- Interface to create nodes. +package Ortho_LLVM is + procedure Init; + procedure Finish_Debug; + + -- LLVM specific: the module. + Module : ModuleRef; + + -- Descriptor for the layout. + Target_Data : LLVM.Target.TargetDataRef; + + Target_Machine : LLVM.TargetMachine.TargetMachineRef; + + -- Optimization level + Optimization : LLVM.TargetMachine.CodeGenOptLevel := + LLVM.TargetMachine.CodeGenLevelDefault; + + -- Set by -g to generate debug info. + Flag_Debug : Boolean := False; + +-- Start of common part + + type O_Enode is private; + type O_Cnode is private; + type O_Lnode is private; + type O_Tnode is private; + type O_Snode is private; + type O_Dnode is private; + type O_Fnode is private; + + O_Cnode_Null : constant O_Cnode; + O_Dnode_Null : constant O_Dnode; + O_Enode_Null : constant O_Enode; + O_Fnode_Null : constant O_Fnode; + O_Lnode_Null : constant O_Lnode; + O_Snode_Null : constant O_Snode; + O_Tnode_Null : constant O_Tnode; + + -- True if the code generated supports nested subprograms. + Has_Nested_Subprograms : constant Boolean; + + ------------------------ + -- Type definitions -- + ------------------------ + + type O_Element_List is limited private; + + -- Build a record type. + procedure Start_Record_Type (Elements : out O_Element_List); + -- Add a field in the record; not constrained array are prohibited, since + -- its size is unlimited. + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode); + -- Finish the record type. + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an uncomplete record type: + -- First call NEW_UNCOMPLETE_RECORD_TYPE, which returns a record type. + -- This type can be declared or used to define access types on it. + -- Then, complete (if necessary) the record type, by calling + -- START_UNCOMPLETE_RECORD_TYPE, NEW_RECORD_FIELD and FINISH_RECORD_TYPE. + procedure New_Uncomplete_Record_Type (Res : out O_Tnode); + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List); + + -- Build an union type. + procedure Start_Union_Type (Elements : out O_Element_List); + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode); + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an access type. + -- DTYPE may be O_tnode_null in order to build an incomplete access type. + -- It is completed with finish_access_type. + function New_Access_Type (Dtype : O_Tnode) return O_Tnode; + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode); + + -- Build an array type. + -- The array is not constrained and unidimensional. + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode; + + -- Build a constrained array type. + function New_Constrained_Array_Type (Atype : O_Tnode; Length : O_Cnode) + return O_Tnode; + + -- Build a scalar type; size may be 8, 16, 32 or 64. + function New_Unsigned_Type (Size : Natural) return O_Tnode; + function New_Signed_Type (Size : Natural) return O_Tnode; + + -- Build a float type. + function New_Float_Type return O_Tnode; + + -- Build a boolean type. + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode); + + -- Create an enumeration + type O_Enum_List is limited private; + + -- Elements are declared in order, the first is ordered from 0. + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural); + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; Res : out O_Cnode); + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode); + + ---------------- + -- Literals -- + ---------------- + + -- Create a literal from an integer. + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode; + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode; + + -- Create a null access literal. + function New_Null_Access (Ltype : O_Tnode) return O_Cnode; + + -- Build a record/array aggregate. + -- The aggregate is constant, and therefore can be only used to initialize + -- constant declaration. + -- ATYPE must be either a record type or an array subtype. + -- Elements must be added in the order, and must be literals or aggregates. + type O_Record_Aggr_List is limited private; + type O_Array_Aggr_List is limited private; + + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; + Atype : O_Tnode); + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode); + procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; + Res : out O_Cnode); + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode); + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode); + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode); + + -- Build an union aggregate. + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode; + + -- Returns the size in bytes of ATYPE. The result is a literal of + -- unsigned type RTYPE + -- ATYPE cannot be an unconstrained array type. + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the alignment in bytes for ATYPE. The result is a literal of + -- unsgined type RTYPE. + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the offset of FIELD in its record ATYPE. The result is a + -- literal of unsigned type or access type RTYPE. + function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode; + + -- Get the address of a subprogram. + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Same as New_Address but without any restriction. + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + ------------------- + -- Expressions -- + ------------------- + + type ON_Op_Kind is + ( + -- Not an operation; invalid. + ON_Nil, + + -- Dyadic operations. + ON_Add_Ov, -- ON_Dyadic_Op_Kind + ON_Sub_Ov, -- ON_Dyadic_Op_Kind + ON_Mul_Ov, -- ON_Dyadic_Op_Kind + ON_Div_Ov, -- ON_Dyadic_Op_Kind + ON_Rem_Ov, -- ON_Dyadic_Op_Kind + ON_Mod_Ov, -- ON_Dyadic_Op_Kind + + -- Binary operations. + ON_And, -- ON_Dyadic_Op_Kind + ON_Or, -- ON_Dyadic_Op_Kind + ON_Xor, -- ON_Dyadic_Op_Kind + + -- Monadic operations. + ON_Not, -- ON_Monadic_Op_Kind + ON_Neg_Ov, -- ON_Monadic_Op_Kind + ON_Abs_Ov, -- ON_Monadic_Op_Kind + + -- Comparaisons + ON_Eq, -- ON_Compare_Op_Kind + ON_Neq, -- ON_Compare_Op_Kind + ON_Le, -- ON_Compare_Op_Kind + ON_Lt, -- ON_Compare_Op_Kind + ON_Ge, -- ON_Compare_Op_Kind + ON_Gt -- ON_Compare_Op_Kind + ); + + subtype ON_Dyadic_Op_Kind is ON_Op_Kind range ON_Add_Ov .. ON_Xor; + subtype ON_Monadic_Op_Kind is ON_Op_Kind range ON_Not .. ON_Abs_Ov; + subtype ON_Compare_Op_Kind is ON_Op_Kind range ON_Eq .. ON_Gt; + + type O_Storage is (O_Storage_External, + O_Storage_Public, + O_Storage_Private, + O_Storage_Local); + -- Specifies the storage kind of a declaration. + -- O_STORAGE_EXTERNAL: + -- The declaration do not either reserve memory nor generate code, and + -- is imported either from an other file or from a later place in the + -- current file. + -- O_STORAGE_PUBLIC, O_STORAGE_PRIVATE: + -- The declaration reserves memory or generates code. + -- With O_STORAGE_PUBLIC, the declaration is exported outside of the + -- file while with O_STORAGE_PRIVATE, the declaration is local to the + -- file. + + Type_Error : exception; + Syntax_Error : exception; + + -- Create a value from a literal. + function New_Lit (Lit : O_Cnode) return O_Enode; + + -- Create a dyadic operation. + -- Left and right nodes must have the same type. + -- Binary operation is allowed only on boolean types. + -- The result is of the type of the operands. + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode; + + -- Create a monadic operation. + -- Result is of the type of operand. + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode; + + -- Create a comparaison operator. + -- NTYPE is the type of the result and must be a boolean type. + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) + return O_Enode; + + + type O_Inter_List is limited private; + type O_Assoc_List is limited private; + type O_If_Block is limited private; + type O_Case_Block is limited private; + + + -- 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; + + -- 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; + + -- Get an element of a record. + -- Type of REC must be a record type. + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode; + + -- Reference an access. + -- Type of ACC must be an access type. + function New_Access_Element (Acc : O_Enode) return O_Lnode; + + -- Do a conversion. + -- Allowed conversions are: + -- FIXME: to write. + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode; + + -- Same as New_Address but without any restriction. + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode; + + -- Get the value of an Lvalue. + function New_Value (Lvalue : O_Lnode) return O_Enode; + function New_Obj_Value (Obj : O_Dnode) return O_Enode; + + -- Get an lvalue from a declaration. + function New_Obj (Obj : O_Dnode) return O_Lnode; + + -- Return a pointer of type RTPE to SIZE bytes allocated on the stack. + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode; + + -- Declare a type. + -- This simply gives a name to a type. + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode); + + --------------------- + -- Declarations. -- + --------------------- + + -- Filename of the next declaration. + procedure New_Debug_Filename_Decl (Filename : String); + + -- Line number of the next declaration. + procedure New_Debug_Line_Decl (Line : Natural); + + -- Add a comment in the declarative region. + procedure New_Debug_Comment_Decl (Comment : String); + + -- Declare a constant. + -- This simply gives a name to a constant value or aggregate. + -- A constant cannot be modified and its storage cannot be local. + -- ATYPE must be constrained. + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Set the value of a non-external constant. + procedure Start_Const_Value (Const : in out O_Dnode); + procedure Finish_Const_Value (Const : in out O_Dnode; Val : O_Cnode); + + -- Create a variable declaration. + -- A variable can be local only inside a function. + -- ATYPE must be constrained. + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Start a subprogram declaration. + -- Note: nested subprograms are allowed, ie o_storage_local subprograms can + -- be declared inside a subprograms. It is not allowed to declare + -- o_storage_external subprograms inside a subprograms. + -- Return type and interfaces cannot be a composite type. + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode); + -- For a subprogram without return value. + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage); + + -- Add an interface declaration to INTERFACES. + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode); + -- Finish the function declaration, get the node and a statement list. + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode); + -- Start a subprogram body. + -- Note: the declaration may have an external storage, in this case it + -- becomes public. + procedure Start_Subprogram_Body (Func : O_Dnode); + -- Finish a subprogram body. + procedure Finish_Subprogram_Body; + + + ------------------- + -- Statements. -- + ------------------- + + -- Add a line number as a statement. + procedure New_Debug_Line_Stmt (Line : Natural); + + -- Add a comment as a statement. + procedure New_Debug_Comment_Stmt (Comment : String); + + -- Start a declarative region. + procedure Start_Declare_Stmt; + procedure Finish_Declare_Stmt; + + -- Create a function call or a procedure call. + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode); + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode); + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode; + procedure New_Procedure_Call (Assocs : in out O_Assoc_List); + + -- Assign VALUE to TARGET, type must be the same or compatible. + -- FIXME: what about slice assignment? + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode); + + -- Exit from the subprogram and return VALUE. + procedure New_Return_Stmt (Value : O_Enode); + -- Exit from the subprogram, which doesn't return value. + procedure New_Return_Stmt; + + -- Build an IF statement. + procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode); + procedure New_Else_Stmt (Block : in out O_If_Block); + procedure Finish_If_Stmt (Block : in out O_If_Block); + + -- Create a infinite loop statement. + procedure Start_Loop_Stmt (Label : out O_Snode); + procedure Finish_Loop_Stmt (Label : in out O_Snode); + + -- Exit from a loop stmt or from a for stmt. + procedure New_Exit_Stmt (L : O_Snode); + -- Go to the start of a loop stmt or of a for stmt. + -- Loops/Fors between L and the current points are exited. + procedure New_Next_Stmt (L : O_Snode); + + -- Case statement. + -- VALUE is the selector and must be a discrete type. + procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode); + -- A choice branch is composed of expr, range or default choices. + -- A choice branch is enclosed between a Start_Choice and a Finish_Choice. + -- The statements are after the finish_choice. + procedure Start_Choice (Block : in out O_Case_Block); + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode); + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode); + procedure New_Default_Choice (Block : in out O_Case_Block); + procedure Finish_Choice (Block : in out O_Case_Block); + procedure Finish_Case_Stmt (Block : in out O_Case_Block); + +-- End of common part +private + -- No support for nested subprograms in LLVM. + Has_Nested_Subprograms : constant Boolean := False; + + type O_Tnode_Type (<>); + type O_Tnode is access O_Tnode_Type; + O_Tnode_Null : constant O_Tnode := null; + + type ON_Type_Kind is + (ON_No_Type, + ON_Unsigned_Type, ON_Signed_Type, ON_Enum_Type, ON_Boolean_Type, + ON_Float_Type, + ON_Array_Type, ON_Array_Sub_Type, + ON_Incomplete_Record_Type, + ON_Record_Type, ON_Union_Type, + ON_Incomplete_Access_Type, ON_Access_Type); + + subtype ON_Scalar_Types is ON_Type_Kind range + ON_Unsigned_Type .. ON_Float_Type; + + subtype ON_Integer_Types is ON_Type_Kind range + ON_Unsigned_Type .. ON_Boolean_Type; + + type O_Tnode_Type (Kind : ON_Type_Kind := ON_No_Type) is record + LLVM : TypeRef; + Dbg : ValueRef; + case Kind is + when ON_No_Type => + null; + when ON_Union_Type => + Un_Size : unsigned; + Un_Main_Field : TypeRef; + when ON_Access_Type + | ON_Incomplete_Access_Type => + Acc_Type : O_Tnode; + when ON_Scalar_Types => + Scal_Size : Natural; + when ON_Array_Type + | ON_Array_Sub_Type => + -- Type of the element + Arr_El_Type : O_Tnode; + when ON_Record_Type + | ON_Incomplete_Record_Type => + null; + end case; + end record; + + type O_Inter; + type O_Inter_Acc is access O_Inter; + type O_Inter is record + Itype : O_Tnode; + Ival : ValueRef; + Ident : O_Ident; + Next : O_Inter_Acc; + end record; + + type On_Decl_Kind is + (ON_Type_Decl, ON_Completed_Type_Decl, + ON_Const_Decl, + ON_Var_Decl, ON_Local_Decl, ON_Interface_Decl, + ON_Subprg_Decl, + ON_No_Decl); + + type O_Dnode (Kind : On_Decl_Kind := ON_No_Decl) is record + Dtype : O_Tnode; + LLVM : ValueRef; + case Kind is + when ON_Var_Decl + | ON_Const_Decl + | ON_Local_Decl => + null; + when ON_Subprg_Decl => + Subprg_Id : O_Ident; + Nbr_Args : unsigned; + Subprg_Inters : O_Inter_Acc; + when ON_Interface_Decl => + Inter : O_Inter_Acc; + when others => + null; + end case; + end record; + + O_Dnode_Null : constant O_Dnode := (Kind => ON_No_Decl, + Dtype => O_Tnode_Null, + LLVM => Null_ValueRef); + + type OF_Kind is (OF_None, OF_Record, OF_Union); + type O_Fnode (Kind : OF_Kind := OF_None) is record + Ftype : O_Tnode; + case Kind is + when OF_None => + null; + when OF_Record => + Index : Natural; + when OF_Union => + Utype : TypeRef; + end case; + end record; + + O_Fnode_Null : constant O_Fnode := (Kind => OF_None, + Ftype => O_Tnode_Null); + + type O_Anode_Type; + type O_Anode is access O_Anode_Type; + type O_Anode_Type is record + Next : O_Anode; + Formal : O_Dnode; + Actual : O_Enode; + end record; + + type O_Cnode is record + LLVM : ValueRef; + Ctype : O_Tnode; + end record; + O_Cnode_Null : constant O_Cnode := (LLVM => Null_ValueRef, + Ctype => O_Tnode_Null); + + type O_Enode is record + LLVM : ValueRef; + Etype : O_Tnode; + end record; + O_Enode_Null : constant O_Enode := (LLVM => Null_ValueRef, + Etype => O_Tnode_Null); + + + type O_Lnode is record + -- If True, the LLVM component is the value (used for arguments). + -- If False, the LLVM component is the address of the value (used + -- for everything else). + Direct : Boolean; + LLVM : ValueRef; + Ltype : O_Tnode; + end record; + + O_Lnode_Null : constant O_Lnode := (False, Null_ValueRef, O_Tnode_Null); + + type O_Snode is record + -- First BB in the loop body. + Bb_Entry : BasicBlockRef; + + -- BB after the loop. + Bb_Exit : BasicBlockRef; + end record; + + O_Snode_Null : constant O_Snode := (Null_BasicBlockRef, + Null_BasicBlockRef); + + type O_Inter_List is record + Ident : O_Ident; + Storage : O_Storage; + Res_Type : O_Tnode; + Nbr_Inter : Natural; + First_Inter, Last_Inter : O_Inter_Acc; + end record; + + type O_Element; + type O_Element_Acc is access O_Element; + type O_Element is record + -- Identifier for the element + Ident : O_Ident; + + -- Type of the element + Etype : O_Tnode; + + -- Next element (in the linked list) + Next : O_Element_Acc; + end record; + + -- Record and union builder. + type O_Element_List is record + Nbr_Elements : Natural; + + -- For record: the access to the incomplete (but named) type. + Rec_Type : O_Tnode; + + -- For unions: biggest for size and alignment + Size : unsigned; + Align : Unsigned_32; + Align_Type : TypeRef; + + First_Elem, Last_Elem : O_Element_Acc; + end record; + + type ValueRefArray_Acc is access ValueRefArray; + + type O_Record_Aggr_List is record + -- Current number of elements in Vals. + Len : unsigned; + + -- Value of elements. + Vals : ValueRefArray_Acc; + + -- Type of the aggregate. + Atype : O_Tnode; + end record; + + type O_Array_Aggr_List is record + -- Current number of elements in Vals. + Len : unsigned; + + -- Value of elements. + Vals : ValueRefArray_Acc; + El_Type : TypeRef; + + -- Type of the aggregate. + Atype : O_Tnode; + end record; + + type O_Assoc_List is record + Subprg : O_Dnode; + Idx : unsigned; + Vals : ValueRefArray_Acc; + end record; + + type O_Enum_List is record + LLVM : TypeRef; + Num : Natural; + Etype : O_Tnode; + end record; + + type O_Choice_Type is record + Low, High : ValueRef; + Bb : BasicBlockRef; + end record; + + type O_Choice_Array is array (Natural range <>) of O_Choice_Type; + type O_Choice_Array_Acc is access O_Choice_Array; + + type O_Case_Block is record + -- BB before the case. + BB_Prev : BasicBlockRef; + + -- Select expression + Value : ValueRef; + Vtype : O_Tnode; + + -- BB after the case statement. + BB_Next : BasicBlockRef; + + -- BB for others + BB_Others : BasicBlockRef; + + -- BB for the current choice + BB_Choice : BasicBlockRef; + + -- List of choices. + Nbr_Choices : Natural; + Choices : O_Choice_Array_Acc; + end record; + + type O_If_Block is record + -- The next basic block. + -- After the 'If', this is the BB for the else part. If there is no + -- else part, this is the BB for statements after the if. + -- After the 'else', this is the BB for statements after the if. + Bb : BasicBlockRef; + end record; + + function Get_LLVM_Type (Atype : O_Tnode) return TypeRef; +end Ortho_LLVM; diff --git a/src/ortho/llvm/ortho_llvm.private.ads b/src/ortho/llvm/ortho_llvm.private.ads new file mode 100644 index 000000000..842a119b5 --- /dev/null +++ b/src/ortho/llvm/ortho_llvm.private.ads @@ -0,0 +1,305 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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 Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with Ortho_Ident; use Ortho_Ident; +with LLVM.Core; use LLVM.Core; +with LLVM.TargetMachine; +with LLVM.Target; + +-- Interface to create nodes. +package Ortho_LLVM is + procedure Init; + procedure Finish_Debug; + + -- LLVM specific: the module. + Module : ModuleRef; + + -- Descriptor for the layout. + Target_Data : LLVM.Target.TargetDataRef; + + Target_Machine : LLVM.TargetMachine.TargetMachineRef; + + -- Optimization level + Optimization : LLVM.TargetMachine.CodeGenOptLevel := + LLVM.TargetMachine.CodeGenLevelDefault; + + -- Set by -g to generate debug info. + Flag_Debug : Boolean := False; + +private + -- No support for nested subprograms in LLVM. + Has_Nested_Subprograms : constant Boolean := False; + + type O_Tnode_Type (<>); + type O_Tnode is access O_Tnode_Type; + O_Tnode_Null : constant O_Tnode := null; + + type ON_Type_Kind is + (ON_No_Type, + ON_Unsigned_Type, ON_Signed_Type, ON_Enum_Type, ON_Boolean_Type, + ON_Float_Type, + ON_Array_Type, ON_Array_Sub_Type, + ON_Incomplete_Record_Type, + ON_Record_Type, ON_Union_Type, + ON_Incomplete_Access_Type, ON_Access_Type); + + subtype ON_Scalar_Types is ON_Type_Kind range + ON_Unsigned_Type .. ON_Float_Type; + + subtype ON_Integer_Types is ON_Type_Kind range + ON_Unsigned_Type .. ON_Boolean_Type; + + type O_Tnode_Type (Kind : ON_Type_Kind := ON_No_Type) is record + LLVM : TypeRef; + Dbg : ValueRef; + case Kind is + when ON_No_Type => + null; + when ON_Union_Type => + Un_Size : unsigned; + Un_Main_Field : TypeRef; + when ON_Access_Type + | ON_Incomplete_Access_Type => + Acc_Type : O_Tnode; + when ON_Scalar_Types => + Scal_Size : Natural; + when ON_Array_Type + | ON_Array_Sub_Type => + -- Type of the element + Arr_El_Type : O_Tnode; + when ON_Record_Type + | ON_Incomplete_Record_Type => + null; + end case; + end record; + + type O_Inter; + type O_Inter_Acc is access O_Inter; + type O_Inter is record + Itype : O_Tnode; + Ival : ValueRef; + Ident : O_Ident; + Next : O_Inter_Acc; + end record; + + type On_Decl_Kind is + (ON_Type_Decl, ON_Completed_Type_Decl, + ON_Const_Decl, + ON_Var_Decl, ON_Local_Decl, ON_Interface_Decl, + ON_Subprg_Decl, + ON_No_Decl); + + type O_Dnode (Kind : On_Decl_Kind := ON_No_Decl) is record + Dtype : O_Tnode; + LLVM : ValueRef; + case Kind is + when ON_Var_Decl + | ON_Const_Decl + | ON_Local_Decl => + null; + when ON_Subprg_Decl => + Subprg_Id : O_Ident; + Nbr_Args : unsigned; + Subprg_Inters : O_Inter_Acc; + when ON_Interface_Decl => + Inter : O_Inter_Acc; + when others => + null; + end case; + end record; + + O_Dnode_Null : constant O_Dnode := (Kind => ON_No_Decl, + Dtype => O_Tnode_Null, + LLVM => Null_ValueRef); + + type OF_Kind is (OF_None, OF_Record, OF_Union); + type O_Fnode (Kind : OF_Kind := OF_None) is record + Ftype : O_Tnode; + case Kind is + when OF_None => + null; + when OF_Record => + Index : Natural; + when OF_Union => + Utype : TypeRef; + end case; + end record; + + O_Fnode_Null : constant O_Fnode := (Kind => OF_None, + Ftype => O_Tnode_Null); + + type O_Anode_Type; + type O_Anode is access O_Anode_Type; + type O_Anode_Type is record + Next : O_Anode; + Formal : O_Dnode; + Actual : O_Enode; + end record; + + type O_Cnode is record + LLVM : ValueRef; + Ctype : O_Tnode; + end record; + O_Cnode_Null : constant O_Cnode := (LLVM => Null_ValueRef, + Ctype => O_Tnode_Null); + + type O_Enode is record + LLVM : ValueRef; + Etype : O_Tnode; + end record; + O_Enode_Null : constant O_Enode := (LLVM => Null_ValueRef, + Etype => O_Tnode_Null); + + + type O_Lnode is record + -- If True, the LLVM component is the value (used for arguments). + -- If False, the LLVM component is the address of the value (used + -- for everything else). + Direct : Boolean; + LLVM : ValueRef; + Ltype : O_Tnode; + end record; + + O_Lnode_Null : constant O_Lnode := (False, Null_ValueRef, O_Tnode_Null); + + type O_Snode is record + -- First BB in the loop body. + Bb_Entry : BasicBlockRef; + + -- BB after the loop. + Bb_Exit : BasicBlockRef; + end record; + + O_Snode_Null : constant O_Snode := (Null_BasicBlockRef, + Null_BasicBlockRef); + + type O_Inter_List is record + Ident : O_Ident; + Storage : O_Storage; + Res_Type : O_Tnode; + Nbr_Inter : Natural; + First_Inter, Last_Inter : O_Inter_Acc; + end record; + + type O_Element; + type O_Element_Acc is access O_Element; + type O_Element is record + -- Identifier for the element + Ident : O_Ident; + + -- Type of the element + Etype : O_Tnode; + + -- Next element (in the linked list) + Next : O_Element_Acc; + end record; + + -- Record and union builder. + type O_Element_List is record + Nbr_Elements : Natural; + + -- For record: the access to the incomplete (but named) type. + Rec_Type : O_Tnode; + + -- For unions: biggest for size and alignment + Size : unsigned; + Align : Unsigned_32; + Align_Type : TypeRef; + + First_Elem, Last_Elem : O_Element_Acc; + end record; + + type ValueRefArray_Acc is access ValueRefArray; + + type O_Record_Aggr_List is record + -- Current number of elements in Vals. + Len : unsigned; + + -- Value of elements. + Vals : ValueRefArray_Acc; + + -- Type of the aggregate. + Atype : O_Tnode; + end record; + + type O_Array_Aggr_List is record + -- Current number of elements in Vals. + Len : unsigned; + + -- Value of elements. + Vals : ValueRefArray_Acc; + El_Type : TypeRef; + + -- Type of the aggregate. + Atype : O_Tnode; + end record; + + type O_Assoc_List is record + Subprg : O_Dnode; + Idx : unsigned; + Vals : ValueRefArray_Acc; + end record; + + type O_Enum_List is record + LLVM : TypeRef; + Num : Natural; + Etype : O_Tnode; + end record; + + type O_Choice_Type is record + Low, High : ValueRef; + Bb : BasicBlockRef; + end record; + + type O_Choice_Array is array (Natural range <>) of O_Choice_Type; + type O_Choice_Array_Acc is access O_Choice_Array; + + type O_Case_Block is record + -- BB before the case. + BB_Prev : BasicBlockRef; + + -- Select expression + Value : ValueRef; + Vtype : O_Tnode; + + -- BB after the case statement. + BB_Next : BasicBlockRef; + + -- BB for others + BB_Others : BasicBlockRef; + + -- BB for the current choice + BB_Choice : BasicBlockRef; + + -- List of choices. + Nbr_Choices : Natural; + Choices : O_Choice_Array_Acc; + end record; + + type O_If_Block is record + -- The next basic block. + -- After the 'If', this is the BB for the else part. If there is no + -- else part, this is the BB for statements after the if. + -- After the 'else', this is the BB for statements after the if. + Bb : BasicBlockRef; + end record; + + function Get_LLVM_Type (Atype : O_Tnode) return TypeRef; +end Ortho_LLVM; diff --git a/src/ortho/llvm/ortho_nodes.ads b/src/ortho/llvm/ortho_nodes.ads new file mode 100644 index 000000000..34d1dbbc9 --- /dev/null +++ b/src/ortho/llvm/ortho_nodes.ads @@ -0,0 +1,20 @@ +-- LLVM back-end for ortho. +-- Copyright (C) 2014 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 Ortho_LLVM; +package Ortho_Nodes renames Ortho_LLVM; diff --git a/src/ortho/mcode/Makefile b/src/ortho/mcode/Makefile new file mode 100644 index 000000000..19d5d26aa --- /dev/null +++ b/src/ortho/mcode/Makefile @@ -0,0 +1,37 @@ +ortho_srcdir=.. +GNAT_FLAGS=-gnaty3befhkmr -gnata -gnatf -gnatwlcru -gnat05 +CC=gcc +BE=mcode +SED=sed + +all: $(ortho_exec) + +$(ortho_exec): $(ortho_srcdir)/mcode/ortho_mcode.ads memsegs_c.o force + gnatmake -m -o $@ -g -aI$(ortho_srcdir)/mcode -aI$(ortho_srcdir) \ + $(GNAT_FLAGS) ortho_code_main -bargs -E -largs memsegs_c.o #-static + +memsegs_c.o: $(ortho_srcdir)/mcode/memsegs_c.c + $(CC) -c $(CFLAGS) -o $@ $< + +oread: force + gnatmake -m -o $@ -g $(GNAT_FLAGS) -aI../oread ortho_code_main -aI.. -largs memsegs_c.o + +elfdump: force + gnatmake -m -g $(GNAT_FLAGS) $@ + +coffdump: force + gnatmake -m $(GNAT_FLAGS) $@ + +clean: + $(RM) -f *.o *.ali ortho_code_main elfdump + $(RM) b~*.ad? *~ + +distclean: clean + + +force: + +.PHONY: force all clean + +ORTHO_BASENAME=ortho_mcode +include $(ortho_srcdir)/Makefile.inc diff --git a/src/ortho/mcode/binary_file-coff.adb b/src/ortho/mcode/binary_file-coff.adb new file mode 100644 index 000000000..cf3cba3f4 --- /dev/null +++ b/src/ortho/mcode/binary_file-coff.adb @@ -0,0 +1,407 @@ +-- Binary file COFF writer. +-- 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.Characters.Latin_1; +with Coff; use Coff; + +package body Binary_File.Coff is + NUL : Character renames Ada.Characters.Latin_1.NUL; + + procedure Write_Coff (Fd : GNAT.OS_Lib.File_Descriptor) + is + use GNAT.OS_Lib; + + procedure Xwrite (Data : System.Address; Len : Natural) is + begin + if Write (Fd, Data, Len) /= Len then + raise Write_Error; + end if; + end Xwrite; + + type Section_Info_Type is record + Sect : Section_Acc; + -- File offset for the data. + Data_Offset : Natural; + -- File offset for the relocs. + Reloc_Offset : Natural; + -- Number of relocs to write. + Nbr_Relocs : Natural; + end record; + type Section_Info_Array is array (Natural range <>) of Section_Info_Type; + Sections : Section_Info_Array (1 .. Nbr_Sections + 3); + Nbr_Sect : Natural; + Sect_Text : constant Natural := 1; + Sect_Data : constant Natural := 2; + Sect_Bss : constant Natural := 3; + Sect : Section_Acc; + + --Section_Align : constant Natural := 2; + + Offset : Natural; + Symtab_Offset : Natural; + -- Number of symtab entries. + Nbr_Symbols : Natural; + Strtab_Offset : Natural; + + function Gen_String (Str : String) return Sym_Name + is + Res : Sym_Name; + begin + if Str'Length <= 8 then + Res.E_Name := (others => NUL); + Res.E_Name (1 .. Str'Length) := Str; + else + Res.E := (E_Zeroes => 0, E_Offset => Unsigned_32 (Offset)); + Offset := Offset + Str'Length + 1; + end if; + return Res; + end Gen_String; + + -- Well known sections name. + type String_Array is array (Sect_Text .. Sect_Bss) of String (1 .. 8); + Sect_Name : constant String_Array := + (Sect_Text => ".text" & NUL & NUL & NUL, + Sect_Data => ".data" & NUL & NUL & NUL, + Sect_Bss => ".bss" & NUL & NUL & NUL & NUL); + type Unsigned32_Array is array (Sect_Text .. Sect_Bss) of Unsigned_32; + Sect_Flags : constant Unsigned32_Array := + (Sect_Text => STYP_TEXT, + Sect_Data => STYP_DATA, + Sect_Bss => STYP_BSS); + + -- If true, do local relocs. + Flag_Reloc : constant Boolean := True; + -- If true, discard local symbols; + Flag_Discard_Local : Boolean := True; + begin + -- If relocations are not performs, then local symbols cannot be + -- discarded. + if not Flag_Reloc then + Flag_Discard_Local := False; + end if; + + -- Fill sections. + Sect := Section_Chain; + Nbr_Sect := 3; + declare + N : Natural; + begin + while Sect /= null loop + if Sect.Name.all = ".text" then + N := Sect_Text; + elsif Sect.Name.all = ".data" then + N := Sect_Data; + elsif Sect.Name.all = ".bss" then + N := Sect_Bss; + else + Nbr_Sect := Nbr_Sect + 1; + N := Nbr_Sect; + end if; + Sections (N).Sect := Sect; + Sect.Number := N; + Sect := Sect.Next; + end loop; + end; + + -- Set data offset. + Offset := Filehdr_Size + Nbr_Sect * Scnhdr_Size; + for I in 1 .. Nbr_Sect loop + if Sections (I).Sect /= null + and then Sections (I).Sect.Data /= null + then + Sections (I).Data_Offset := Offset; + Offset := Offset + Natural (Sections (I).Sect.Pc); + else + Sections (I).Data_Offset := 0; + end if; + end loop; + + -- Set relocs offset. + declare + Rel : Reloc_Acc; + begin + for I in 1 .. Nbr_Sect loop + Sections (I).Nbr_Relocs := 0; + if Sections (I).Sect /= null then + Sections (I).Reloc_Offset := Offset; + if not Flag_Reloc then + -- Do local relocations. + Rel := Sections (I).Sect.First_Reloc; + while Rel /= null loop + if S_Local (Rel.Sym) then + if Get_Section (Rel.Sym) = Sections (I).Sect + then + -- Intra section local reloc. + Apply_Reloc (Sections (I).Sect, Rel); + else + -- Inter section local reloc. + -- A relocation is still required. + Sections (I).Nbr_Relocs := + Sections (I).Nbr_Relocs + 1; + -- FIXME: todo. + raise Program_Error; + end if; + else + Sections (I).Nbr_Relocs := Sections (I).Nbr_Relocs + 1; + end if; + Rel := Rel.Sect_Next; + end loop; + else + Sections (I).Nbr_Relocs := Sections (I).Sect.Nbr_Relocs; + end if; + Offset := Offset + Sections (I).Nbr_Relocs * Relsz; + else + Sections (I).Reloc_Offset := 0; + end if; + end loop; + end; + + Symtab_Offset := Offset; + Nbr_Symbols := 2 + Nbr_Sect * 2; -- 2 for file. + for I in Symbols.First .. Symbols.Last loop + Set_Number (I, Nbr_Symbols); + Nbr_Symbols := Nbr_Symbols + 1; + end loop; + Offset := Offset + Nbr_Symbols * Symesz; + Strtab_Offset := Offset; + Offset := Offset + 4; + + -- Write file header. + declare + Hdr : Filehdr; + begin + Hdr.F_Magic := I386magic; + Hdr.F_Nscns := Unsigned_16 (Nbr_Sect); + Hdr.F_Timdat := 0; + Hdr.F_Symptr := Unsigned_32 (Symtab_Offset); + Hdr.F_Nsyms := Unsigned_32 (Nbr_Symbols); + Hdr.F_Opthdr := 0; + Hdr.F_Flags := F_Lnno; + Xwrite (Hdr'Address, Filehdr_Size); + end; + + -- Write sections header. + for I in 1 .. Nbr_Sect loop + declare + Hdr : Scnhdr; + L : Natural; + begin + case I is + when Sect_Text + | Sect_Data + | Sect_Bss => + Hdr.S_Name := Sect_Name (I); + Hdr.S_Flags := Sect_Flags (I); + when others => + Hdr.S_Flags := 0; + L := Sections (I).Sect.Name'Length; + if L > Hdr.S_Name'Length then + Hdr.S_Name := Sections (I).Sect.Name + (Sections (I).Sect.Name'First .. + Sections (I).Sect.Name'First + Hdr.S_Name'Length - 1); + else + Hdr.S_Name (1 .. L) := Sections (I).Sect.Name.all; + Hdr.S_Name (L + 1 .. Hdr.S_Name'Last) := (others => NUL); + end if; + end case; + Hdr.S_Paddr := 0; + Hdr.S_Vaddr := 0; + Hdr.S_Scnptr := Unsigned_32 (Sections (I).Data_Offset); + Hdr.S_Relptr := Unsigned_32 (Sections (I).Reloc_Offset); + Hdr.S_Lnnoptr := 0; + Hdr.S_Nreloc := Unsigned_16 (Sections (I).Nbr_Relocs); + if Sections (I).Sect /= null then + Hdr.S_Size := Unsigned_32 (Sections (I).Sect.Pc); + else + Hdr.S_Size := 0; + end if; + Hdr.S_Nlnno := 0; + Xwrite (Hdr'Address, Scnhdr_Size); + end; + end loop; + + -- Write sections content. + for I in 1 .. Nbr_Sect loop + if Sections (I).Sect /= null + and then Sections (I).Sect.Data /= null + then + Xwrite (Sections (I).Sect.Data (0)'Address, + Natural (Sections (I).Sect.Pc)); + end if; + end loop; + + -- Write sections reloc. + for I in 1 .. Nbr_Sect loop + if Sections (I).Sect /= null then + declare + R : Reloc_Acc; + Rel : Reloc; + begin + R := Sections (I).Sect.First_Reloc; + while R /= null loop + case R.Kind is + when Reloc_32 => + Rel.R_Type := Reloc_Addr32; + when Reloc_Pc32 => + Rel.R_Type := Reloc_Rel32; + when others => + raise Program_Error; + end case; + Rel.R_Vaddr := Unsigned_32 (R.Addr); + Rel.R_Symndx := Unsigned_32 (Get_Number (R.Sym)); + Xwrite (Rel'Address, Relsz); + R := R.Sect_Next; + end loop; + end; + end if; + end loop; + + -- Write symtab. + -- Write file symbol + aux + declare + Sym : Syment; + A_File : Auxent_File; + begin + Sym := (E => (Inline => True, + E_Name => ".file" & NUL & NUL & NUL), + E_Value => 0, + E_Scnum => N_DEBUG, + E_Type => 0, + E_Sclass => C_FILE, + E_Numaux => 1); + Xwrite (Sym'Address, Symesz); + A_File := (Inline => True, + X_Fname => "testfile.xxxxx"); + Xwrite (A_File'Address, Symesz); + end; + -- Write sections symbol + aux + for I in 1 .. Nbr_Sect loop + declare + A_Scn : Auxent_Scn; + Sym : Syment; + begin + Sym := (E => (Inline => True, E_Name => (others => NUL)), + E_Value => 0, + E_Scnum => Unsigned_16 (I), + E_Type => 0, + E_Sclass => C_STAT, + E_Numaux => 1); + if I <= Sect_Bss then + Sym.E.E_Name := Sect_Name (I); + else + Sym.E := Gen_String (Sections (I).Sect.Name.all); + end if; + Xwrite (Sym'Address, Symesz); + if Sections (I).Sect /= null + and then Sections (I).Sect.Data /= null + then + A_Scn := + (X_Scnlen => Unsigned_32 (Sections (I).Sect.Pc), + X_Nreloc => Unsigned_16 (Sections (I).Nbr_Relocs), + X_Nlinno => 0); + else + A_Scn := (X_Scnlen => 0, X_Nreloc => 0, X_Nlinno => 0); + end if; + Xwrite (A_Scn'Address, Symesz); + end; + end loop; + + -- Write symbols. + declare + procedure Write_Symbol (S : Symbol) + is + Sym : Syment; + begin + Sym := (E => Gen_String (Get_Symbol_Name (S)), + E_Value => Unsigned_32 (Get_Symbol_Value (S)), + E_Scnum => 0, + E_Type => 0, + E_Sclass => C_EXT, + E_Numaux => 0); + case Get_Scope (S) is + when Sym_Local + | Sym_Private => + Sym.E_Sclass := C_STAT; + when Sym_Undef + | Sym_Global => + Sym.E_Sclass := C_EXT; + end case; + if Get_Section (S) /= null then + Sym.E_Scnum := Unsigned_16 (Get_Section (S).Number); + end if; + Xwrite (Sym'Address, Symesz); + end Write_Symbol; + begin + -- First the non-local symbols (1). + for I in Symbols.First .. Symbols.Last loop + if Get_Scope (I) in Symbol_Scope_External then + Write_Symbol (I); + end if; + end loop; + -- Then the local symbols (2). + if not Flag_Discard_Local then + for I in Symbols.First .. Symbols.Last loop + if Get_Scope (I) not in Symbol_Scope_External then + Write_Symbol (I); + end if; + end loop; + end if; + end; + + -- Write strtab. + -- Write strtab length. + declare + L : Unsigned_32; + + procedure Write_String (Str : String) is + begin + if Str (Str'Last) /= NUL then + raise Program_Error; + end if; + if Str'Length <= 9 then + return; + end if; + Xwrite (Str'Address, Str'Length); + Strtab_Offset := Strtab_Offset + Str'Length; + end Write_String; + begin + L := Unsigned_32 (Offset - Strtab_Offset); + Xwrite (L'Address, 4); + + -- Write section name string. + for I in Sect_Bss + 1 .. Nbr_Sect loop + if Sections (I).Sect /= null + and then Sections (I).Sect.Name'Length > 8 + then + Write_String (Sections (I).Sect.Name.all & NUL); + end if; + end loop; + + for I in Symbols.First .. Symbols.Last loop + declare + Str : constant String := Get_Symbol_Name (I); + begin + Write_String (Str & NUL); + end; + end loop; + if Strtab_Offset + 4 /= Offset then + raise Program_Error; + end if; + end; + end Write_Coff; + +end Binary_File.Coff; diff --git a/src/ortho/mcode/binary_file-coff.ads b/src/ortho/mcode/binary_file-coff.ads new file mode 100644 index 000000000..e671555ea --- /dev/null +++ b/src/ortho/mcode/binary_file-coff.ads @@ -0,0 +1,23 @@ +-- Binary file COFF writer. +-- 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 GNAT.OS_Lib; + +package Binary_File.Coff is + procedure Write_Coff (Fd : GNAT.OS_Lib.File_Descriptor); +end Binary_File.Coff; + diff --git a/src/ortho/mcode/binary_file-elf.adb b/src/ortho/mcode/binary_file-elf.adb new file mode 100644 index 000000000..329dbacd3 --- /dev/null +++ b/src/ortho/mcode/binary_file-elf.adb @@ -0,0 +1,679 @@ +-- Binary file ELF writer. +-- 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; use Ada.Text_IO; +with Ada.Characters.Latin_1; +with Elf_Common; +with Elf32; + +package body Binary_File.Elf is + NUL : Character renames Ada.Characters.Latin_1.NUL; + + type Arch_Bool is array (Arch_Kind) of Boolean; + Is_Rela : constant Arch_Bool := (Arch_Unknown => False, + Arch_X86 => False, + Arch_Sparc => True, + Arch_Ppc => True); + + procedure Write_Elf (Fd : GNAT.OS_Lib.File_Descriptor) + is + use Elf_Common; + use Elf32; + use GNAT.OS_Lib; + + procedure Xwrite (Data : System.Address; Len : Natural) is + begin + if Write (Fd, Data, Len) /= Len then + raise Write_Error; + end if; + end Xwrite; + + procedure Check_File_Pos (Off : Elf32_Off) + is + L : Long_Integer; + begin + L := File_Length (Fd); + if L /= Long_Integer (Off) then + Put_Line (Standard_Error, "check_file_pos error: expect " + & Elf32_Off'Image (Off) & ", found " + & Long_Integer'Image (L)); + raise Write_Error; + end if; + end Check_File_Pos; + + function Sect_Align (V : Elf32_Off) return Elf32_Off + is + Tmp : Elf32_Off; + begin + Tmp := V + 2 ** 2 - 1; + return Tmp - (Tmp mod 2 ** 2); + end Sect_Align; + + type Section_Info_Type is record + Sect : Section_Acc; + -- Index of the section symbol (in symtab). + Sym : Elf32_Word; + -- Number of relocs to write. + --Nbr_Relocs : Natural; + end record; + type Section_Info_Array is array (Natural range <>) of Section_Info_Type; + Sections : Section_Info_Array (0 .. 3 + 2 * Nbr_Sections); + type Elf32_Shdr_Array is array (Natural range <>) of Elf32_Shdr; + Shdr : Elf32_Shdr_Array (0 .. 3 + 2 * Nbr_Sections); + Nbr_Sect : Natural; + Sect : Section_Acc; + + -- The first 4 sections are always present. + Sect_Null : constant Natural := 0; + Sect_Shstrtab : constant Natural := 1; + Sect_Symtab : constant Natural := 2; + Sect_Strtab : constant Natural := 3; + Sect_First : constant Natural := 4; + + Offset : Elf32_Off; + + -- Size of a relocation entry. + Rel_Size : Natural; + + -- If true, do local relocs. + Flag_Reloc : constant Boolean := True; + -- If true, discard local symbols; + Flag_Discard_Local : Boolean := True; + + -- Number of symbols. + Nbr_Symbols : Natural := 0; + begin + -- If relocations are not performs, then local symbols cannot be + -- discarded. + if not Flag_Reloc then + Flag_Discard_Local := False; + end if; + + -- Set size of a relocation entry. This avoids severals conditionnal. + if Is_Rela (Arch) then + Rel_Size := Elf32_Rela_Size; + else + Rel_Size := Elf32_Rel_Size; + end if; + + -- Set section header. + + -- SHT_NULL. + Shdr (Sect_Null) := + Elf32_Shdr'(Sh_Name => 0, + Sh_Type => SHT_NULL, + Sh_Flags => 0, + Sh_Addr => 0, + Sh_Offset => 0, + Sh_Size => 0, + Sh_Link => 0, + Sh_Info => 0, + Sh_Addralign => 0, + Sh_Entsize => 0); + + -- shstrtab. + Shdr (Sect_Shstrtab) := + Elf32_Shdr'(Sh_Name => 1, + Sh_Type => SHT_STRTAB, + Sh_Flags => 0, + Sh_Addr => 0, + Sh_Offset => 0, -- Filled latter. + -- NUL: 1, .symtab: 8, .strtab: 8 and .shstrtab: 10. + Sh_Size => 1 + 10 + 8 + 8, + Sh_Link => 0, + Sh_Info => 0, + Sh_Addralign => 1, + Sh_Entsize => 0); + + -- Symtab + Shdr (Sect_Symtab) := + Elf32_Shdr'(Sh_Name => 11, + Sh_Type => SHT_SYMTAB, + Sh_Flags => 0, + Sh_Addr => 0, + Sh_Offset => 0, + Sh_Size => 0, + Sh_Link => Elf32_Word (Sect_Strtab), + Sh_Info => 0, -- FIXME + Sh_Addralign => 4, + Sh_Entsize => Elf32_Word (Elf32_Sym_Size)); + + -- strtab. + Shdr (Sect_Strtab) := + Elf32_Shdr'(Sh_Name => 19, + Sh_Type => SHT_STRTAB, + Sh_Flags => 0, + Sh_Addr => 0, + Sh_Offset => 0, + Sh_Size => 0, + Sh_Link => 0, + Sh_Info => 0, + Sh_Addralign => 1, + Sh_Entsize => 0); + + -- Fill sections. + Sect := Section_Chain; + Nbr_Sect := Sect_First; + Nbr_Symbols := 1; + while Sect /= null loop + Sections (Nbr_Sect) := (Sect => Sect, + Sym => Elf32_Word (Nbr_Symbols)); + Nbr_Symbols := Nbr_Symbols + 1; + Sect.Number := Nbr_Sect; + + Shdr (Nbr_Sect) := + Elf32_Shdr'(Sh_Name => Shdr (Sect_Shstrtab).Sh_Size, + Sh_Type => SHT_PROGBITS, + Sh_Flags => 0, + Sh_Addr => Elf32_Addr (Sect.Vaddr), + Sh_Offset => 0, + Sh_Size => 0, + Sh_Link => 0, + Sh_Info => 0, + Sh_Addralign => 2 ** Sect.Align, + Sh_Entsize => Elf32_Word (Sect.Esize)); + if Sect.Data = null then + Shdr (Nbr_Sect).Sh_Type := SHT_NOBITS; + end if; + if (Sect.Flags and Section_Read) /= 0 then + Shdr (Nbr_Sect).Sh_Flags := + Shdr (Nbr_Sect).Sh_Flags or SHF_ALLOC; + end if; + if (Sect.Flags and Section_Exec) /= 0 then + Shdr (Nbr_Sect).Sh_Flags := + Shdr (Nbr_Sect).Sh_Flags or SHF_EXECINSTR; + end if; + if (Sect.Flags and Section_Write) /= 0 then + Shdr (Nbr_Sect).Sh_Flags := + Shdr (Nbr_Sect).Sh_Flags or SHF_WRITE; + end if; + if Sect.Flags = Section_Strtab then + Shdr (Nbr_Sect).Sh_Type := SHT_STRTAB; + Shdr (Nbr_Sect).Sh_Addralign := 1; + Shdr (Nbr_Sect).Sh_Entsize := 0; + end if; + + Shdr (Sect_Shstrtab).Sh_Size := Shdr (Sect_Shstrtab).Sh_Size + + Sect.Name'Length + 1; -- 1 for Nul. + + Nbr_Sect := Nbr_Sect + 1; + if Flag_Reloc then + if Sect.First_Reloc /= null then + Do_Intra_Section_Reloc (Sect); + end if; + end if; + if Sect.First_Reloc /= null then + -- Add a section for the relocs. + Shdr (Nbr_Sect) := Elf32_Shdr' + (Sh_Name => Shdr (Sect_Shstrtab).Sh_Size, + Sh_Type => SHT_NULL, + Sh_Flags => 0, + Sh_Addr => 0, + Sh_Offset => 0, + Sh_Size => 0, + Sh_Link => Elf32_Word (Sect_Symtab), + Sh_Info => Elf32_Word (Nbr_Sect - 1), + Sh_Addralign => 4, + Sh_Entsize => Elf32_Word (Rel_Size)); + + if Is_Rela (Arch) then + Shdr (Nbr_Sect).Sh_Type := SHT_RELA; + else + Shdr (Nbr_Sect).Sh_Type := SHT_REL; + end if; + Shdr (Sect_Shstrtab).Sh_Size := Shdr (Sect_Shstrtab).Sh_Size + + Sect.Name'Length + 4 -- 4 for ".rel" + + Boolean'Pos (Is_Rela (Arch)) + 1; -- 1 for 'a', 1 for Nul. + + Nbr_Sect := Nbr_Sect + 1; + end if; + Sect := Sect.Next; + end loop; + + -- Lay-out sections. + Offset := Elf32_Off (Elf32_Ehdr_Size); + + -- Section table + Offset := Offset + Elf32_Off (Nbr_Sect * Elf32_Shdr_Size); + + -- shstrtab. + Shdr (Sect_Shstrtab).Sh_Offset := Offset; + + Offset := Sect_Align (Offset + Shdr (Sect_Shstrtab).Sh_Size); + + -- user-sections and relocation. + for I in Sect_First .. Nbr_Sect - 1 loop + Sect := Sections (I).Sect; + if Sect /= null then + Sect.Pc := Pow_Align (Sect.Pc, Sect.Align); + Shdr (Sect.Number).Sh_Size := Elf32_Word (Sect.Pc); + if Sect.Data /= null then + -- Set data offset. + Shdr (Sect.Number).Sh_Offset := Offset; + Offset := Offset + Shdr (Sect.Number).Sh_Size; + + -- Set relocs offset. + if Sect.First_Reloc /= null then + Shdr (Sect.Number + 1).Sh_Offset := Offset; + Shdr (Sect.Number + 1).Sh_Size := + Elf32_Word (Sect.Nbr_Relocs * Rel_Size); + Offset := Offset + Shdr (Sect.Number + 1).Sh_Size; + end if; + end if; + -- Set link. + if Sect.Link /= null then + Shdr (Sect.Number).Sh_Link := Elf32_Word (Sect.Link.Number); + end if; + end if; + end loop; + + -- Number symbols, put local before globals. + Nbr_Symbols := 1 + Nbr_Sections; + + -- First local symbols. + for I in Symbols.First .. Symbols.Last loop + case Get_Scope (I) is + when Sym_Private => + Set_Number (I, Nbr_Symbols); + Nbr_Symbols := Nbr_Symbols + 1; + when Sym_Local => + if not Flag_Discard_Local then + Set_Number (I, Nbr_Symbols); + Nbr_Symbols := Nbr_Symbols + 1; + end if; + when Sym_Undef + | Sym_Global => + null; + end case; + end loop; + + Shdr (Sect_Symtab).Sh_Info := Elf32_Word (Nbr_Symbols); + + -- Then globals. + for I in Symbols.First .. Symbols.Last loop + case Get_Scope (I) is + when Sym_Private + | Sym_Local => + null; + when Sym_Undef => + if Get_Used (I) then + Set_Number (I, Nbr_Symbols); + Nbr_Symbols := Nbr_Symbols + 1; + end if; + when Sym_Global => + Set_Number (I, Nbr_Symbols); + Nbr_Symbols := Nbr_Symbols + 1; + end case; + end loop; + + -- Symtab. + Shdr (Sect_Symtab).Sh_Offset := Offset; + -- 1 for nul. + Shdr (Sect_Symtab).Sh_Size := Elf32_Word (Nbr_Symbols * Elf32_Sym_Size); + + Offset := Offset + Shdr (Sect_Symtab).Sh_Size; + + -- Strtab offset. + Shdr (Sect_Strtab).Sh_Offset := Offset; + Shdr (Sect_Strtab).Sh_Size := 1; + + -- Compute length of strtab. + -- First, sections names. + Sect := Section_Chain; +-- while Sect /= null loop +-- Shdr (Sect_Strtab).Sh_Size := +-- Shdr (Sect_Strtab).Sh_Size + Sect.Name'Length + 1; +-- Sect := Sect.Prev; +-- end loop; + -- Then symbols. + declare + Len : Natural; + L : Natural; + begin + Len := 0; + for I in Symbols.First .. Symbols.Last loop + L := Get_Symbol_Name_Length (I) + 1; + case Get_Scope (I) is + when Sym_Local => + if Flag_Discard_Local then + L := 0; + end if; + when Sym_Private => + null; + when Sym_Global => + null; + when Sym_Undef => + if not Get_Used (I) then + L := 0; + end if; + end case; + Len := Len + L; + end loop; + + Shdr (Sect_Strtab).Sh_Size := + Shdr (Sect_Strtab).Sh_Size + Elf32_Word (Len); + end; + + -- Write file header. + declare + Ehdr : Elf32_Ehdr; + begin + Ehdr := (E_Ident => (EI_MAG0 => ELFMAG0, + EI_MAG1 => ELFMAG1, + EI_MAG2 => ELFMAG2, + EI_MAG3 => ELFMAG3, + EI_CLASS => ELFCLASS32, + EI_DATA => ELFDATANONE, + EI_VERSION => EV_CURRENT, + EI_PAD .. 15 => 0), + E_Type => ET_REL, + E_Machine => EM_NONE, + E_Version => Elf32_Word (EV_CURRENT), + E_Entry => 0, + E_Phoff => 0, + E_Shoff => Elf32_Off (Elf32_Ehdr_Size), + E_Flags => 0, + E_Ehsize => Elf32_Half (Elf32_Ehdr_Size), + E_Phentsize => 0, + E_Phnum => 0, + E_Shentsize => Elf32_Half (Elf32_Shdr_Size), + E_Shnum => Elf32_Half (Nbr_Sect), + E_Shstrndx => 1); + case Arch is + when Arch_X86 => + Ehdr.E_Ident (EI_DATA) := ELFDATA2LSB; + Ehdr.E_Machine := EM_386; + when Arch_Sparc => + Ehdr.E_Ident (EI_DATA) := ELFDATA2MSB; + Ehdr.E_Machine := EM_SPARC; + when others => + raise Program_Error; + end case; + Xwrite (Ehdr'Address, Elf32_Ehdr_Size); + end; + + -- Write shdr. + Xwrite (Shdr'Address, Nbr_Sect * Elf32_Shdr_Size); + + -- Write shstrtab + Check_File_Pos (Shdr (Sect_Shstrtab).Sh_Offset); + declare + Str : String := + NUL & ".shstrtab" & NUL & ".symtab" & NUL & ".strtab" & NUL; + Rela : String := NUL & ".rela"; + begin + Xwrite (Str'Address, Str'Length); + Sect := Section_Chain; + while Sect /= null loop + Xwrite (Sect.Name.all'Address, Sect.Name'Length); + if Sect.First_Reloc /= null then + if Is_Rela (Arch) then + Xwrite (Rela'Address, Rela'Length); + else + Xwrite (Rela'Address, Rela'Length - 1); + end if; + Xwrite (Sect.Name.all'Address, Sect.Name'Length); + end if; + Xwrite (NUL'Address, 1); + Sect := Sect.Next; + end loop; + end; + -- Pad. + declare + Delt : Elf32_Word; + Nul_Str : String (1 .. 4) := (others => NUL); + begin + Delt := Shdr (Sect_Shstrtab).Sh_Size and 3; + if Delt /= 0 then + Xwrite (Nul_Str'Address, Natural (4 - Delt)); + end if; + end; + + -- Write sections content and reloc. + for I in 1 .. Nbr_Sect loop + Sect := Sections (I).Sect; + if Sect /= null then + if Sect.Data /= null then + Check_File_Pos (Shdr (Sect.Number).Sh_Offset); + Xwrite (Sect.Data (0)'Address, Natural (Sect.Pc)); + end if; + declare + R : Reloc_Acc; + Rel : Elf32_Rel; + Rela : Elf32_Rela; + S : Elf32_Word; + Nbr_Reloc : Natural; + begin + R := Sect.First_Reloc; + Nbr_Reloc := 0; + while R /= null loop + if R.Done then + S := Sections (Get_Section (R.Sym).Number).Sym; + else + S := Elf32_Word (Get_Number (R.Sym)); + end if; + + if Is_Rela (Arch) then + case R.Kind is + when Reloc_Disp22 => + Rela.R_Info := Elf32_R_Info (S, R_SPARC_WDISP22); + when Reloc_Disp30 => + Rela.R_Info := Elf32_R_Info (S, R_SPARC_WDISP30); + when Reloc_Hi22 => + Rela.R_Info := Elf32_R_Info (S, R_SPARC_HI22); + when Reloc_Lo10 => + Rela.R_Info := Elf32_R_Info (S, R_SPARC_LO10); + when Reloc_32 => + Rela.R_Info := Elf32_R_Info (S, R_SPARC_32); + when Reloc_Ua_32 => + Rela.R_Info := Elf32_R_Info (S, R_SPARC_UA32); + when others => + raise Program_Error; + end case; + Rela.R_Addend := 0; + Rela.R_Offset := Elf32_Addr (R.Addr); + Xwrite (Rela'Address, Elf32_Rela_Size); + else + case R.Kind is + when Reloc_32 => + Rel.R_Info := Elf32_R_Info (S, R_386_32); + when Reloc_Pc32 => + Rel.R_Info := Elf32_R_Info (S, R_386_PC32); + when others => + raise Program_Error; + end case; + Rel.R_Offset := Elf32_Addr (R.Addr); + Xwrite (Rel'Address, Elf32_Rel_Size); + end if; + Nbr_Reloc := Nbr_Reloc + 1; + R := R.Sect_Next; + end loop; + if Nbr_Reloc /= Sect.Nbr_Relocs then + raise Program_Error; + end if; + end; + end if; + end loop; + + -- Write symbol table. + Check_File_Pos (Shdr (Sect_Symtab).Sh_Offset); + declare + Str_Off : Elf32_Word; + + procedure Gen_Sym (S : Symbol) + is + Sym : Elf32_Sym; + Bind : Elf32_Uchar; + Typ : Elf32_Uchar; + begin + Sym := Elf32_Sym'(St_Name => Str_Off, + St_Value => Elf32_Addr (Get_Symbol_Value (S)), + St_Size => 0, + St_Info => 0, + St_Other => 0, + St_Shndx => SHN_UNDEF); + if Get_Section (S) /= null then + Sym.St_Shndx := Elf32_Half (Get_Section (S).Number); + end if; + case Get_Scope (S) is + when Sym_Private + | Sym_Local => + Bind := STB_LOCAL; + Typ := STT_NOTYPE; + when Sym_Global => + Bind := STB_GLOBAL; + if Get_Section (S) /= null + and then (Get_Section (S).Flags and Section_Exec) /= 0 + then + Typ := STT_FUNC; + else + Typ := STT_OBJECT; + end if; + when Sym_Undef => + Bind := STB_GLOBAL; + Typ := STT_NOTYPE; + end case; + Sym.St_Info := Elf32_St_Info (Bind, Typ); + + Xwrite (Sym'Address, Elf32_Sym_Size); + + Str_Off := Str_Off + Elf32_Off (Get_Symbol_Name_Length (S) + 1); + end Gen_Sym; + + Sym : Elf32_Sym; + begin + + Str_Off := 1; + + -- write null entry + Sym := Elf32_Sym'(St_Name => 0, + St_Value => 0, + St_Size => 0, + St_Info => 0, + St_Other => 0, + St_Shndx => SHN_UNDEF); + Xwrite (Sym'Address, Elf32_Sym_Size); + + -- write section entries + Sect := Section_Chain; + while Sect /= null loop +-- Sym := Elf32_Sym'(St_Name => Str_Off, +-- St_Value => 0, +-- St_Size => 0, +-- St_Info => Elf32_St_Info (STB_LOCAL, +-- STT_NOTYPE), +-- St_Other => 0, +-- St_Shndx => Elf32_Half (Sect.Number)); +-- Xwrite (Sym'Address, Elf32_Sym_Size); +-- Str_Off := Str_Off + Sect.Name'Length + 1; + + Sym := Elf32_Sym'(St_Name => 0, + St_Value => 0, + St_Size => 0, + St_Info => Elf32_St_Info (STB_LOCAL, + STT_SECTION), + St_Other => 0, + St_Shndx => Elf32_Half (Sect.Number)); + Xwrite (Sym'Address, Elf32_Sym_Size); + Sect := Sect.Next; + end loop; + + -- First local symbols. + for I in Symbols.First .. Symbols.Last loop + case Get_Scope (I) is + when Sym_Private => + Gen_Sym (I); + when Sym_Local => + if not Flag_Discard_Local then + Gen_Sym (I); + end if; + when Sym_Global + | Sym_Undef => + null; + end case; + end loop; + + -- Then global symbols. + for I in Symbols.First .. Symbols.Last loop + case Get_Scope (I) is + when Sym_Global => + Gen_Sym (I); + when Sym_Undef => + if Get_Used (I) then + Gen_Sym (I); + end if; + when Sym_Private + | Sym_Local => + null; + end case; + end loop; + end; + + -- Write strtab. + Check_File_Pos (Shdr (Sect_Strtab).Sh_Offset); + -- First is NUL. + Xwrite (NUL'Address, 1); + -- Then the sections name. +-- Sect := Section_List; +-- while Sect /= null loop +-- Xwrite (Sect.Name.all'Address, Sect.Name'Length); +-- Xwrite (NUL'Address, 1); +-- Sect := Sect.Prev; +-- end loop; + + -- Then the symbols name. + declare + procedure Write_Sym_Name (S : Symbol) + is + Str : String := Get_Symbol_Name (S) & NUL; + begin + Xwrite (Str'Address, Str'Length); + end Write_Sym_Name; + begin + -- First locals. + for I in Symbols.First .. Symbols.Last loop + case Get_Scope (I) is + when Sym_Private => + Write_Sym_Name (I); + when Sym_Local => + if not Flag_Discard_Local then + Write_Sym_Name (I); + end if; + when Sym_Global + | Sym_Undef => + null; + end case; + end loop; + + -- Then global symbols. + for I in Symbols.First .. Symbols.Last loop + case Get_Scope (I) is + when Sym_Global => + Write_Sym_Name (I); + when Sym_Undef => + if Get_Used (I) then + Write_Sym_Name (I); + end if; + when Sym_Private + | Sym_Local => + null; + end case; + end loop; + end; + end Write_Elf; + +end Binary_File.Elf; diff --git a/src/ortho/mcode/binary_file-elf.ads b/src/ortho/mcode/binary_file-elf.ads new file mode 100644 index 000000000..e0d3a4d2a --- /dev/null +++ b/src/ortho/mcode/binary_file-elf.ads @@ -0,0 +1,22 @@ +-- Binary file ELF writer. +-- 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 GNAT.OS_Lib; + +package Binary_File.Elf is + procedure Write_Elf (Fd : GNAT.OS_Lib.File_Descriptor); +end Binary_File.Elf; diff --git a/src/ortho/mcode/binary_file-memory.adb b/src/ortho/mcode/binary_file-memory.adb new file mode 100644 index 000000000..a37af9cb7 --- /dev/null +++ b/src/ortho/mcode/binary_file-memory.adb @@ -0,0 +1,101 @@ +-- Binary file execute in memory handler. +-- 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; use Ada.Text_IO; +with Ada.Unchecked_Conversion; + +package body Binary_File.Memory is + -- Absolute section. + Sect_Abs : Section_Acc; + + function To_Pc_Type is new Ada.Unchecked_Conversion + (Source => System.Address, Target => Pc_Type); + + procedure Set_Symbol_Address (Sym : Symbol; Addr : System.Address) + is + begin + Set_Symbol_Value (Sym, To_Pc_Type (Addr)); + Set_Scope (Sym, Sym_Global); + Set_Section (Sym, Sect_Abs); + end Set_Symbol_Address; + + procedure Write_Memory_Init is + begin + Create_Section (Sect_Abs, "*ABS*", Section_Exec); + Sect_Abs.Vaddr := 0; + end Write_Memory_Init; + + procedure Write_Memory_Relocate (Error : out Boolean) + is + Sect : Section_Acc; + Rel : Reloc_Acc; + N_Rel : Reloc_Acc; + begin + -- Relocate section in memory. + Sect := Section_Chain; + while Sect /= null loop + if Sect.Data = null then + if Sect.Pc > 0 then + Resize (Sect, Sect.Pc); + Sect.Data (0 .. Sect.Pc - 1) := (others => 0); + else + null; + --Sect.Data := new Byte_Array (1 .. 0); + end if; + end if; + if Sect.Data_Max > 0 + and (Sect /= Sect_Abs and Sect.Flags /= Section_Debug) + then + Sect.Vaddr := To_Pc_Type (Sect.Data (0)'Address); + end if; + Sect := Sect.Next; + end loop; + + -- Do all relocations. + Sect := Section_Chain; + Error := False; + while Sect /= null loop +-- Put_Line ("Section: " & Sect.Name.all & ", Flags:" +-- & Section_Flags'Image (Sect.Flags)); + Rel := Sect.First_Reloc; + while Rel /= null loop + N_Rel := Rel.Sect_Next; + if Get_Scope (Rel.Sym) = Sym_Undef then + Put_Line ("symbol " & Get_Symbol_Name (Rel.Sym) + & " is undefined"); + Error := True; + else + Apply_Reloc (Sect, Rel); + end if; + Free (Rel); + Rel := N_Rel; + end loop; + + Sect.First_Reloc := null; + Sect.Last_Reloc := null; + Sect.Nbr_Relocs := 0; + + if (Sect.Flags and Section_Exec) /= 0 + and (Sect.Flags and Section_Write) = 0 + then + Memsegs.Set_Rx (Sect.Seg); + end if; + + Sect := Sect.Next; + end loop; + end Write_Memory_Relocate; +end Binary_File.Memory; diff --git a/src/ortho/mcode/binary_file-memory.ads b/src/ortho/mcode/binary_file-memory.ads new file mode 100644 index 000000000..a205da527 --- /dev/null +++ b/src/ortho/mcode/binary_file-memory.ads @@ -0,0 +1,25 @@ +-- Binary file execute in memory handler. +-- 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. +package Binary_File.Memory is + + -- Must be called before set_symbol_address. + procedure Write_Memory_Init; + procedure Set_Symbol_Address (Sym : Symbol; Addr : System.Address); + + procedure Write_Memory_Relocate (Error : out Boolean); +end Binary_File.Memory; diff --git a/src/ortho/mcode/binary_file.adb b/src/ortho/mcode/binary_file.adb new file mode 100644 index 000000000..6043d7319 --- /dev/null +++ b/src/ortho/mcode/binary_file.adb @@ -0,0 +1,977 @@ +-- Binary file 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 System.Storage_Elements; +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Characters.Latin_1; +with Ada.Unchecked_Conversion; +with Hex_Images; use Hex_Images; +with Disassemble; + +package body Binary_File is + Cur_Sect : Section_Acc := null; + + HT : Character renames Ada.Characters.Latin_1.HT; + + function To_Byte_Array_Acc is new Ada.Unchecked_Conversion + (Source => System.Address, Target => Byte_Array_Acc); + + -- Resize a section to SIZE bytes. + procedure Resize (Sect : Section_Acc; Size : Pc_Type) + is + begin + Sect.Data_Max := Size; + Memsegs.Resize (Sect.Seg, Natural (Size)); + Sect.Data := To_Byte_Array_Acc (Memsegs.Get_Address (Sect.Seg)); + end Resize; + + function Get_Scope (Sym : Symbol) return Symbol_Scope is + begin + return Symbols.Table (Sym).Scope; + end Get_Scope; + + procedure Set_Scope (Sym : Symbol; Scope : Symbol_Scope) is + begin + Symbols.Table (Sym).Scope := Scope; + end Set_Scope; + + function Get_Section (Sym : Symbol) return Section_Acc is + begin + return Symbols.Table (Sym).Section; + end Get_Section; + + procedure Set_Section (Sym : Symbol; Sect : Section_Acc) is + begin + Symbols.Table (Sym).Section := Sect; + end Set_Section; + + function Get_Number (Sym : Symbol) return Natural is + begin + return Symbols.Table (Sym).Number; + end Get_Number; + + procedure Set_Number (Sym : Symbol; Num : Natural) is + begin + Symbols.Table (Sym).Number := Num; + end Set_Number; + + function Get_Relocs (Sym : Symbol) return Reloc_Acc is + begin + return Symbols.Table (Sym).Relocs; + end Get_Relocs; + + procedure Set_Relocs (Sym : Symbol; Reloc : Reloc_Acc) is + begin + Symbols.Table (Sym).Relocs := Reloc; + end Set_Relocs; + + function Get_Name (Sym : Symbol) return O_Ident is + begin + return Symbols.Table (Sym).Name; + end Get_Name; + + function Get_Used (Sym : Symbol) return Boolean is + begin + return Symbols.Table (Sym).Used; + end Get_Used; + + procedure Set_Used (Sym : Symbol; Val : Boolean) is + begin + Symbols.Table (Sym).Used := Val; + end Set_Used; + + function Get_Symbol_Value (Sym : Symbol) return Pc_Type is + begin + return Symbols.Table (Sym).Value; + end Get_Symbol_Value; + + procedure Set_Symbol_Value (Sym : Symbol; Val : Pc_Type) is + begin + Symbols.Table (Sym).Value := Val; + end Set_Symbol_Value; + + function S_Defined (Sym : Symbol) return Boolean is + begin + return Get_Scope (Sym) /= Sym_Undef; + end S_Defined; + pragma Unreferenced (S_Defined); + + function S_Local (Sym : Symbol) return Boolean is + begin + return Get_Scope (Sym) = Sym_Local; + end S_Local; + + procedure Create_Section (Sect : out Section_Acc; + Name : String; Flags : Section_Flags) + is + begin + Sect := new Section_Type'(Next => null, + Flags => Flags, + Name => new String'(Name), + Link => null, + Align => 2, + Esize => 0, + Pc => 0, + Insn_Pc => 0, + Data => null, + Data_Max => 0, + First_Reloc => null, + Last_Reloc => null, + Nbr_Relocs => 0, + Number => 0, + Seg => Memsegs.Create, + Vaddr => 0); + if (Flags and Section_Zero) = 0 then + -- Allocate memory for the segment, unless BSS. + Resize (Sect, 8192); + end if; + if (Flags and Section_Strtab) /= 0 then + Sect.Align := 0; + end if; + if Section_Chain = null then + Section_Chain := Sect; + else + Section_Last.Next := Sect; + end if; + Section_Last := Sect; + Nbr_Sections := Nbr_Sections + 1; + end Create_Section; + + procedure Sect_Prealloc (Sect : Section_Acc; L : Pc_Type) + is + New_Max : Pc_Type; + begin + if Sect.Pc + L < Sect.Data_Max then + return; + end if; + New_Max := Sect.Data_Max; + loop + New_Max := New_Max * 2; + exit when Sect.Pc + L < New_Max; + end loop; + Resize (Sect, New_Max); + end Sect_Prealloc; + + procedure Merge_Section (Dest : Section_Acc; Src : Section_Acc) + is + Rel : Reloc_Acc; + begin + -- Sanity checks. + if Src = null or else Dest = Src then + raise Program_Error; + end if; + + Rel := Src.First_Reloc; + + if Rel /= null then + -- Move relocs. + if Dest.Last_Reloc = null then + Dest.First_Reloc := Rel; + Dest.Last_Reloc := Rel; + else + Dest.Last_Reloc.Sect_Next := Rel; + Dest.Last_Reloc := Rel; + end if; + Dest.Nbr_Relocs := Dest.Nbr_Relocs + Src.Nbr_Relocs; + + + -- Reloc reloc, since the pc has changed. + while Rel /= null loop + Rel.Addr := Rel.Addr + Dest.Pc; + Rel := Rel.Sect_Next; + end loop; + end if; + + if Src.Pc > 0 then + Sect_Prealloc (Dest, Src.Pc); + Dest.Data (Dest.Pc .. Dest.Pc + Src.Pc - 1) := + Src.Data (0 .. Src.Pc - 1); + Dest.Pc := Dest.Pc + Src.Pc; + end if; + + Memsegs.Delete (Src.Seg); + Src.Pc := 0; + Src.Data_Max := 0; + Src.Data := null; + Src.First_Reloc := null; + Src.Last_Reloc := null; + Src.Nbr_Relocs := 0; + + -- Remove from section_chain. + if Section_Chain = Src then + Section_Chain := Src.Next; + else + declare + Sect : Section_Acc; + begin + Sect := Section_Chain; + while Sect.Next /= Src loop + Sect := Sect.Next; + end loop; + Sect.Next := Src.Next; + if Section_Last = Src then + Section_Last := Sect; + end if; + end; + end if; + Nbr_Sections := Nbr_Sections - 1; + end Merge_Section; + + procedure Set_Section_Info (Sect : Section_Acc; + Link : Section_Acc; + Align : Natural; + Esize : Natural) + is + begin + Sect.Link := Link; + Sect.Align := Align; + Sect.Esize := Esize; + end Set_Section_Info; + + procedure Set_Current_Section (Sect : Section_Acc) is + begin + -- If the current section does not change, this is a no-op. + if Cur_Sect = Sect then + return; + end if; + + if Dump_Asm then + Put_Line (HT & ".section """ & Sect.Name.all & """"); + end if; + Cur_Sect := Sect; + end Set_Current_Section; + + function Get_Current_Pc return Pc_Type is + begin + return Cur_Sect.Pc; + end Get_Current_Pc; + + function Get_Pc (Sect : Section_Acc) return Pc_Type is + begin + return Sect.Pc; + end Get_Pc; + + + procedure Prealloc (L : Pc_Type) is + begin + Sect_Prealloc (Cur_Sect, L); + end Prealloc; + + procedure Start_Insn is + begin + -- Check there is enough memory for the next instruction. + Sect_Prealloc (Cur_Sect, 16); + if Cur_Sect.Insn_Pc /= 0 then + -- end_insn was not called. + raise Program_Error; + end if; + Cur_Sect.Insn_Pc := Cur_Sect.Pc; + end Start_Insn; + + procedure Get_Symbol_At_Addr (Addr : System.Address; + Line : in out String; + Line_Len : in out Natural) + is + use System; + use System.Storage_Elements; + Off : Pc_Type; + Reloc : Reloc_Acc; + begin + -- Check if addr is in the current section. + if Addr < Cur_Sect.Data (0)'Address + or else Addr > Cur_Sect.Data (Cur_Sect.Pc)'Address + then + raise Program_Error; + --return; + end if; + Off := Pc_Type + (To_Integer (Addr) - To_Integer (Cur_Sect.Data (0)'Address)); + + -- Find a relocation at OFF. + Reloc := Cur_Sect.First_Reloc; + while Reloc /= null loop + if Reloc.Addr = Off then + declare + Str : constant String := Get_Symbol_Name (Reloc.Sym); + begin + Line (Line'First .. Line'First + Str'Length - 1) := Str; + Line_Len := Line_Len + Str'Length; + return; + end; + end if; + Reloc := Reloc.Sect_Next; + end loop; + end Get_Symbol_At_Addr; + + procedure End_Insn + is + Str : String (1 .. 256); + Len : Natural; + Insn_Len : Natural; + begin + --if Insn_Pc = 0 then + -- -- start_insn was not called. + -- raise Program_Error; + --end if; + if Debug_Hex then + Put (HT); + Put ('#'); + for I in Cur_Sect.Insn_Pc .. Cur_Sect.Pc - 1 loop + Put (' '); + Put (Hex_Image (Unsigned_8 (Cur_Sect.Data (I)))); + end loop; + New_Line; + end if; + + if Dump_Asm then + Disassemble.Disassemble_Insn + (Cur_Sect.Data (Cur_Sect.Insn_Pc)'Address, + Unsigned_32 (Cur_Sect.Insn_Pc), + Str, Len, Insn_Len, + Get_Symbol_At_Addr'Access); + Put (HT); + Put_Line (Str (1 .. Len)); + end if; + --if Natural (Cur_Pc - Insn_Pc) /= Insn_Len then + -- raise Program_Error; + --end if; + Cur_Sect.Insn_Pc := 0; + end End_Insn; + + procedure Gen_B8 (B : Byte) is + begin + Cur_Sect.Data (Cur_Sect.Pc) := B; + Cur_Sect.Pc := Cur_Sect.Pc + 1; + end Gen_B8; + + procedure Gen_B16 (B0, B1 : Byte) is + begin + Cur_Sect.Data (Cur_Sect.Pc + 0) := B0; + Cur_Sect.Data (Cur_Sect.Pc + 1) := B1; + Cur_Sect.Pc := Cur_Sect.Pc + 2; + end Gen_B16; + + procedure Gen_Le8 (B : Unsigned_32) is + begin + Cur_Sect.Data (Cur_Sect.Pc) := Byte (B and 16#Ff#); + Cur_Sect.Pc := Cur_Sect.Pc + 1; + end Gen_Le8; + + procedure Gen_Le16 (B : Unsigned_32) is + begin + Cur_Sect.Data (Cur_Sect.Pc + 0) := Byte (Shift_Right (B, 0) and 16#Ff#); + Cur_Sect.Data (Cur_Sect.Pc + 1) := Byte (Shift_Right (B, 8) and 16#Ff#); + Cur_Sect.Pc := Cur_Sect.Pc + 2; + end Gen_Le16; + + procedure Gen_Be16 (B : Unsigned_32) is + begin + Cur_Sect.Data (Cur_Sect.Pc + 0) := Byte (Shift_Right (B, 8) and 16#Ff#); + Cur_Sect.Data (Cur_Sect.Pc + 1) := Byte (Shift_Right (B, 0) and 16#Ff#); + Cur_Sect.Pc := Cur_Sect.Pc + 2; + end Gen_Be16; + + procedure Write_B8 (Sect : Section_Acc; Pc : Pc_Type; V : Unsigned_8) is + begin + Sect.Data (Pc) := Byte (V); + end Write_B8; + + procedure Write_Be16 (Sect : Section_Acc; Pc : Pc_Type; V : Unsigned_32) is + begin + Sect.Data (Pc + 0) := Byte (Shift_Right (V, 8) and 16#Ff#); + Sect.Data (Pc + 1) := Byte (Shift_Right (V, 0) and 16#Ff#); + end Write_Be16; + + procedure Write_Le32 (Sect : Section_Acc; Pc : Pc_Type; V : Unsigned_32) is + begin + Sect.Data (Pc + 0) := Byte (Shift_Right (V, 0) and 16#Ff#); + Sect.Data (Pc + 1) := Byte (Shift_Right (V, 8) and 16#Ff#); + Sect.Data (Pc + 2) := Byte (Shift_Right (V, 16) and 16#Ff#); + Sect.Data (Pc + 3) := Byte (Shift_Right (V, 24) and 16#Ff#); + end Write_Le32; + + procedure Write_Be32 (Sect : Section_Acc; Pc : Pc_Type; V : Unsigned_32) is + begin + Sect.Data (Pc + 0) := Byte (Shift_Right (V, 24) and 16#Ff#); + Sect.Data (Pc + 1) := Byte (Shift_Right (V, 16) and 16#Ff#); + Sect.Data (Pc + 2) := Byte (Shift_Right (V, 8) and 16#Ff#); + Sect.Data (Pc + 3) := Byte (Shift_Right (V, 0) and 16#Ff#); + end Write_Be32; + + procedure Write_16 (Sect : Section_Acc; Pc : Pc_Type; B : Unsigned_32) + is + subtype B2 is Byte_Array_Base (0 .. 1); + function To_B2 is new Ada.Unchecked_Conversion + (Source => Unsigned_16, Target => B2); + begin + Sect.Data (Pc + 0 .. Pc + 1) := To_B2 (Unsigned_16 (B)); + end Write_16; + + procedure Write_32 (Sect : Section_Acc; Pc : Pc_Type; B : Unsigned_32) + is + subtype B4 is Byte_Array_Base (0 .. 3); + function To_B4 is new Ada.Unchecked_Conversion + (Source => Unsigned_32, Target => B4); + begin + Sect.Data (Pc + 0 .. Pc + 3) := To_B4 (B); + end Write_32; + + procedure Gen_16 (B : Unsigned_32) is + begin + Write_16 (Cur_Sect, Cur_Sect.Pc, B); + Cur_Sect.Pc := Cur_Sect.Pc + 2; + end Gen_16; + + procedure Gen_32 (B : Unsigned_32) is + begin + Write_32 (Cur_Sect, Cur_Sect.Pc, B); + Cur_Sect.Pc := Cur_Sect.Pc + 4; + end Gen_32; + + function Read_Le32 (Sect : Section_Acc; Pc : Pc_Type) return Unsigned_32 is + begin + return Shift_Left (Unsigned_32 (Sect.Data (Pc + 0)), 0) + or Shift_Left (Unsigned_32 (Sect.Data (Pc + 1)), 8) + or Shift_Left (Unsigned_32 (Sect.Data (Pc + 2)), 16) + or Shift_Left (Unsigned_32 (Sect.Data (Pc + 3)), 24); + end Read_Le32; + + function Read_Be32 (Sect : Section_Acc; Pc : Pc_Type) return Unsigned_32 is + begin + return Shift_Left (Unsigned_32 (Sect.Data (Pc + 0)), 24) + or Shift_Left (Unsigned_32 (Sect.Data (Pc + 1)), 16) + or Shift_Left (Unsigned_32 (Sect.Data (Pc + 2)), 8) + or Shift_Left (Unsigned_32 (Sect.Data (Pc + 3)), 0); + end Read_Be32; + + procedure Add_Le32 (Sect : Section_Acc; Pc : Pc_Type; V : Unsigned_32) is + begin + Write_Le32 (Sect, Pc, V + Read_Le32 (Sect, Pc)); + end Add_Le32; + + procedure Patch_Le32 (Pc : Pc_Type; V : Unsigned_32) is + begin + if Pc + 4 > Get_Current_Pc then + raise Program_Error; + end if; + Write_Le32 (Cur_Sect, Pc, V); + end Patch_Le32; + + procedure Patch_Be32 (Pc : Pc_Type; V : Unsigned_32) is + begin + if Pc + 4 > Get_Current_Pc then + raise Program_Error; + end if; + Write_Be32 (Cur_Sect, Pc, V); + end Patch_Be32; + + procedure Patch_Be16 (Pc : Pc_Type; V : Unsigned_32) is + begin + if Pc + 2 > Get_Current_Pc then + raise Program_Error; + end if; + Write_Be16 (Cur_Sect, Pc, V); + end Patch_Be16; + + procedure Patch_B8 (Pc : Pc_Type; V : Unsigned_8) is + begin + if Pc >= Get_Current_Pc then + raise Program_Error; + end if; + Write_B8 (Cur_Sect, Pc, V); + end Patch_B8; + + procedure Patch_32 (Pc : Pc_Type; V : Unsigned_32) is + begin + if Pc + 4 > Get_Current_Pc then + raise Program_Error; + end if; + Write_32 (Cur_Sect, Pc, V); + end Patch_32; + + procedure Gen_Le32 (B : Unsigned_32) is + begin + Write_Le32 (Cur_Sect, Cur_Sect.Pc, B); + Cur_Sect.Pc := Cur_Sect.Pc + 4; + end Gen_Le32; + + procedure Gen_Be32 (B : Unsigned_32) is + begin + Write_Be32 (Cur_Sect, Cur_Sect.Pc, B); + Cur_Sect.Pc := Cur_Sect.Pc + 4; + end Gen_Be32; + + procedure Gen_Data_Le8 (B : Unsigned_32) is + begin + if Dump_Asm then + Put_Line (HT & ".byte 0x" & Hex_Image (Unsigned_8 (B))); + end if; + Gen_Le8 (B); + end Gen_Data_Le8; + + procedure Gen_Data_Le16 (B : Unsigned_32) is + begin + if Dump_Asm then + Put_Line (HT & ".half 0x" & Hex_Image (Unsigned_16 (B))); + end if; + Gen_Le16 (B); + end Gen_Data_Le16; + + procedure Gen_Data_32 (Sym : Symbol; Offset : Integer_32) is + begin + if Dump_Asm then + if Sym = Null_Symbol then + Put_Line (HT & ".word 0x" & Hex_Image (Offset)); + else + if Offset = 0 then + Put_Line (HT & ".word " & Get_Symbol_Name (Sym)); + else + Put_Line (HT & ".word " & Get_Symbol_Name (Sym) & " + " + & Hex_Image (Offset)); + end if; + end if; + end if; + case Arch is + when Arch_X86 => + Gen_X86_32 (Sym, Offset); + when Arch_Sparc => + Gen_Sparc_32 (Sym, Offset); + when others => + raise Program_Error; + end case; + end Gen_Data_32; + + function Create_Symbol (Name : O_Ident) return Symbol + is + begin + Symbols.Append (Symbol_Type'(Section => null, + Value => 0, + Scope => Sym_Undef, + Used => False, + Name => Name, + Relocs => null, + Number => 0)); + return Symbols.Last; + end Create_Symbol; + + Last_Label : Natural := 1; + + function Create_Local_Symbol return Symbol is + begin + Symbols.Append (Symbol_Type'(Section => Cur_Sect, + Value => 0, + Scope => Sym_Local, + Used => False, + Name => O_Ident_Nul, + Relocs => null, + Number => Last_Label)); + + Last_Label := Last_Label + 1; + + return Symbols.Last; + end Create_Local_Symbol; + + function Get_Symbol_Name (Sym : Symbol) return String + is + Res : String (1 .. 10); + N : Natural; + P : Natural; + begin + if S_Local (Sym) then + N := Get_Number (Sym); + P := Res'Last; + loop + Res (P) := Character'Val ((N mod 10) + Character'Pos ('0')); + N := N / 10; + P := P - 1; + exit when N = 0; + end loop; + Res (P) := 'L'; + Res (P - 1) := '.'; + return Res (P - 1 .. Res'Last); + else + if Is_Nul (Get_Name (Sym)) then + return "ANON"; + else + return Get_String (Get_Name (Sym)); + end if; + end if; + end Get_Symbol_Name; + + function Get_Symbol_Name_Length (Sym : Symbol) return Natural + is + N : Natural; + begin + if S_Local (Sym) then + N := 10; + for I in 3 .. 8 loop + if Get_Number (Sym) < N then + return I; + end if; + N := N * 10; + end loop; + raise Program_Error; + else + return Get_String_Length (Get_Name (Sym)); + end if; + end Get_Symbol_Name_Length; + + function Get_Symbol (Name : String) return Symbol is + begin + for I in Symbols.First .. Symbols.Last loop + if Get_Symbol_Name (I) = Name then + return I; + end if; + end loop; + return Null_Symbol; + end Get_Symbol; + + function Pow_Align (V : Pc_Type; Align : Natural) return Pc_Type + is + Tmp : Pc_Type; + begin + Tmp := V + 2 ** Align - 1; + return Tmp - (Tmp mod Pc_Type (2 ** Align)); + end Pow_Align; + + procedure Gen_Pow_Align (Align : Natural) is + begin + if Align = 0 then + return; + end if; + if Dump_Asm then + Put_Line (HT & ".align" & Natural'Image (Align)); + end if; + Cur_Sect.Pc := Pow_Align (Cur_Sect.Pc, Align); + end Gen_Pow_Align; + + -- Generate LENGTH bytes set to 0. + procedure Gen_Space (Length : Integer_32) is + begin + if Dump_Asm then + Put_Line (HT & ".space" & Integer_32'Image (Length)); + end if; + Cur_Sect.Pc := Cur_Sect.Pc + Pc_Type (Length); + end Gen_Space; + + procedure Set_Symbol_Pc (Sym : Symbol; Export : Boolean) is + begin + case Get_Scope (Sym) is + when Sym_Local => + if Export then + raise Program_Error; + end if; + when Sym_Private + | Sym_Global => + raise Program_Error; + when Sym_Undef => + if Export then + Set_Scope (Sym, Sym_Global); + else + Set_Scope (Sym, Sym_Private); + end if; + end case; + -- Set value/section. + Set_Symbol_Value (Sym, Cur_Sect.Pc); + Set_Section (Sym, Cur_Sect); + + if Dump_Asm then + if Export then + Put_Line (HT & ".globl " & Get_Symbol_Name (Sym)); + end if; + Put (Get_Symbol_Name (Sym)); + Put_Line (":"); + end if; + end Set_Symbol_Pc; + + procedure Add_Reloc (Sym : Symbol; Kind : Reloc_Kind) + is + Reloc : Reloc_Acc; + begin + Reloc := new Reloc_Type'(Kind => Kind, + Done => False, + Sym_Next => Get_Relocs (Sym), + Sect_Next => null, + Addr => Cur_Sect.Pc, + Sym => Sym); + Set_Relocs (Sym, Reloc); + if Cur_Sect.First_Reloc = null then + Cur_Sect.First_Reloc := Reloc; + else + Cur_Sect.Last_Reloc.Sect_Next := Reloc; + end if; + Cur_Sect.Last_Reloc := Reloc; + Cur_Sect.Nbr_Relocs := Cur_Sect.Nbr_Relocs + 1; + end Add_Reloc; + + procedure Gen_X86_Pc32 (Sym : Symbol) + is + begin + Add_Reloc (Sym, Reloc_Pc32); + Gen_Le32 (16#ff_ff_ff_fc#); + end Gen_X86_Pc32; + + procedure Gen_Sparc_Disp22 (W : Unsigned_32; Sym : Symbol) + is + begin + Add_Reloc (Sym, Reloc_Disp22); + Gen_Be32 (W); + end Gen_Sparc_Disp22; + + procedure Gen_Sparc_Disp30 (W : Unsigned_32; Sym : Symbol) + is + begin + Add_Reloc (Sym, Reloc_Disp30); + Gen_Be32 (W); + end Gen_Sparc_Disp30; + + procedure Gen_Sparc_Hi22 (W : Unsigned_32; + Sym : Symbol; Off : Unsigned_32) + is + pragma Unreferenced (Off); + begin + Add_Reloc (Sym, Reloc_Hi22); + Gen_Be32 (W); + end Gen_Sparc_Hi22; + + procedure Gen_Sparc_Lo10 (W : Unsigned_32; + Sym : Symbol; Off : Unsigned_32) + is + pragma Unreferenced (Off); + begin + Add_Reloc (Sym, Reloc_Lo10); + Gen_Be32 (W); + end Gen_Sparc_Lo10; + + function Conv is new Ada.Unchecked_Conversion + (Source => Integer_32, Target => Unsigned_32); + + procedure Gen_X86_32 (Sym : Symbol; Offset : Integer_32) is + begin + if Sym /= Null_Symbol then + Add_Reloc (Sym, Reloc_32); + end if; + Gen_Le32 (Conv (Offset)); + end Gen_X86_32; + + procedure Gen_Sparc_32 (Sym : Symbol; Offset : Integer_32) is + begin + if Sym /= Null_Symbol then + Add_Reloc (Sym, Reloc_32); + end if; + Gen_Be32 (Conv (Offset)); + end Gen_Sparc_32; + + procedure Gen_Sparc_Ua_32 (Sym : Symbol; Offset : Integer_32) + is + pragma Unreferenced (Offset); + begin + if Sym /= Null_Symbol then + Add_Reloc (Sym, Reloc_Ua_32); + end if; + Gen_Be32 (0); + end Gen_Sparc_Ua_32; + + procedure Gen_Ua_32 (Sym : Symbol; Offset : Integer_32) is + begin + case Arch is + when Arch_X86 => + Gen_X86_32 (Sym, Offset); + when Arch_Sparc => + Gen_Sparc_Ua_32 (Sym, Offset); + when others => + raise Program_Error; + end case; + end Gen_Ua_32; + + procedure Gen_Ppc_24 (V : Unsigned_32; Sym : Symbol) + is + begin + Add_Reloc (Sym, Reloc_Ppc_Addr24); + Gen_32 (V); + end Gen_Ppc_24; + + function Get_Symbol_Vaddr (Sym : Symbol) return Pc_Type is + begin + return Get_Section (Sym).Vaddr + Get_Symbol_Value (Sym); + end Get_Symbol_Vaddr; + + procedure Write_Left_Be32 (Sect : Section_Acc; + Addr : Pc_Type; + Size : Natural; + Val : Unsigned_32) + is + W : Unsigned_32; + Mask : Unsigned_32; + begin + -- Write value. + Mask := Shift_Left (1, Size) - 1; + W := Read_Be32 (Sect, Addr); + Write_Be32 (Sect, Addr, (W and not Mask) or (Val and Mask)); + end Write_Left_Be32; + + procedure Set_Wdisp (Sect : Section_Acc; + Addr : Pc_Type; + Sym : Symbol; + Size : Natural) + is + D : Unsigned_32; + Mask : Unsigned_32; + begin + D := Unsigned_32 (Get_Symbol_Vaddr (Sym) - (Sect.Vaddr + Addr)); + -- Check overflow. + Mask := Shift_Left (1, Size + 2) - 1; + if (D and Shift_Left (1, Size + 1)) = 0 then + if (D and not Mask) /= 0 then + raise Program_Error; + end if; + else + if (D and not Mask) /= not Mask then + raise Program_Error; + end if; + end if; + -- Write value. + Write_Left_Be32 (Sect, Addr, Size, D / 4); + end Set_Wdisp; + + procedure Do_Reloc (Kind : Reloc_Kind; + Sect : Section_Acc; Addr : Pc_Type; Sym : Symbol) + is + begin + if Get_Scope (Sym) = Sym_Undef then + raise Program_Error; + end if; + + case Kind is + when Reloc_32 => + Add_Le32 (Sect, Addr, Unsigned_32 (Get_Symbol_Vaddr (Sym))); + + when Reloc_Pc32 => + Add_Le32 (Sect, Addr, + Unsigned_32 (Get_Symbol_Vaddr (Sym) + - (Sect.Vaddr + Addr))); + when Reloc_Disp22 => + Set_Wdisp (Sect, Addr, Sym, 22); + when Reloc_Disp30 => + Set_Wdisp (Sect, Addr, Sym, 30); + when Reloc_Hi22 => + Write_Left_Be32 (Sect, Addr, 22, + Unsigned_32 (Get_Symbol_Vaddr (Sym) / 1024)); + when Reloc_Lo10 => + Write_Left_Be32 (Sect, Addr, 10, + Unsigned_32 (Get_Symbol_Vaddr (Sym))); + when Reloc_Ua_32 => + Write_Be32 (Sect, Addr, Unsigned_32 (Get_Symbol_Vaddr (Sym))); + when Reloc_Ppc_Addr24 => + raise Program_Error; + end case; + end Do_Reloc; + + function Is_Reloc_Relative (Reloc : Reloc_Acc) return Boolean is + begin + case Reloc.Kind is + when Reloc_Pc32 + | Reloc_Disp22 + | Reloc_Disp30 => + return True; + when others => + return False; + end case; + end Is_Reloc_Relative; + + procedure Apply_Reloc (Sect : Section_Acc; Reloc : Reloc_Acc) is + begin + Do_Reloc (Reloc.Kind, Sect, Reloc.Addr, Reloc.Sym); + end Apply_Reloc; + + procedure Do_Intra_Section_Reloc (Sect : Section_Acc) + is + Prev : Reloc_Acc; + Rel : Reloc_Acc; + Next : Reloc_Acc; + begin + Rel := Sect.First_Reloc; + Prev := null; + while Rel /= null loop + Next := Rel.Sect_Next; + if Get_Scope (Rel.Sym) /= Sym_Undef then + Do_Reloc (Rel.Kind, Sect, Rel.Addr, Rel.Sym); + Rel.Done := True; + + if Get_Section (Rel.Sym) = Sect + and then Is_Reloc_Relative (Rel) + then + -- Remove reloc. + Sect.Nbr_Relocs := Sect.Nbr_Relocs - 1; + if Prev = null then + Sect.First_Reloc := Next; + else + Prev.Sect_Next := Next; + end if; + if Next = null then + Sect.Last_Reloc := Prev; + end if; + Free (Rel); + else + Prev := Rel; + end if; + else + Set_Used (Rel.Sym, True); + Prev := Rel; + end if; + Rel := Next; + end loop; + end Do_Intra_Section_Reloc; + + -- Return VAL rounded up to 2 ^ POW. +-- function Align_Pow (Val : Integer; Pow : Natural) return Integer +-- is +-- N : Integer; +-- Tmp : Integer; +-- begin +-- N := 2 ** Pow; +-- Tmp := Val + N - 1; +-- return Tmp - (Tmp mod N); +-- end Align_Pow; + + procedure Disp_Stats is + begin + Put_Line ("Number of Symbols: " & Symbol'Image (Symbols.Last)); + end Disp_Stats; + + procedure Finish + is + Sect : Section_Acc; + Rel, N_Rel : Reloc_Acc; + begin + Symbols.Free; + Sect := Section_Chain; + while Sect /= null loop + -- Free relocs. + Rel := Sect.First_Reloc; + while Rel /= null loop + N_Rel := Rel.Sect_Next; + Free (Rel); + Rel := N_Rel; + end loop; + Sect.First_Reloc := null; + Sect.Last_Reloc := null; + + Sect := Sect.Next; + end loop; + end Finish; +end Binary_File; diff --git a/src/ortho/mcode/binary_file.ads b/src/ortho/mcode/binary_file.ads new file mode 100644 index 000000000..1a2bf588d --- /dev/null +++ b/src/ortho/mcode/binary_file.ads @@ -0,0 +1,305 @@ +-- Binary file 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 System; +with Interfaces; use Interfaces; +with Ada.Unchecked_Deallocation; +with Ortho_Ident; use Ortho_Ident; +with GNAT.Table; +with Memsegs; + +package Binary_File is + type Section_Type is limited private; + type Section_Acc is access Section_Type; + + type Section_Flags is new Unsigned_32; + Section_None : constant Section_Flags; + Section_Exec : constant Section_Flags; + Section_Read : constant Section_Flags; + Section_Write : constant Section_Flags; + Section_Zero : constant Section_Flags; + Section_Strtab : constant Section_Flags; + Section_Debug : constant Section_Flags; + + type Byte is new Unsigned_8; + + type Symbol is range -2 ** 31 .. 2 ** 31 - 1; + for Symbol'Size use 32; + Null_Symbol : constant Symbol := 0; + + type Pc_Type is mod System.Memory_Size; + Null_Pc : constant Pc_Type := 0; + + type Arch_Kind is (Arch_Unknown, Arch_X86, Arch_Sparc, Arch_Ppc); + Arch : Arch_Kind := Arch_Unknown; + + -- Dump assembly when generated. + Dump_Asm : Boolean := False; + + Debug_Hex : Boolean := False; + + -- Create a section. + procedure Create_Section (Sect : out Section_Acc; + Name : String; Flags : Section_Flags); + procedure Set_Section_Info (Sect : Section_Acc; + Link : Section_Acc; + Align : Natural; + Esize : Natural); + + procedure Merge_Section (Dest : Section_Acc; Src : Section_Acc); + + -- Set the current section. + procedure Set_Current_Section (Sect : Section_Acc); + + -- Create an undefined local (anonymous) symbol in the current section. + function Create_Local_Symbol return Symbol; + function Create_Symbol (Name : O_Ident) return Symbol; + + -- Research symbol NAME, very expansive call. + -- Return NULL_Symbol if not found. + function Get_Symbol (Name : String) return Symbol; + + -- Get the virtual address of a symbol. + function Get_Symbol_Vaddr (Sym : Symbol) return Pc_Type; + pragma Inline (Get_Symbol_Vaddr); + + -- Set the value of a symbol. + procedure Set_Symbol_Pc (Sym : Symbol; Export : Boolean); + function Get_Symbol_Value (Sym : Symbol) return Pc_Type; + + -- Get the current PC. + function Get_Current_Pc return Pc_Type; + pragma Inline (Get_Current_Pc); + + function Get_Pc (Sect : Section_Acc) return Pc_Type; + pragma Inline (Get_Pc); + + -- Align the current section of 2 ** ALIGN. + procedure Gen_Pow_Align (Align : Natural); + + -- Generate LENGTH times 0. + procedure Gen_Space (Length : Integer_32); + + -- Add a reloc in the current section at the current address. + procedure Gen_X86_Pc32 (Sym : Symbol); + procedure Gen_Sparc_Disp22 (W : Unsigned_32; Sym : Symbol); + procedure Gen_Sparc_Disp30 (W : Unsigned_32; Sym : Symbol); + procedure Gen_Sparc_Hi22 (W : Unsigned_32; + Sym : Symbol; Off : Unsigned_32); + procedure Gen_Sparc_Lo10 (W : Unsigned_32; + Sym : Symbol; Off : Unsigned_32); + + -- Add a 32 bits value with a symbol relocation in the current section at + -- the current address. + procedure Gen_X86_32 (Sym : Symbol; Offset : Integer_32); + procedure Gen_Sparc_32 (Sym : Symbol; Offset : Integer_32); + procedure Gen_Sparc_Ua_32 (Sym : Symbol; Offset : Integer_32); + + procedure Gen_Ppc_24 (V : Unsigned_32; Sym : Symbol); + + procedure Gen_Ua_32 (Sym : Symbol; Offset : Integer_32); + + -- Start/finish an instruction in the current section. + procedure Start_Insn; + procedure End_Insn; + -- Pre allocate L bytes. + procedure Prealloc (L : Pc_Type); + + -- Add bits in the current section. + procedure Gen_B8 (B : Byte); + procedure Gen_B16 (B0, B1 : Byte); + procedure Gen_Le8 (B : Unsigned_32); + procedure Gen_Le16 (B : Unsigned_32); + procedure Gen_Be16 (B : Unsigned_32); + procedure Gen_Le32 (B : Unsigned_32); + procedure Gen_Be32 (B : Unsigned_32); + + procedure Gen_16 (B : Unsigned_32); + procedure Gen_32 (B : Unsigned_32); + + -- Add bits in the current section, but as stand-alone data. + procedure Gen_Data_Le8 (B : Unsigned_32); + procedure Gen_Data_Le16 (B : Unsigned_32); + procedure Gen_Data_32 (Sym : Symbol; Offset : Integer_32); + + -- Modify already generated code. + procedure Patch_B8 (Pc : Pc_Type; V : Unsigned_8); + procedure Patch_Le32 (Pc : Pc_Type; V : Unsigned_32); + procedure Patch_Be32 (Pc : Pc_Type; V : Unsigned_32); + procedure Patch_Be16 (Pc : Pc_Type; V : Unsigned_32); + procedure Patch_32 (Pc : Pc_Type; V : Unsigned_32); + + -- Binary writers: + + -- Set ERROR in case of error (undefined symbol). + --procedure Write_Memory (Error : out Boolean); + + procedure Disp_Stats; + procedure Finish; +private + type Byte_Array_Base is array (Pc_Type range <>) of Byte; + subtype Byte_Array is Byte_Array_Base (Pc_Type); + type Byte_Array_Acc is access Byte_Array; + type String_Acc is access String; + --type Section_Flags is new Unsigned_32; + + -- Relocations. + type Reloc_Kind is (Reloc_32, Reloc_Pc32, + Reloc_Ua_32, + Reloc_Disp22, Reloc_Disp30, + Reloc_Hi22, Reloc_Lo10, + Reloc_Ppc_Addr24); + type Reloc_Type; + type Reloc_Acc is access Reloc_Type; + type Reloc_Type is record + Kind : Reloc_Kind; + -- If true, the reloc was already applied. + Done : Boolean; + -- Next in simply linked list. + -- next reloc in the section. + Sect_Next : Reloc_Acc; + -- next reloc for the symbol. + Sym_Next : Reloc_Acc; + -- Address that must be relocated. + Addr : Pc_Type; + -- Symbol. + Sym : Symbol; + end record; + + type Section_Type is record + -- Simply linked list of sections. + Next : Section_Acc; + -- Flags. + Flags : Section_Flags; + -- Name of the section. + Name : String_Acc; + -- Link to another section (used by ELF). + Link : Section_Acc; + -- Alignment (in power of 2). + Align : Natural; + -- Entry size (if any). + Esize : Natural; + -- Offset of the next data in DATA. + Pc : Pc_Type; + -- Offset of the current instruction. + Insn_Pc : Pc_Type; + -- Data for this section. + Data : Byte_Array_Acc; + -- Max address for data (before extending the area). + Data_Max : Pc_Type; + -- Chain of relocs defined in this section. + First_Reloc : Reloc_Acc; + Last_Reloc : Reloc_Acc; + -- Number of relocs in this section. + Nbr_Relocs : Natural; + -- Section number (set and used by binary writer). + Number : Natural; + -- Virtual address, if set. + Vaddr : Pc_Type; -- SSE.Integer_Address; + -- Memory for this segment. + Seg : Memsegs.Memseg_Type; + end record; + + Section_Exec : constant Section_Flags := 2#0000_0001#; + Section_Read : constant Section_Flags := 2#0000_0010#; + Section_Write : constant Section_Flags := 2#0000_0100#; + Section_Zero : constant Section_Flags := 2#0000_1000#; + Section_Strtab : constant Section_Flags := 2#0001_0000#; + Section_Debug : constant Section_Flags := 2#0010_0000#; + Section_None : constant Section_Flags := 2#0000_0000#; + + -- Scope of a symbol: + -- SYM_PRIVATE: not visible outside of the file. + -- SYM_UNDEF: not (yet) defined, unresolved. + -- SYM_GLOBAL: visible to all files. + -- SYM_LOCAL: locally generated symbol. + type Symbol_Scope is (Sym_Undef, Sym_Global, Sym_Private, Sym_Local); + subtype Symbol_Scope_External is Symbol_Scope range Sym_Undef .. Sym_Global; + type Symbol_Type is record + Section : Section_Acc; + Value : Pc_Type; + Scope : Symbol_Scope; + -- True if the symbol is referenced/used. + Used : Boolean; + -- Name of the symbol. + Name : O_Ident; + -- List of relocation made with this symbol. + Relocs : Reloc_Acc; + -- Symbol number, from 0. + Number : Natural; + end record; + + -- Number of sections. + Nbr_Sections : Natural := 0; + -- Simply linked list of sections. + Section_Chain : Section_Acc := null; + Section_Last : Section_Acc := null; + + package Symbols is new GNAT.Table + (Table_Component_Type => Symbol_Type, + Table_Index_Type => Symbol, + Table_Low_Bound => 2, + Table_Initial => 1024, + Table_Increment => 100); + + function Pow_Align (V : Pc_Type; Align : Natural) return Pc_Type; + + function Get_Symbol_Name (Sym : Symbol) return String; + function Get_Symbol_Name_Length (Sym : Symbol) return Natural; + + procedure Set_Symbol_Value (Sym : Symbol; Val : Pc_Type); + pragma Inline (Set_Symbol_Value); + + procedure Set_Scope (Sym : Symbol; Scope : Symbol_Scope); + pragma Inline (Set_Scope); + + function Get_Scope (Sym : Symbol) return Symbol_Scope; + pragma Inline (Get_Scope); + + function Get_Section (Sym : Symbol) return Section_Acc; + pragma Inline (Get_Section); + + procedure Set_Section (Sym : Symbol; Sect : Section_Acc); + pragma Inline (Set_Section); + + function Get_Name (Sym : Symbol) return O_Ident; + pragma Inline (Get_Name); + + procedure Apply_Reloc (Sect : Section_Acc; Reloc : Reloc_Acc); + pragma Inline (Apply_Reloc); + + procedure Set_Number (Sym : Symbol; Num : Natural); + pragma Inline (Set_Number); + + function Get_Number (Sym : Symbol) return Natural; + pragma Inline (Get_Number); + + function Get_Used (Sym : Symbol) return Boolean; + pragma Inline (Get_Used); + + procedure Do_Intra_Section_Reloc (Sect : Section_Acc); + + function S_Local (Sym : Symbol) return Boolean; + pragma Inline (S_Local); + + procedure Resize (Sect : Section_Acc; Size : Pc_Type); + + procedure Free is new Ada.Unchecked_Deallocation + (Name => Reloc_Acc, Object => Reloc_Type); + + Write_Error : exception; +end Binary_File; diff --git a/src/ortho/mcode/coff.ads b/src/ortho/mcode/coff.ads new file mode 100644 index 000000000..6ef9cdde9 --- /dev/null +++ b/src/ortho/mcode/coff.ads @@ -0,0 +1,208 @@ +-- COFF definitions. +-- 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 Interfaces; use Interfaces; +with System; use System; + +package Coff is + type Filehdr is record + F_Magic : Unsigned_16; -- Magic number. + F_Nscns : Unsigned_16; -- Number of sections. + F_Timdat : Unsigned_32; -- Time and date stamp. + F_Symptr : Unsigned_32; -- File pointer to symtab. + F_Nsyms : Unsigned_32; -- Number of symtab entries. + F_Opthdr : Unsigned_16; -- Size of optionnal header. + F_Flags : Unsigned_16; -- Flags; + end record; + + -- Size of Filehdr. + Filehdr_Size : constant Natural := Filehdr'Size / Storage_Unit; + + -- Magic numbers. + I386magic : constant Unsigned_16 := 16#014c#; + + -- Flags of file header. + -- Relocation info stripped from file. + F_Relflg : constant Unsigned_16 := 16#0001#; + + -- File is executable (no unresolved symbols). + F_Exec : constant Unsigned_16 := 16#0002#; + + -- Line numbers stripped from file. + F_Lnno : constant Unsigned_16 := 16#0004#; + + -- Local symbols stripped from file. + F_Lsyms : constant Unsigned_16 := 16#0008#; + + type Scnhdr is record + S_Name : String (1 .. 8); -- Section name. + S_Paddr : Unsigned_32; -- Physical address. + S_Vaddr : Unsigned_32; -- Virtual address. + S_Size : Unsigned_32; -- Section size. + S_Scnptr : Unsigned_32; -- File pointer to raw section data. + S_Relptr : Unsigned_32; -- File pointer to relocation data. + S_Lnnoptr : Unsigned_32; -- File pointer to line number data. + S_Nreloc : Unsigned_16; -- Number of relocation entries. + S_Nlnno : Unsigned_16; -- Number of line number entries. + S_Flags : Unsigned_32; -- Flags. + end record; + Scnhdr_Size : constant Natural := Scnhdr'Size / Storage_Unit; + + -- section contains text only. + STYP_TEXT : constant Unsigned_32 := 16#0020#; + -- section contains data only. + STYP_DATA : constant Unsigned_32 := 16#0040#; + -- section contains bss only. + STYP_BSS : constant Unsigned_32 := 16#0080#; + + type Strent_Type is record + E_Zeroes : Unsigned_32; + E_Offset : Unsigned_32; + end record; + + type Sym_Name (Inline : Boolean := True) is record + case Inline is + when True => + E_Name : String (1 .. 8); + when False => + E : Strent_Type; + end case; + end record; + pragma Unchecked_Union (Sym_Name); + for Sym_Name'Size use 64; + + type Syment is record + E : Sym_Name; -- Name of the symbol + E_Value : Unsigned_32; -- Value + E_Scnum : Unsigned_16; -- Section + E_Type : Unsigned_16; + E_Sclass : Unsigned_8; + E_Numaux : Unsigned_8; + end record; + Symesz : constant Natural := 18; + for Syment'Size use Symesz * Storage_Unit; + + -- An undefined (extern) symbol. + N_UNDEF : constant Unsigned_16 := 16#00_00#; + -- An absolute symbol (e_value is a constant, not an address). + N_ABS : constant Unsigned_16 := 16#Ff_Ff#; + -- A debugging symbol. + N_DEBUG : constant Unsigned_16 := 16#Ff_Fe#; + + C_NULL : constant Unsigned_8 := 0; + C_AUTO : constant Unsigned_8 := 1; + C_EXT : constant Unsigned_8 := 2; + C_STAT : constant Unsigned_8 := 3; + C_REG : constant Unsigned_8 := 4; + C_EXTDEF : constant Unsigned_8 := 5; + C_LABEL : constant Unsigned_8 := 6; + C_ULABEL : constant Unsigned_8 := 7; + C_MOS : constant Unsigned_8 := 8; + C_ARG : constant Unsigned_8 := 9; + C_STRTAG : constant Unsigned_8 := 10; + C_MOU : constant Unsigned_8 := 11; + C_UNTAG : constant Unsigned_8 := 12; + C_TPDEF : constant Unsigned_8 := 13; + C_USTATIC : constant Unsigned_8 := 14; + C_ENTAG : constant Unsigned_8 := 15; + C_MOE : constant Unsigned_8 := 16; + C_REGPARM : constant Unsigned_8 := 17; + C_FIELD : constant Unsigned_8 := 18; + C_AUTOARG : constant Unsigned_8 := 19; + C_LASTENT : constant Unsigned_8 := 20; + C_BLOCK : constant Unsigned_8 := 100; + C_FCN : constant Unsigned_8 := 101; + C_EOS : constant Unsigned_8 := 102; + C_FILE : constant Unsigned_8 := 103; + C_LINE : constant Unsigned_8 := 104; + C_ALIAS : constant Unsigned_8 := 105; + C_HIDDEN : constant Unsigned_8 := 106; + C_EFCN : constant Unsigned_8 := 255; + + -- Textual description of sclass. + type Const_String_Acc is access constant String; + type Sclass_Desc_Type is record + Name : Const_String_Acc; + Meaning : Const_String_Acc; + end record; + type Sclass_Desc_Array_Type is array (Unsigned_8) of Sclass_Desc_Type; + Sclass_Desc : constant Sclass_Desc_Array_Type; + + type Auxent_File (Inline : Boolean := True) is record + case Inline is + when True => + X_Fname : String (1 .. 14); + when False => + X_N : Strent_Type; + end case; + end record; + pragma Unchecked_Union (Auxent_File); + + type Auxent_Scn is record + X_Scnlen : Unsigned_32; + X_Nreloc : Unsigned_16; + X_Nlinno : Unsigned_16; + end record; + + -- Relocation. + type Reloc is record + R_Vaddr : Unsigned_32; + R_Symndx : Unsigned_32; + R_Type : Unsigned_16; + end record; + Relsz : constant Natural := Reloc'Size / Storage_Unit; + + Reloc_Rel32 : constant Unsigned_16 := 20; + Reloc_Addr32 : constant Unsigned_16 := 6; + +private + subtype S is String; + Sclass_Desc : constant Sclass_Desc_Array_Type := + (C_NULL => (new S'("C_NULL"), new S'("No entry")), + C_AUTO => (new S'("C_AUTO"), new S'("Automatic variable")), + C_EXT => (new S'("C_EXT"), new S'("External/public symbol")), + C_STAT => (new S'("C_STAT"), new S'("static (private) symbol")), + C_REG => (new S'("C_REG"), new S'("register variable")), + C_EXTDEF => (new S'("C_EXTDEF"), new S'("External definition")), + C_LABEL => (new S'("C_LABEL"), new S'("label")), + C_ULABEL => (new S'("C_ULABEL"), new S'("undefined label")), + C_MOS => (new S'("C_MOS"), new S'("member of structure")), + C_ARG => (new S'("C_ARG"), new S'("function argument")), + C_STRTAG => (new S'("C_STRTAG"), new S'("structure tag")), + C_MOU => (new S'("C_MOU"), new S'("member of union")), + C_UNTAG => (new S'("C_UNTAG"), new S'("union tag")), + C_TPDEF => (new S'("C_TPDEF"), new S'("type definition")), + C_USTATIC => (new S'("C_USTATIC"), new S'("undefined static")), + C_ENTAG => (new S'("C_ENTAG"), new S'("enumaration tag")), + C_MOE => (new S'("C_MOE"), new S'("member of enumeration")), + C_REGPARM => (new S'("C_REGPARM"), new S'("register parameter")), + C_FIELD => (new S'("C_FIELD"), new S'("bit field")), + C_AUTOARG => (new S'("C_AUTOARG"), new S'("auto argument")), + C_LASTENT => (new S'("C_LASTENT"), new S'("dummy entry (end of block)")), + C_BLOCK => (new S'("C_BLOCK"), new S'("beginning or end of block")), + C_FCN => (new S'("C_FCN"), new S'("beginning or end of function")), + C_EOS => (new S'("C_EOS"), new S'("end of structure")), + C_FILE => (new S'("C_FILE"), new S'("file name")), + C_LINE => (new S'("C_LINE"), + new S'("line number, reformatted as symbol")), + C_ALIAS => (new S'("C_ALIAS"), new S'("duplicate tag")), + C_HIDDEN => (new S'("C_HIDDEN"), + new S'("ext symbol in dmert public lib")), + C_EFCN => (new S'("C_EFCN"), new S'("physical end of function")), + others => (null, null)); + +end Coff; diff --git a/src/ortho/mcode/coffdump.adb b/src/ortho/mcode/coffdump.adb new file mode 100644 index 000000000..6384b6c27 --- /dev/null +++ b/src/ortho/mcode/coffdump.adb @@ -0,0 +1,274 @@ +-- COFF dumper. +-- 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 Coff; use Coff; +with Interfaces; use Interfaces; +with System; +with Ada.Unchecked_Conversion; +with Ada.Command_Line; use Ada.Command_Line; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Ada.Text_IO; use Ada.Text_IO; +with Hex_Images; use Hex_Images; + +procedure Coffdump is + type Cstring is array (Unsigned_32 range <>) of Character; + type Cstring_Acc is access Cstring; + type Section_Array is array (Unsigned_16 range <>) of Scnhdr; + type Section_Array_Acc is access Section_Array; + -- Array of sections. + Sections : Section_Array_Acc; + + type External_Symbol is array (0 .. Symesz - 1) of Character; + type External_Symbol_Array is array (Unsigned_32 range <>) + of External_Symbol; + type Symbol_Array_Acc is access External_Symbol_Array; + -- Symbols table. + External_Symbols : Symbol_Array_Acc; + + -- String table. + Str : Cstring_Acc; + Str_Size : Natural; + + Hdr : Filehdr; + --Sym : Syment; + Fd : File_Descriptor; + Skip : Natural; + Skip_Kind : Unsigned_8; + Aux_File : Auxent_File; + Aux_Scn : Auxent_Scn; + Rel : Reloc; + Len : Natural; + + Nul : constant Character := Character'Val (0); + + function Find_Nul (S : String) return String is + begin + for I in S'Range loop + if S (I) = Nul then + return S (S'First .. I - 1); + end if; + end loop; + return S; + end Find_Nul; + + function Get_String (N : Strent_Type; S : String) return String + is + begin + if N.E_Zeroes /= 0 then + return Find_Nul (S); + else + for I in N.E_Offset .. Str'Last loop + if Str (I) = Nul then + return String (Str (N.E_Offset .. I - 1)); + end if; + end loop; + raise Program_Error; + end if; + end Get_String; + + procedure Memcpy + (Dst : System.Address; Src : System.Address; Size : Natural); + pragma Import (C, Memcpy); + + function Get_Section_Name (N : Unsigned_16) return String is + begin + if N = N_UNDEF then + return "UNDEF"; + elsif N = N_ABS then + return "ABS"; + elsif N = N_DEBUG then + return "DEBUG"; + elsif N > Hdr.F_Nscns then + return "???"; + else + return Find_Nul (Sections (N).S_Name); + end if; + end Get_Section_Name; + + function Get_Symbol (N : Unsigned_32) return Syment is + function Unchecked_Conv is new Ada.Unchecked_Conversion + (Source => External_Symbol, Target => Syment); + begin + if N > Hdr.F_Nsyms then + raise Constraint_Error; + end if; + return Unchecked_Conv (External_Symbols (N)); + end Get_Symbol; + + function Get_Symbol_Name (N : Unsigned_32) return String + is + S : Syment := Get_Symbol (N); + begin + return Get_String (S.E.E, S.E.E_Name); + end Get_Symbol_Name; +begin + for I in 1 .. Argument_Count loop + Fd := Open_Read (Argument (I), Binary); + if Fd = Invalid_FD then + Put_Line ("cannot open " & Argument (I)); + return; + end if; + -- Read file header. + if Read (Fd, Hdr'Address, Filehdr_Size) /= Filehdr_Size then + Put_Line ("cannot read header"); + return; + end if; + Put_Line ("File: " & Argument (I)); + Put_Line ("magic: " & Hex_Image (Hdr.F_Magic)); + Put_Line ("number of sections: " & Hex_Image (Hdr.F_Nscns)); + Put_Line ("time and date stamp: " & Hex_Image (Hdr.F_Timdat)); + Put_Line ("symtab file pointer: " & Hex_Image (Hdr.F_Symptr)); + Put_Line ("nbr symtab entries: " & Hex_Image (Hdr.F_Nsyms)); + Put_Line ("opt header size: " & Hex_Image (Hdr.F_Opthdr)); + Put_Line ("flags: " & Hex_Image (Hdr.F_Flags)); + + -- Read sections header. + Lseek (Fd, Long_Integer (Hdr.F_Opthdr), Seek_Cur); + Sections := new Section_Array (1 .. Hdr.F_Nscns); + Len := Scnhdr_Size * Natural (Hdr.F_Nscns); + if Read (Fd, Sections (1)'Address, Len) /= Len then + Put_Line ("cannot read section header"); + return; + end if; + for I in 1 .. Hdr.F_Nscns loop + declare + S: Scnhdr renames Sections (I); + begin + Put_Line ("Section " & Find_Nul (S.S_Name)); + Put_Line ("Physical address : " & Hex_Image (S.S_Paddr)); + Put_Line ("Virtual address : " & Hex_Image (S.S_Vaddr)); + Put_Line ("section size : " & Hex_Image (S.S_Size)); + Put_Line ("section pointer : " & Hex_Image (S.S_Scnptr)); + Put_Line ("relocation pointer : " & Hex_Image (S.S_Relptr)); + Put_Line ("line num pointer : " & Hex_Image (S.S_Lnnoptr)); + Put_Line ("Nbr reloc entries : " & Hex_Image (S.S_Nreloc)); + Put_Line ("Nbr line num entries : " & Hex_Image (S.S_Nlnno)); + Put_Line ("Flags : " & Hex_Image (S.S_Flags)); + end; + end loop; + + -- Read string table. + Lseek (Fd, + Long_Integer (Hdr.F_Symptr + Hdr.F_Nsyms * Unsigned_32 (Symesz)), + Seek_Set); + if Read (Fd, Str_Size'Address, 4) /= 4 then + Put_Line ("cannot read string table size"); + return; + end if; + Str := new Cstring (0 .. Unsigned_32 (Str_Size)); + if Read (Fd, Str (4)'Address, Str_Size - 4) /= Str_Size - 4 then + Put_Line ("cannot read string table"); + return; + end if; + + -- Read symbol table. + Lseek (Fd, Long_Integer (Hdr.F_Symptr), Seek_Set); + External_Symbols := new External_Symbol_Array (0 .. Hdr.F_Nsyms - 1); + Len := Natural (Hdr.F_Nsyms) * Symesz; + if Read (Fd, External_Symbols (0)'Address, Len) /= Len then + Put_Line ("cannot read symbol"); + return; + end if; + + Skip := 0; + Skip_Kind := C_NULL; + for I in External_Symbols'range loop + if Skip > 0 then + case Skip_Kind is + when C_FILE => + Memcpy (Aux_File'Address, External_Symbols (I)'Address, + Aux_File'Size / 8); + Put_Line ("aux file : " & Get_String (Aux_File.X_N, + Aux_File.X_Fname)); + Skip_Kind := C_NULL; + when C_STAT => + Memcpy (Aux_Scn'Address, External_Symbols (I)'Address, + Aux_Scn'Size / 8); + Put_Line ("section len: " & Hex_Image (Aux_Scn.X_Scnlen)); + Put_Line ("nbr reloc ent: " & Hex_Image (Aux_Scn.X_Nreloc)); + Put_Line ("nbr line num: " & Hex_Image (Aux_Scn.X_Nlinno)); + when others => + Put_Line ("skip"); + end case; + Skip := Skip - 1; + else + declare + S : Syment := Get_Symbol (I); + begin + Put_Line ("Symbol #" & Hex_Image (I)); + Put_Line ("symbol name : " & Get_Symbol_Name (I)); + Put_Line ("symbol value: " & Hex_Image (S.E_Value)); + Put_Line ("section num : " & Hex_Image (S.E_Scnum) + & " " & Get_Section_Name (S.E_Scnum)); + Put_Line ("type : " & Hex_Image (S.E_Type)); + Put ("sclass : " & Hex_Image (S.E_Sclass)); + if Sclass_Desc (S.E_Sclass).Name /= null then + Put (" ("); + Put (Sclass_Desc (S.E_Sclass).Name.all); + Put (" - "); + Put (Sclass_Desc (S.E_Sclass).Meaning.all); + Put (")"); + end if; + New_Line; + Put_Line ("numaux : " & Hex_Image (S.E_Numaux)); + if S.E_Numaux > 0 then + case S.E_Sclass is + when C_FILE => + Skip_Kind := C_FILE; + when C_STAT => + Skip_Kind := C_STAT; + when others => + Skip_Kind := C_NULL; + end case; + end if; + Skip := Natural (S.E_Numaux); + end; + end if; + end loop; + + -- Disp relocs. + for I in 1 .. Hdr.F_Nscns loop + if Sections (I).S_Nreloc > 0 then + -- Read relocations. + Put_Line ("Relocations for section " & Get_Section_Name (I)); + Lseek (Fd, Long_Integer (Sections (I).S_Relptr), Seek_Set); + for J in 1 .. Sections (I).S_Nreloc loop + if Read (Fd, Rel'Address, Relsz) /= Relsz then + Put_Line ("cannot read reloc"); + return; + end if; + Put_Line ("reloc virtual addr: " & Hex_Image (Rel.R_Vaddr)); + Put_Line ("symbol index : " & Hex_Image (Rel.R_Symndx) + & " " & Get_Symbol_Name (Rel.R_Symndx)); + Put ("type of relocation: " & Hex_Image (Rel.R_Type)); + case Rel.R_Type is + when Reloc_Rel32 => + Put (" RELOC_REL32"); + when Reloc_Addr32 => + Put (" RELOC_ADDR32"); + when others => + null; + end case; + New_Line; + end loop; + end if; + end loop; + + Close (Fd); + end loop; +end Coffdump; + diff --git a/src/ortho/mcode/disa_sparc.adb b/src/ortho/mcode/disa_sparc.adb new file mode 100644 index 000000000..8c9176ff8 --- /dev/null +++ b/src/ortho/mcode/disa_sparc.adb @@ -0,0 +1,274 @@ +with System; use System; +with Interfaces; use Interfaces; +with Ada.Unchecked_Conversion; +with Hex_Images; use Hex_Images; + +package body Disa_Sparc is + subtype Reg_Type is Unsigned_32 range 0 .. 31; + + type Hex_Map_Type is array (Unsigned_32 range 0 .. 15) of Character; + Hex_Digit : constant Hex_Map_Type := "0123456789abcdef"; + + type Cstring_Acc is access constant String; + type Cond_Map_Type is array (Unsigned_32 range 0 .. 15) of Cstring_Acc; + subtype S is String; + Bicc_Map : constant Cond_Map_Type := + (0 => new S'("n"), + 1 => new S'("e"), + 2 => new S'("le"), + 3 => new S'("l"), + 4 => new S'("leu"), + 5 => new S'("cs"), + 6 => new S'("neg"), + 7 => new S'("vs"), + 8 => new S'("a"), + 9 => new S'("ne"), + 10 => new S'("g"), + 11 => new S'("ge"), + 12 => new S'("gu"), + 13 => new S'("cc"), + 14 => new S'("pos"), + 15 => new S'("vc") + ); + + + type Format_Type is + ( + Format_Bad, + Format_Regimm, -- format 3, rd, rs1, rs2 or imm13 + Format_Rd, -- format 3, rd only. + Format_Copro, -- format 3, fpu or coprocessor + Format_Asi -- format 3, rd, rs1, asi and rs2. + ); + + type Insn_Desc_Type is record + Name : Cstring_Acc; + Format : Format_Type; + end record; + + type Insn_Desc_Array is array (Unsigned_32 range 0 .. 63) of Insn_Desc_Type; + Insn_Desc_10 : constant Insn_Desc_Array := + ( + 2#000_000# => (new S'("add"), Format_Regimm), + 2#000_001# => (new S'("and"), Format_Regimm), + 2#000_010# => (new S'("or"), Format_Regimm), + 2#000_011# => (new S'("xor"), Format_Regimm), + 2#000_100# => (new S'("sub"), Format_Regimm), + 2#000_101# => (new S'("andn"), Format_Regimm), + 2#000_110# => (new S'("orn"), Format_Regimm), + 2#000_111# => (new S'("xnor"), Format_Regimm), + 2#001_000# => (new S'("addx"), Format_Regimm), + + 2#001_100# => (new S'("subx"), Format_Regimm), + + 2#010_000# => (new S'("addcc"), Format_Regimm), + 2#010_001# => (new S'("andcc"), Format_Regimm), + 2#010_010# => (new S'("orcc"), Format_Regimm), + 2#010_011# => (new S'("xorcc"), Format_Regimm), + 2#010_100# => (new S'("subcc"), Format_Regimm), + 2#010_101# => (new S'("andncc"), Format_Regimm), + 2#010_110# => (new S'("orncc"), Format_Regimm), + 2#010_111# => (new S'("xnorcc"), Format_Regimm), + 2#011_000# => (new S'("addxcc"), Format_Regimm), + + 2#011_100# => (new S'("subxcc"), Format_Regimm), + + 2#111_000# => (new S'("jmpl"), Format_Regimm), + + 2#111_100# => (new S'("save"), Format_Regimm), + 2#111_101# => (new S'("restore"), Format_Regimm), + + others => (null, Format_Bad) + ); + + Insn_Desc_11 : constant Insn_Desc_Array := + ( + 2#000_000# => (new S'("ld"), Format_Regimm), + 2#000_001# => (new S'("ldub"), Format_Regimm), + 2#000_010# => (new S'("lduh"), Format_Regimm), + 2#000_011# => (new S'("ldd"), Format_Regimm), + 2#000_100# => (new S'("st"), Format_Regimm), + 2#000_101# => (new S'("stb"), Format_Regimm), + + 2#010_000# => (new S'("lda"), Format_Asi), + 2#010_011# => (new S'("ldda"), Format_Asi), + + 2#110_000# => (new S'("ldc"), Format_Regimm), + 2#110_001# => (new S'("ldcsr"), Format_Regimm), + + others => (null, Format_Bad) + ); + + -- Disassemble instruction at ADDR, and put the result in LINE/LINE_LEN. + procedure Disassemble_Insn (Addr : Address; + Line : in out String; + Line_Len : out Natural; + Insn_Len : out Natural; + Proc_Cb : Symbol_Proc_Type) + is + type Unsigned_32_Acc is access Unsigned_32; + function To_Unsigned_32_Acc is new Ada.Unchecked_Conversion + (Source => Address, Target => Unsigned_32_Acc); + + W : Unsigned_32; + Lo : Natural; + + -- Add CHAR to the line. + procedure Add_Char (C : Character); + pragma Inline (Add_Char); + + procedure Add_Char (C : Character) is + begin + Line (Lo) := C; + Lo := Lo + 1; + end Add_Char; + + -- Add STR to the line. + procedure Add_String (Str : String) is + begin + Line (Lo .. Lo + Str'Length - 1) := Str; + Lo := Lo + Str'Length; + end Add_String; + + -- Add BYTE to the line. +-- procedure Add_Byte (V : Byte) is +-- type My_Str is array (Natural range 0 .. 15) of Character; +-- Hex_Digit : constant My_Str := "0123456789abcdef"; +-- begin +-- Add_Char (Hex_Digit (Natural (Shift_Right (V, 4) and 16#0f#))); +-- Add_Char (Hex_Digit (Natural (Shift_Right (V, 0) and 16#0f#))); +-- end Add_Byte; + + procedure Disp_Const (Mask : Unsigned_32) + is + L : Natural; + V : Unsigned_32; + begin + L := Lo; + Proc_Cb.all (Addr, Line (Lo .. Line'Last), Lo); + V := W and Mask; + + -- Extend sign. + if (W and ((Mask + 1) / 2)) /= 0 then + V := V or not Mask; + end if; + if L /= Lo then + if V = 0 then + return; + end if; + Add_String (" + "); + end if; + Add_String ("0x"); + Add_String (Hex_Image (V)); + end Disp_Const; + + procedure Add_Cond (Str : String) + is + begin + Add_String (Str); + Add_String (Bicc_Map (Shift_Right (W, 25) and 2#1111#).all); + if (W and 16#2000_0000#) /= 0 then + Add_String (",a"); + end if; + Add_Char (' '); + Disp_Const (16#3f_Ffff#); + end Add_Cond; + + + procedure Add_Ireg (R : Reg_Type) + is + begin + Add_Char ('%'); + if R <= 7 then + Add_Char ('g'); + elsif R <= 15 then + if R = 14 then + Add_String ("sp"); + return; + else + Add_Char ('o'); + end if; + elsif R <= 23 then + Add_Char ('l'); + else + if R = 30 then + Add_String ("fp"); + return; + else + Add_Char ('i'); + end if; + end if; + Add_Char (Hex_Digit (R and 7)); + end Add_Ireg; + + procedure Disp_Unknown is + begin + Add_String ("unknown "); + Add_String (Hex_Image (W)); + end Disp_Unknown; + + procedure Disp_Format3 (Map : Insn_Desc_Array) + is + Op2 : Unsigned_32 range 0 .. 63; + begin + Op2 := Shift_Right (W, 19) and 2#111_111#; + + case Map (Op2).Format is + when Format_Regimm => + Add_String (Map (Op2).Name.all); + Add_Char (' '); + Add_Ireg (Shift_Right (W, 25) and 31); + Add_Char (','); + Add_Ireg (Shift_Right (W, 14) and 31); + Add_Char (','); + if (W and 16#2000#) /= 0 then + Disp_Const (16#1fff#); + else + Add_Ireg (W and 31); + end if; + when others => + Add_String ("unknown3, op2="); + Add_String (Hex_Image (Op2)); + end case; + end Disp_Format3; + + + begin + W := To_Unsigned_32_Acc (Addr).all; + Insn_Len := 4; + Lo := Line'First; + + case Shift_Right (W, 30) is + when 2#00# => + -- BIcc, SETHI + case Shift_Right (W, 22) and 2#111# is + when 2#000# => + Add_String ("unimp "); + Disp_Const (16#3f_Ffff#); + when 2#010# => + Add_Cond ("b"); + when 2#100# => + Add_String ("sethi "); + Add_Ireg (Shift_Right (W, 25)); + Add_String (", "); + Disp_Const (16#3f_Ffff#); + when others => + Disp_Unknown; + end case; + when 2#01# => + -- Call + Add_String ("call "); + Disp_Const (16#3fff_Ffff#); + when 2#10# => + Disp_Format3 (Insn_Desc_10); + when 2#11# => + Disp_Format3 (Insn_Desc_11); + when others => + -- Misc. + Disp_Unknown; + end case; + + Line_Len := Lo - Line'First; + end Disassemble_Insn; + +end Disa_Sparc; diff --git a/src/ortho/mcode/disa_sparc.ads b/src/ortho/mcode/disa_sparc.ads new file mode 100644 index 000000000..486dff977 --- /dev/null +++ b/src/ortho/mcode/disa_sparc.ads @@ -0,0 +1,15 @@ +with System; + +package Disa_Sparc is + -- Call-back used to find a relocation symbol. + type Symbol_Proc_Type is access procedure (Addr : System.Address; + Line : in out String; + Line_Len : in out Natural); + + -- Disassemble instruction at ADDR, and put the result in LINE/LINE_LEN. + procedure Disassemble_Insn (Addr : System.Address; + Line : in out String; + Line_Len : out Natural; + Insn_Len : out Natural; + Proc_Cb : Symbol_Proc_Type); +end Disa_Sparc; diff --git a/src/ortho/mcode/disa_x86.adb b/src/ortho/mcode/disa_x86.adb new file mode 100644 index 000000000..1d2d48565 --- /dev/null +++ b/src/ortho/mcode/disa_x86.adb @@ -0,0 +1,997 @@ +-- X86 disassembler. +-- 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 System.Address_To_Access_Conversions; + +package body Disa_X86 is + type Byte is new Interfaces.Unsigned_8; + type Bf_2 is mod 2 ** 2; + type Bf_3 is mod 2 ** 3; + type Byte_Vector is array (Natural) of Byte; + package Bv_Addr2acc is new System.Address_To_Access_Conversions + (Object => Byte_Vector); + use Bv_Addr2acc; + + type Cstring_Acc is access constant String; + type Index_Type is + ( + N_None, + N_Push, + N_Pop, + N_Ret, + N_Mov, + N_Add, + N_Or, + N_Adc, + N_Sbb, + N_And, + N_Sub, + N_Xor, + N_Cmp, + N_Into, + N_Jmp, + N_Jcc, + N_Setcc, + N_Call, + N_Int, + N_Cdq, + N_Imul, + N_Mul, + N_Leave, + N_Test, + N_Lea, + N_O, + N_No, + N_B, + N_AE, + N_E, + N_Ne, + N_Be, + N_A, + N_S, + N_Ns, + N_P, + N_Np, + N_L, + N_Ge, + N_Le, + N_G, + N_Not, + N_Neg, + N_Cbw, + N_Div, + N_Idiv, + N_Movsx, + N_Movzx, + N_Nop, + N_Hlt, + N_Inc, + N_Dec, + N_Rol, + N_Ror, + N_Rcl, + N_Rcr, + N_Shl, + N_Shr, + N_Sar, + N_Fadd, + N_Fmul, + N_Fcom, + N_Fcomp, + N_Fsub, + N_Fsubr, + N_Fdiv, + N_Fdivr, + + G_1, + G_2, + G_3, + G_5 + ); + + type Names_Type is array (Index_Type range <>) of Cstring_Acc; + subtype S is String; + Names : constant Names_Type := + (N_None => new S'("none"), + N_Push => new S'("push"), + N_Pop => new S'("pop"), + N_Ret => new S'("ret"), + N_Mov => new S'("mov"), + N_Add => new S'("add"), + N_Or => new S'("or"), + N_Adc => new S'("adc"), + N_Sbb => new S'("sbb"), + N_And => new S'("and"), + N_Sub => new S'("sub"), + N_Xor => new S'("xor"), + N_Cmp => new S'("cmp"), + N_Into => new S'("into"), + N_Jmp => new S'("jmp"), + N_Jcc => new S'("j"), + N_Int => new S'("int"), + N_Cdq => new S'("cdq"), + N_Call => new S'("call"), + N_Imul => new S'("imul"), + N_Mul => new S'("mul"), + N_Leave => new S'("leave"), + N_Test => new S'("test"), + N_Setcc => new S'("set"), + N_Lea => new S'("lea"), + N_O => new S'("o"), + N_No => new S'("no"), + N_B => new S'("b"), + N_AE => new S'("ae"), + N_E => new S'("e"), + N_Ne => new S'("ne"), + N_Be => new S'("be"), + N_A => new S'("a"), + N_S => new S'("s"), + N_Ns => new S'("ns"), + N_P => new S'("p"), + N_Np => new S'("np"), + N_L => new S'("l"), + N_Ge => new S'("ge"), + N_Le => new S'("le"), + N_G => new S'("g"), + N_Not => new S'("not"), + N_Neg => new S'("neg"), + N_Cbw => new S'("cbw"), + N_Div => new S'("div"), + N_Idiv => new S'("idiv"), + N_Movsx => new S'("movsx"), + N_Movzx => new S'("movzx"), + N_Nop => new S'("nop"), + N_Hlt => new S'("hlt"), + N_Inc => new S'("inc"), + N_Dec => new S'("dec"), + N_Rol => new S'("rol"), + N_Ror => new S'("ror"), + N_Rcl => new S'("rcl"), + N_Rcr => new S'("rcr"), + N_Shl => new S'("shl"), + N_Shr => new S'("shr"), + N_Sar => new S'("sar"), + N_Fadd => new S'("fadd"), + N_Fmul => new S'("fmul"), + N_Fcom => new S'("fcom"), + N_Fcomp => new S'("fcomp"), + N_Fsub => new S'("fsub"), + N_Fsubr => new S'("fsubr"), + N_Fdiv => new S'("fdiv"), + N_Fdivr => new S'("fdivr") + ); + + + + -- Format of an instruction. + -- MODRM_SRC_8 : modrm byte follow, and modrm is source, witdh = 8bits + -- MODRM_DST_8 : modrm byte follow, and modrm is dest, width = 8 bits. + -- MODRM_SRC_W : modrm byte follow, and modrm is source, width = 16/32 bits + -- MODRM_DST_W : modrm byte follow, and modrm is dest, width =16/32 bits. + -- MODRM_IMM_W : modrm byte follow, with an opcode in the reg field, + -- followed by an immediat, width = 16/32 bits. + -- MODRM_IMM_8 : modrm byte follow, with an opcode in the reg field, + -- followed by an immediat, width = 8 bits. + -- IMM : the opcode is followed by an immediate value. + -- PREFIX : the opcode is a prefix (1 byte). + -- OPCODE : inherent addressing. + -- OPCODE2 : a second byte specify the instruction. + -- REG_IMP : register is in the 3 LSB of the opcode. + -- REG_IMM_W : register is in the 3 LSB of the opcode, followed by an + -- immediat, width = 16/32 bits. + -- DISP_W : a wide displacement (16/32 bits). + -- DISP_8 : short displacement (8 bits). + -- INVALID : bad opcode. + type Format_Type is (Modrm_Src, Modrm_Dst, + Modrm_Imm, Modrm_Imm_S, + Modrm, + Modrm_Ax, + Modrm_Imm8, + Imm, Imm_S, Imm_8, + Eax_Imm, + Prefix, Opcode, Opcode2, Reg_Imp, + Reg_Imm, + Imp, + Disp_W, Disp_8, + Cond_Disp_W, Cond_Disp_8, + Cond_Modrm, + Ax_Off_Src, Ax_Off_Dst, + Invalid); + + type Width_Type is (W_None, W_8, W_16, W_32, W_Data); + + -- Description for one instruction. + type Insn_Desc_Type is record + -- Name of the operation. + Name : Index_Type; + + -- Width of the instruction. + -- This is used to add a suffix (b,w,l) to the instruction. + -- This may also be the size of a data. + Width : Width_Type; + + -- Format of the instruction. + Format : Format_Type; + end record; + + Desc_Invalid : constant Insn_Desc_Type := (N_None, W_None, Invalid); + + type Insn_Desc_Array_Type is array (Byte) of Insn_Desc_Type; + type Group_Desc_Array_Type is array (Bf_3) of Insn_Desc_Type; + Insn_Desc : constant Insn_Desc_Array_Type := + ( + 2#00_000_000# => (N_Add, W_8, Modrm_Dst), + 2#00_000_001# => (N_Add, W_Data, Modrm_Dst), + 2#00_000_010# => (N_Add, W_8, Modrm_Src), + 2#00_000_011# => (N_Add, W_Data, Modrm_Src), + + 2#00_001_000# => (N_Or, W_8, Modrm_Dst), + 2#00_001_001# => (N_Or, W_Data, Modrm_Dst), + 2#00_001_010# => (N_Or, W_8, Modrm_Src), + 2#00_001_011# => (N_Or, W_Data, Modrm_Src), + + 2#00_011_000# => (N_Sbb, W_8, Modrm_Dst), + 2#00_011_001# => (N_Sbb, W_Data, Modrm_Dst), + 2#00_011_010# => (N_Sbb, W_8, Modrm_Src), + 2#00_011_011# => (N_Sbb, W_Data, Modrm_Src), + + 2#00_100_000# => (N_And, W_8, Modrm_Dst), + 2#00_100_001# => (N_And, W_Data, Modrm_Dst), + 2#00_100_010# => (N_And, W_8, Modrm_Src), + 2#00_100_011# => (N_And, W_Data, Modrm_Src), + + 2#00_101_000# => (N_Sub, W_8, Modrm_Dst), + 2#00_101_001# => (N_Sub, W_Data, Modrm_Dst), + 2#00_101_010# => (N_Sub, W_8, Modrm_Src), + 2#00_101_011# => (N_Sub, W_Data, Modrm_Src), + + 2#00_110_000# => (N_Xor, W_8, Modrm_Dst), + 2#00_110_001# => (N_Xor, W_Data, Modrm_Dst), + 2#00_110_010# => (N_Xor, W_8, Modrm_Src), + 2#00_110_011# => (N_Xor, W_Data, Modrm_Src), + + 2#00_111_000# => (N_Cmp, W_8, Modrm_Dst), + 2#00_111_001# => (N_Cmp, W_Data, Modrm_Dst), + 2#00_111_010# => (N_Cmp, W_8, Modrm_Src), + 2#00_111_011# => (N_Cmp, W_Data, Modrm_Src), + + 2#00_111_100# => (N_Cmp, W_8, Eax_Imm), + 2#00_111_101# => (N_Cmp, W_Data, Eax_Imm), + + 2#0101_0_000# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_001# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_010# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_011# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_100# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_101# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_110# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_111# => (N_Push, W_Data, Reg_Imp), + + 2#0101_1_000# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_001# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_010# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_011# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_100# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_101# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_110# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_111# => (N_Pop, W_Data, Reg_Imp), + + 2#0110_1000# => (N_Push, W_Data, Imm), + 2#0110_1010# => (N_Push, W_Data, Imm_S), + + 2#0111_0000# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0001# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0010# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0011# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0100# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0101# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0110# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0111# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1000# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1001# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1010# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1011# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1100# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1101# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1110# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1111# => (N_Jcc, W_None, Cond_Disp_8), + + 2#1000_0000# => (G_1, W_8, Modrm_Imm), + 2#1000_0001# => (G_1, W_Data, Modrm_Imm), + 2#1000_0011# => (G_1, W_Data, Modrm_Imm_S), + + 2#1000_0101# => (N_Test, W_Data, Modrm_Src), + 2#1000_1101# => (N_Lea, W_Data, Modrm_Src), + + 2#1000_1010# => (N_Mov, W_8, Modrm_Src), + 2#1000_1011# => (N_Mov, W_Data, Modrm_Src), + 2#1000_1000# => (N_Mov, W_8, Modrm_Dst), + 2#1000_1001# => (N_Mov, W_Data, Modrm_Dst), + + 2#1001_0000# => (N_Nop, W_None, Opcode), + 2#1001_1001# => (N_Cdq, W_Data, Imp), + + 2#1010_0000# => (N_Mov, W_8, Ax_Off_Src), + 2#1010_0001# => (N_Mov, W_Data, Ax_Off_Src), + 2#1010_0010# => (N_Mov, W_8, Ax_Off_Dst), + 2#1010_0011# => (N_Mov, W_Data, Ax_Off_Dst), + + 2#1011_0000# => (N_Mov, W_8, Reg_Imm), + + 2#1011_1000# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1001# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1010# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1011# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1100# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1101# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1110# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1111# => (N_Mov, W_Data, Reg_Imm), + + 2#1100_0000# => (G_2, W_8, Modrm_Imm8), + 2#1100_0001# => (G_2, W_Data, Modrm_Imm8), + + 2#1100_0011# => (N_Ret, W_None, Opcode), + 2#1100_0110# => (N_Mov, W_8, Modrm_Imm), + 2#1100_0111# => (N_Mov, W_Data, Modrm_Imm), + 2#1100_1001# => (N_Leave, W_None, Opcode), + 2#1100_1101# => (N_Int, W_None, Imm_8), + 2#1100_1110# => (N_Into, W_None, Opcode), + + 2#1110_1000# => (N_Call, W_None, Disp_W), + 2#1110_1001# => (N_Jmp, W_None, Disp_W), + 2#1110_1011# => (N_Jmp, W_None, Disp_8), + + 2#1111_0100# => (N_Hlt, W_None, Opcode), + + 2#1111_0110# => (G_3, W_None, Invalid), + 2#1111_0111# => (G_3, W_None, Invalid), + + 2#1111_1111# => (G_5, W_None, Invalid), + --2#1111_1111# => (N_Push, W_Data, Modrm), + others => (N_None, W_None, Invalid)); + + Insn_Desc_0F : constant Insn_Desc_Array_Type := + (2#1000_0000# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0001# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0010# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0011# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0100# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0101# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0110# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0111# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1000# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1001# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1010# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1011# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1100# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1101# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1110# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1111# => (N_Jcc, W_None, Cond_Disp_W), + + 2#1001_0000# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0001# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0010# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0011# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0100# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0101# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0110# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0111# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1000# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1001# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1010# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1011# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1100# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1101# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1110# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1111# => (N_Setcc, W_8, Cond_Modrm), + + 2#1011_0110# => (N_Movzx, W_Data, Modrm_Dst), + 2#1011_1110# => (N_Movsx, W_Data, Modrm_Dst), + others => (N_None, W_None, Invalid)); + + -- 16#F7# + Insn_Desc_G3 : constant Group_Desc_Array_Type := + (2#000# => (N_Test, W_Data, Reg_Imm), + 2#010# => (N_Not, W_Data, Modrm_Dst), + 2#011# => (N_Neg, W_Data, Modrm_Dst), + 2#100# => (N_Mul, W_Data, Modrm_Ax), + 2#101# => (N_Imul, W_Data, Modrm_Ax), + 2#110# => (N_Div, W_Data, Modrm_Ax), + 2#111# => (N_Idiv, W_Data, Modrm_Ax), + others => (N_None, W_None, Invalid)); + + Insn_Desc_G5 : constant Group_Desc_Array_Type := + (2#000# => (N_Inc, W_Data, Modrm), + 2#001# => (N_Dec, W_Data, Modrm), + 2#010# => (N_Call, W_Data, Modrm), + --2#011# => (N_Call, W_Data, Modrm_Ax), + 2#100# => (N_Jmp, W_Data, Modrm), + --2#101# => (N_Jmp, W_Data, Modrm_Ax), + 2#110# => (N_Push, W_Data, Modrm_Ax), + others => (N_None, W_None, Invalid)); + + type Group_Name_Array_Type is array (Index_Type range G_1 .. G_2, Bf_3) + of Index_Type; + Group_Name : constant Group_Name_Array_Type := + ( + G_1 => (N_Add, N_Or, N_Adc, N_Sbb, N_And, N_Sub, N_Xor, N_Cmp), + G_2 => (N_Rol, N_Ror, N_Rcl, N_Rcr, N_Shl, N_Shr, N_None, N_Sar) + ); + + -- Standard widths of operations. + type Width_Array_Type is array (Width_Type) of Character; + Width_Char : constant Width_Array_Type := + (W_None => '-', W_8 => 'b', W_16 => 'w', W_32 => 'l', W_Data => '?'); + type Width_Len_Type is array (Width_Type) of Natural; + Width_Len : constant Width_Len_Type := + (W_None => 0, W_8 => 1, W_16 => 2, W_32 => 4, W_Data => 0); + + -- Registers. +-- type Reg_Type is (Reg_Ax, Reg_Bx, Reg_Cx, Reg_Dx, +-- Reg_Bp, Reg_Sp, Reg_Si, Reg_Di, +-- Reg_Al, Reg_Ah, Reg_Bl, Reg_Bh, +-- Reg_Cl, Reg_Ch, Reg_Dl, Reg_Dh); + + -- Bits extraction from byte functions. + -- For a byte, MSB (most significant bit) is bit 7 while + -- LSB (least significant bit) is bit 0. + + -- Extract bits 2, 1 and 0. + function Ext_210 (B : Byte) return Bf_3; + pragma Inline (Ext_210); + + -- Extract bits 5-3 of byte B. + function Ext_543 (B : Byte) return Bf_3; + pragma Inline (Ext_543); + + -- Extract bits 7-6 of byte B. + function Ext_76 (B : Byte) return Bf_2; + pragma Inline (Ext_76); + + function Ext_210 (B : Byte) return Bf_3 is + begin + return Bf_3 (B and 2#111#); + end Ext_210; + + function Ext_543 (B : Byte) return Bf_3 is + begin + return Bf_3 (Shift_Right (B, 3) and 2#111#); + end Ext_543; + + function Ext_76 (B : Byte) return Bf_2 is + begin + return Bf_2 (Shift_Right (B, 6) and 2#11#); + end Ext_76; + + function Ext_Modrm_Mod (B : Byte) return Bf_2 renames Ext_76; + function Ext_Modrm_Rm (B : Byte) return Bf_3 renames Ext_210; + function Ext_Modrm_Reg (B : Byte) return Bf_3 renames Ext_543; + function Ext_Sib_Base (B : Byte) return Bf_3 renames Ext_210; + function Ext_Sib_Index (B : Byte) return Bf_3 renames Ext_543; + function Ext_Sib_Scale (B : Byte) return Bf_2 renames Ext_76; + + procedure Disassemble_Insn (Addr : System.Address; + Pc : Unsigned_32; + Line : in out String; + Line_Len : out Natural; + Insn_Len : out Natural; + Proc_Cb : Symbol_Proc_Type) + is + -- Index in LINE of the next character to be written. + Lo : Natural; + + -- Default width. + W_Default : constant Width_Type := W_32; + + -- The instruction memory, 0 based. + Mem : Bv_Addr2acc.Object_Pointer; + + -- Add NAME to the line. + procedure Add_Name (Name : Index_Type); + pragma Inline (Add_Name); + + -- Add CHAR to the line. + procedure Add_Char (C : Character); + pragma Inline (Add_Char); + + -- Add STR to the line. + procedure Add_String (Str : String) is + begin + Line (Lo .. Lo + Str'Length - 1) := Str; + Lo := Lo + Str'Length; + end Add_String; + + -- Add BYTE to the line. + procedure Add_Byte (V : Byte) is + type My_Str is array (Natural range 0 .. 15) of Character; + Hex_Digit : constant My_Str := "0123456789abcdef"; + begin + Add_Char (Hex_Digit (Natural (Shift_Right (V, 4) and 16#0f#))); + Add_Char (Hex_Digit (Natural (Shift_Right (V, 0) and 16#0f#))); + end Add_Byte; + + procedure Add_Name (Name : Index_Type) is + begin + Add_String (Names (Name).all); + end Add_Name; + + procedure Add_Char (C : Character) is + begin + Line (Lo) := C; + Lo := Lo + 1; + end Add_Char; + + procedure Add_Comma is + begin + Add_String (", "); + end Add_Comma; + + procedure Name_Align (Orig : Natural) is + begin + Add_Char (' '); + while Lo - Orig < 8 loop + Add_Char (' '); + end loop; + end Name_Align; + + procedure Add_Opcode (Name : Index_Type; Width : Width_Type) + is + L : constant Natural := Lo; + begin + Add_Name (Name); + if False and Width /= W_None then + Add_Char (Width_Char (Width)); + end if; + Name_Align (L); + end Add_Opcode; + + procedure Add_Cond_Opcode (Name : Index_Type; B : Byte) + is + L : constant Natural := Lo; + begin + Add_Name (Name); + Add_Name (Index_Type'Val (Index_Type'Pos (N_O) + + Byte'Pos (B and 16#0f#))); + Name_Align (L); + end Add_Cond_Opcode; + + procedure Decode_Reg_Field (F : Bf_3; W : Width_Type) is + type Reg_Name2_Array is array (Bf_3) of String (1 .. 2); + type Reg_Name3_Array is array (Bf_3) of String (1 .. 3); + Regs_8 : constant Reg_Name2_Array := + ("al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"); + Regs_16 : constant Reg_Name2_Array := + ("ax", "cx", "dx", "bx", "sp", "bp", "si", "di"); + Regs_32 : constant Reg_Name3_Array := + ("eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"); + begin + Add_Char ('%'); + case W is + when W_8 => + Add_String (Regs_8 (F)); + when W_16 => + Add_String (Regs_16 (F)); + when W_32 => + Add_String (Regs_32 (F)); + when W_None + | W_Data => + raise Program_Error; + end case; + end Decode_Reg_Field; + + procedure Decode_Val (Off : Natural; Width : Width_Type) + is + begin + case Width is + when W_8 => + Add_Byte (Mem (Off)); + when W_16 => + Add_Byte (Mem (Off + 1)); + Add_Byte (Mem (Off)); + when W_32 => + Add_Byte (Mem (Off + 3)); + Add_Byte (Mem (Off + 2)); + Add_Byte (Mem (Off + 1)); + Add_Byte (Mem (Off + 0)); + when W_None + | W_Data => + raise Program_Error; + end case; + end Decode_Val; + + function Decode_Val (Off : Natural; Width : Width_Type) + return Unsigned_32 + is + V : Unsigned_32; + begin + case Width is + when W_8 => + V := Unsigned_32 (Mem (Off)); + -- Sign extension. + if V >= 16#80# then + V := 16#Ffff_Ff00# or V; + end if; + return V; + when W_16 => + return Shift_Left (Unsigned_32 (Mem (Off + 1)), 8) + or Unsigned_32 (Mem (Off)); + when W_32 => + return Shift_Left (Unsigned_32 (Mem (Off + 3)), 24) + or Shift_Left (Unsigned_32 (Mem (Off + 2)), 16) + or Shift_Left (Unsigned_32 (Mem (Off + 1)), 8) + or Shift_Left (Unsigned_32 (Mem (Off + 0)), 0); + when W_None + | W_Data => + raise Program_Error; + end case; + end Decode_Val; + + procedure Decode_Imm (Off : in out Natural; Width : Width_Type) + is + begin + Add_String ("$0x"); + Decode_Val (Off, Width); + Off := Off + Width_Len (Width); + end Decode_Imm; + + procedure Decode_Disp (Off : in out Natural; + Width : Width_Type; + Offset : Unsigned_32 := 0) + is + L : Natural; + V : Unsigned_32; + Off_Orig : constant Natural := Off; + begin + L := Lo; + V := Decode_Val (Off, Width) + Offset; + Off := Off + Width_Len (Width); + if Proc_Cb /= null then + Proc_Cb.all (Mem (Off)'Address, + Line (Lo .. Line'Last), Lo); + end if; + if L /= Lo then + if V = 0 then + return; + end if; + Add_String (" + "); + end if; + Add_String ("0x"); + if Offset = 0 then + Decode_Val (Off_Orig, Width); + else + Add_Byte (Byte (Shift_Right (V, 24) and 16#Ff#)); + Add_Byte (Byte (Shift_Right (V, 16) and 16#Ff#)); + Add_Byte (Byte (Shift_Right (V, 8) and 16#Ff#)); + Add_Byte (Byte (Shift_Right (V, 0) and 16#Ff#)); + end if; + end Decode_Disp; + + procedure Decode_Modrm_Reg (B : Byte; Width : Width_Type) is + begin + Decode_Reg_Field (Ext_Modrm_Reg (B), Width); + end Decode_Modrm_Reg; + + procedure Decode_Sib (Sib : Byte; B_Mod : Bf_2) + is + S : Bf_2; + I : Bf_3; + B : Bf_3; + begin + S := Ext_Sib_Scale (Sib); + B := Ext_Sib_Base (Sib); + I := Ext_Sib_Index (Sib); + Add_Char ('('); + if B = 2#101# and then B_Mod /= 0 then + Decode_Reg_Field (B, W_32); + Add_Char (','); + end if; + if I /= 2#100# then + Decode_Reg_Field (I, W_32); + case S is + when 2#00# => + null; + when 2#01# => + Add_String (",2"); + when 2#10# => + Add_String (",4"); + when 2#11# => + Add_String (",8"); + end case; + end if; + Add_Char (')'); + end Decode_Sib; + + procedure Decode_Modrm_Mem (Off : in out Natural; Width : Width_Type) + is + B : Byte; + B_Mod : Bf_2; + B_Rm : Bf_3; + Off_Orig : Natural; + begin + B := Mem (Off); + B_Mod := Ext_Modrm_Mod (B); + B_Rm := Ext_Modrm_Rm (B); + Off_Orig := Off; + case B_Mod is + when 2#11# => + Decode_Reg_Field (B_Rm, Width); + Off := Off + 1; + when 2#10# => + if B_Rm = 2#100# then + Off := Off + 2; + Decode_Disp (Off, W_32); + Decode_Sib (Mem (Off_Orig + 1), B_Mod); + else + Off := Off + 1; + Decode_Disp (Off, W_32); + Add_Char ('('); + Decode_Reg_Field (B_Rm, W_32); + Add_Char (')'); + end if; + when 2#01# => + if B_Rm = 2#100# then + Off := Off + 2; + Decode_Disp (Off, W_8); + Decode_Sib (Mem (Off_Orig + 1), B_Mod); + else + Off := Off + 1; + Decode_Disp (Off, W_8); + Add_Char ('('); + Decode_Reg_Field (B_Rm, W_32); + Add_Char (')'); + end if; + when 2#00# => + if B_Rm = 2#100# then + Off := Off + 2; + Decode_Sib (Mem (Off_Orig + 1), B_Mod); + elsif B_Rm = 2#101# then + Off := Off + 1; + Decode_Disp (Off, W_32); + else + Add_Char ('('); + Decode_Reg_Field (B_Rm, W_32); + Add_Char (')'); + Off := Off + 1; + end if; + end case; + end Decode_Modrm_Mem; + + -- Return the length of the modrm bytes. + -- At least 1 (mod/rm), at most 6 (mod/rm + SUB + disp32). + function Decode_Modrm_Len (Off : Natural) return Natural + is + B : Byte; + M_Mod : Bf_2; + M_Rm : Bf_3; + begin + B := Mem (Off); + M_Mod := Ext_Modrm_Mod (B); + M_Rm := Ext_Modrm_Rm (B); + case M_Mod is + when 2#11# => + return 1; + when 2#10# => + if M_Rm = 2#100# then + return 1 + 1 + 4; + else + return 1 + 4; + end if; + when 2#01# => + if M_Rm = 2#100# then + return 1 + 1 + 1; + else + return 1 + 1; + end if; + when 2#00# => + if M_Rm = 2#101# then + -- disp32. + return 1 + 4; + elsif M_Rm = 2#100# then + -- SIB + return 1 + 1; + else + return 1; + end if; + end case; + end Decode_Modrm_Len; + + + Off : Natural; + B : Byte; + B1 : Byte; + Desc : Insn_Desc_Type; + Name : Index_Type; + W : Width_Type; + begin + Mem := To_Pointer (Addr); + Off := 0; + Lo := Line'First; + + B := Mem (0); + if B = 2#0000_1111# then + B := Mem (1); + Off := 2; + Insn_Len := 2; + Desc := Insn_Desc_0F (B); + else + Off := 1; + Insn_Len := 1; + Desc := Insn_Desc (B); + end if; + + if Desc.Name >= G_1 then + B1 := Mem (Off); + case Desc.Name is + when G_1 + | G_2 => + Name := Group_Name (Desc.Name, Ext_543 (B1)); + when G_3 => + Desc := Insn_Desc_G3 (Ext_543 (B1)); + Name := Desc.Name; + when G_5 => + Desc := Insn_Desc_G5 (Ext_543 (B1)); + Name := Desc.Name; + when others => + Desc := Desc_Invalid; + end case; + else + Name := Desc.Name; + end if; + + case Desc.Width is + when W_Data => + W := W_Default; + when W_8 + | W_16 + | W_32 => + W := Desc.Width; + when W_None => + case Desc.Format is + when Disp_8 + | Cond_Disp_8 + | Imm_8 => + W := W_8; + when Disp_W + | Cond_Disp_W => + W := W_Default; + when Invalid + | Opcode => + W := W_None; + when others => + raise Program_Error; + end case; + end case; + + case Desc.Format is + when Reg_Imp => + Add_Opcode (Desc.Name, W_Default); + Decode_Reg_Field (Ext_210 (B), W_Default); + when Opcode => + Add_Opcode (Desc.Name, W_None); + when Modrm => + Add_Opcode (Desc.Name, W); + Decode_Modrm_Mem (Insn_Len, W); + when Modrm_Src => + Add_Opcode (Desc.Name, W); + -- Disp source first. + Decode_Modrm_Mem (Insn_Len, W); + Add_Comma; + B := Mem (Off); + Decode_Modrm_Reg (Mem (Off), W); + when Modrm_Dst => + Add_Opcode (Desc.Name, W); + -- Disp source first. + B := Mem (Off); + Decode_Modrm_Reg (B, W); + Add_Comma; + Decode_Modrm_Mem (Insn_Len, W); + when Modrm_Imm => + Add_Opcode (Name, W); + Insn_Len := Off + Decode_Modrm_Len (Off); + Decode_Imm (Insn_Len, W); + Add_Comma; + Decode_Modrm_Mem (Off, W); + when Modrm_Imm_S => + Add_Opcode (Name, W); + Insn_Len := Off + Decode_Modrm_Len (Off); + Decode_Imm (Insn_Len, W_8); + Add_Comma; + Decode_Modrm_Mem (Off, W); + when Modrm_Imm8 => + Add_Opcode (Name, W); + Decode_Modrm_Mem (Off, W); + Add_Comma; + Decode_Imm (Off, W_8); + + when Reg_Imm => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W); + Add_Comma; + Decode_Reg_Field (Ext_210 (B), W); + when Eax_Imm => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W); + Add_Comma; + Decode_Reg_Field (2#000#, W); + + when Disp_W + | Disp_8 => + Add_Opcode (Desc.Name, W_None); + Decode_Disp (Insn_Len, W, + Pc + Unsigned_32 (Insn_Len + Width_Len (W))); + + when Cond_Disp_8 + | Cond_Disp_W => + Add_Cond_Opcode (Desc.Name, B); + Decode_Disp (Insn_Len, W, + Pc + Unsigned_32 (Insn_Len + Width_Len (W))); + + when Cond_Modrm => + Add_Cond_Opcode (Desc.Name, B); + Decode_Modrm_Mem (Insn_Len, W); + + when Imm => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W); + + when Imm_S + | Imm_8 => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W_8); + + when Modrm_Ax => + if (B and 2#1#) = 2#0# then + W := W_8; + else + W := W_Default; + end if; + Add_Opcode (Desc.Name, W); + Decode_Reg_Field (0, W); + Add_Comma; + Decode_Modrm_Mem (Off, W); + + when Ax_Off_Src => + Add_Opcode (Desc.Name, W); + Decode_Disp (Insn_Len, W); + Add_Comma; + Decode_Reg_Field (0, W); + + when Ax_Off_Dst => + Add_Opcode (Desc.Name, W); + Decode_Reg_Field (0, W); + Add_Comma; + Decode_Disp (Insn_Len, W); + + when Imp => + Add_Opcode (Desc.Name, W_Default); + + when Invalid + | Prefix + | Opcode2 => + Add_String ("invalid "); + if Insn_Len = 2 then + Add_Byte (Mem (0)); + end if; + Add_Byte (B); + Insn_Len := 1; + end case; + + Line_Len := Lo - Line'First; + end Disassemble_Insn; +end Disa_X86; + + diff --git a/src/ortho/mcode/disa_x86.ads b/src/ortho/mcode/disa_x86.ads new file mode 100644 index 000000000..c215cf0a3 --- /dev/null +++ b/src/ortho/mcode/disa_x86.ads @@ -0,0 +1,34 @@ +-- X86 disassembler. +-- 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 System; +with Interfaces; use Interfaces; + +package Disa_X86 is + -- Call-back used to find a relocation symbol. + type Symbol_Proc_Type is access procedure (Addr : System.Address; + Line : in out String; + Line_Len : in out Natural); + + -- Disassemble instruction at ADDR, and put the result in LINE/LINE_LEN. + procedure Disassemble_Insn (Addr : System.Address; + Pc : Unsigned_32; + Line : in out String; + Line_Len : out Natural; + Insn_Len : out Natural; + Proc_Cb : Symbol_Proc_Type); +end Disa_X86; diff --git a/src/ortho/mcode/disassemble.ads b/src/ortho/mcode/disassemble.ads new file mode 100644 index 000000000..5c9811fed --- /dev/null +++ b/src/ortho/mcode/disassemble.ads @@ -0,0 +1,3 @@ +with Disa_X86; + +package Disassemble renames Disa_X86; diff --git a/src/ortho/mcode/dwarf.ads b/src/ortho/mcode/dwarf.ads new file mode 100644 index 000000000..40ee94f10 --- /dev/null +++ b/src/ortho/mcode/dwarf.ads @@ -0,0 +1,446 @@ +-- DWARF definitions. +-- 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 Interfaces; use Interfaces; + +package Dwarf is + DW_TAG_Array_Type : constant := 16#01#; + DW_TAG_Class_Type : constant := 16#02#; + DW_TAG_Entry_Point : constant := 16#03#; + DW_TAG_Enumeration_Type : constant := 16#04#; + DW_TAG_Formal_Parameter : constant := 16#05#; + DW_TAG_Imported_Declaration : constant := 16#08#; + DW_TAG_Label : constant := 16#0a#; + DW_TAG_Lexical_Block : constant := 16#0b#; + DW_TAG_Member : constant := 16#0d#; + DW_TAG_Pointer_Type : constant := 16#0f#; + DW_TAG_Reference_Type : constant := 16#10#; + DW_TAG_Compile_Unit : constant := 16#11#; + DW_TAG_String_Type : constant := 16#12#; + DW_TAG_Structure_Type : constant := 16#13#; + DW_TAG_Subroutine_Type : constant := 16#15#; + DW_TAG_Typedef : constant := 16#16#; + DW_TAG_Union_Type : constant := 16#17#; + DW_TAG_Unspecified_Parameters : constant := 16#18#; + DW_TAG_Variant : constant := 16#19#; + DW_TAG_Common_Block : constant := 16#1a#; + DW_TAG_Common_Inclusion : constant := 16#1b#; + DW_TAG_Inheritance : constant := 16#1c#; + DW_TAG_Inlined_Subroutine : constant := 16#1d#; + DW_TAG_Module : constant := 16#1e#; + DW_TAG_Ptr_To_Member_Type : constant := 16#1f#; + DW_TAG_Set_Type : constant := 16#20#; + DW_TAG_Subrange_Type : constant := 16#21#; + DW_TAG_With_Stmt : constant := 16#22#; + DW_TAG_Access_Declaration : constant := 16#23#; + DW_TAG_Base_Type : constant := 16#24#; + DW_TAG_Catch_Block : constant := 16#25#; + DW_TAG_Const_Type : constant := 16#26#; + DW_TAG_Constant : constant := 16#27#; + DW_TAG_Enumerator : constant := 16#28#; + DW_TAG_File_Type : constant := 16#29#; + DW_TAG_Friend : constant := 16#2a#; + DW_TAG_Namelist : constant := 16#2b#; + DW_TAG_Namelist_Item : constant := 16#2c#; + DW_TAG_Packed_Type : constant := 16#2d#; + DW_TAG_Subprogram : constant := 16#2e#; + DW_TAG_Template_Type_Parameter : constant := 16#2f#; + DW_TAG_Template_Value_Parameter : constant := 16#30#; + DW_TAG_Thrown_Type : constant := 16#31#; + DW_TAG_Try_Block : constant := 16#32#; + DW_TAG_Variant_Part : constant := 16#33#; + DW_TAG_Variable : constant := 16#34#; + DW_TAG_Volatile_Type : constant := 16#35#; + DW_TAG_Dwarf_Procedure : constant := 16#36#; + DW_TAG_Restrict_Type : constant := 16#37#; + DW_TAG_Interface_Type : constant := 16#38#; + DW_TAG_Namespace : constant := 16#39#; + DW_TAG_Imported_Module : constant := 16#3a#; + DW_TAG_Unspecified_Type : constant := 16#3b#; + DW_TAG_Partial_Unit : constant := 16#3c#; + DW_TAG_Imported_Unit : constant := 16#3d#; + DW_TAG_Mutable_Type : constant := 16#3e#; + DW_TAG_Lo_User : constant := 16#4080#; + DW_TAG_Hi_User : constant := 16#Ffff#; + + DW_CHILDREN_No : constant := 16#0#; + DW_CHILDREN_Yes : constant := 16#1#; + + DW_AT_Sibling : constant := 16#01#; -- reference + DW_AT_Location : constant := 16#02#; -- block, loclistptr + DW_AT_Name : constant := 16#03#; -- string + DW_AT_Ordering : constant := 16#09#; -- constant + DW_AT_Byte_Size : constant := 16#0b#; -- block, constant, ref + DW_AT_Bit_Offset : constant := 16#0c#; -- block, constant, ref + DW_AT_Bit_Size : constant := 16#0d#; -- block, constant, ref + DW_AT_Stmt_List : constant := 16#10#; -- lineptr + DW_AT_Low_Pc : constant := 16#11#; -- address + DW_AT_High_Pc : constant := 16#12#; -- address + DW_AT_Language : constant := 16#13#; -- constant + DW_AT_Discr : constant := 16#15#; -- reference + DW_AT_Discr_Value : constant := 16#16#; -- constant + DW_AT_Visibility : constant := 16#17#; -- constant + DW_AT_Import : constant := 16#18#; -- reference + DW_AT_String_Length : constant := 16#19#; -- block, loclistptr + DW_AT_Common_Reference : constant := 16#1a#; -- reference + DW_AT_Comp_Dir : constant := 16#1b#; -- string + DW_AT_Const_Value : constant := 16#1c#; -- block, constant, string + DW_AT_Containing_Type : constant := 16#1d#; -- reference + DW_AT_Default_Value : constant := 16#1e#; -- reference + DW_AT_Inline : constant := 16#20#; -- constant + DW_AT_Is_Optional : constant := 16#21#; -- flag + DW_AT_Lower_Bound : constant := 16#22#; -- block, constant, ref + DW_AT_Producer : constant := 16#25#; -- string + DW_AT_Prototyped : constant := 16#27#; -- flag + DW_AT_Return_Addr : constant := 16#2a#; -- block, loclistptr + DW_AT_Start_Scope : constant := 16#2c#; -- constant + DW_AT_Stride_Size : constant := 16#2e#; -- constant + DW_AT_Upper_Bound : constant := 16#2f#; -- block, constant, ref + DW_AT_Abstract_Origin : constant := 16#31#; -- reference + DW_AT_Accessibility : constant := 16#32#; -- constant + DW_AT_Address_Class : constant := 16#33#; -- constant + DW_AT_Artificial : constant := 16#34#; -- flag + DW_AT_Base_Types : constant := 16#35#; -- reference + DW_AT_Calling_Convention : constant := 16#36#; -- constant + DW_AT_Count : constant := 16#37#; -- block, constant, ref + DW_AT_Data_Member_Location : constant := 16#38#; -- block, const, loclistptr + DW_AT_Decl_Column : constant := 16#39#; -- constant + DW_AT_Decl_File : constant := 16#3a#; -- constant + DW_AT_Decl_Line : constant := 16#3b#; -- constant + DW_AT_Declaration : constant := 16#3c#; -- flag + DW_AT_Discr_List : constant := 16#3d#; -- block + DW_AT_Encoding : constant := 16#3e#; -- constant + DW_AT_External : constant := 16#3f#; -- flag + DW_AT_Frame_Base : constant := 16#40#; -- block, loclistptr + DW_AT_Friend : constant := 16#41#; -- reference + DW_AT_Identifier_Case : constant := 16#42#; -- constant + DW_AT_Macro_Info : constant := 16#43#; -- macptr + DW_AT_Namelist_Item : constant := 16#44#; -- block + DW_AT_Priority : constant := 16#45#; -- reference + DW_AT_Segment : constant := 16#46#; -- block, constant + DW_AT_Specification : constant := 16#47#; -- reference + DW_AT_Static_Link : constant := 16#48#; -- block, loclistptr + DW_AT_Type : constant := 16#49#; -- reference + DW_AT_Use_Location : constant := 16#4a#; -- block, loclistptr + DW_AT_Variable_Parameter : constant := 16#4b#; -- flag + DW_AT_Virtuality : constant := 16#4c#; -- constant + DW_AT_Vtable_Elem_Location : constant := 16#4d#; -- block, loclistptr + DW_AT_Allocated : constant := 16#4e#; -- block, constant, ref + DW_AT_Associated : constant := 16#4f#; -- block, constant, ref + DW_AT_Data_Location : constant := 16#50#; -- x50block + DW_AT_Stride : constant := 16#51#; -- block, constant, ref + DW_AT_Entry_Pc : constant := 16#52#; -- address + DW_AT_Use_UTF8 : constant := 16#53#; -- flag + DW_AT_Extension : constant := 16#04#; -- reference + DW_AT_Ranges : constant := 16#55#; -- rangelistptr + DW_AT_Trampoline : constant := 16#56#; -- address, flag, ref, str + DW_AT_Call_Column : constant := 16#57#; -- constant + DW_AT_Call_File : constant := 16#58#; -- constant + DW_AT_Call_Line : constant := 16#59#; -- constant + DW_AT_Description : constant := 16#5a#; -- string + DW_AT_Lo_User : constant := 16#2000#; -- --- + DW_AT_Hi_User : constant := 16#3fff#; -- --- + + DW_FORM_Addr : constant := 16#01#; -- address + DW_FORM_Block2 : constant := 16#03#; -- block + DW_FORM_Block4 : constant := 16#04#; -- block + DW_FORM_Data2 : constant := 16#05#; -- constant + DW_FORM_Data4 : constant := 16#06#; -- constant, lineptr, loclistptr... + DW_FORM_Data8 : constant := 16#07#; -- ... macptr, rangelistptr + DW_FORM_String : constant := 16#08#; -- string + DW_FORM_Block : constant := 16#09#; -- block + DW_FORM_Block1 : constant := 16#0a#; -- block + DW_FORM_Data1 : constant := 16#0b#; -- constant + DW_FORM_Flag : constant := 16#0c#; -- flag + DW_FORM_Sdata : constant := 16#0d#; -- constant + DW_FORM_Strp : constant := 16#0e#; -- string + DW_FORM_Udata : constant := 16#0f#; -- constant + DW_FORM_Ref_Addr : constant := 16#10#; -- reference + DW_FORM_Ref1 : constant := 16#11#; -- reference + DW_FORM_Ref2 : constant := 16#12#; -- reference + DW_FORM_Ref4 : constant := 16#13#; -- reference + DW_FORM_Ref8 : constant := 16#14#; -- reference + DW_FORM_Ref_Udata : constant := 16#15#; -- reference + DW_FORM_Indirect : constant := 16#16#; -- (see Section 7.5.3) + + + DW_OP_Addr : constant := 16#03#; -- 1 constant address (target spec) + DW_OP_Deref : constant := 16#06#; -- 0 + DW_OP_Const1u : constant := 16#08#; -- 1 1-byte constant + DW_OP_Const1s : constant := 16#09#; -- 1 1-byte constant + DW_OP_Const2u : constant := 16#0a#; -- 1 2-byte constant + DW_OP_Const2s : constant := 16#0b#; -- 1 2-byte constant + DW_OP_Const4u : constant := 16#0c#; -- 1 4-byte constant + DW_OP_Const4s : constant := 16#0d#; -- 1 4-byte constant + DW_OP_Const8u : constant := 16#0e#; -- 1 8-byte constant + DW_OP_Const8s : constant := 16#0f#; -- 1 8-byte constant + DW_OP_Constu : constant := 16#10#; -- 1 ULEB128 constant + DW_OP_Consts : constant := 16#11#; -- 1 SLEB128 constant + DW_OP_Dup : constant := 16#12#; -- 0 + DW_OP_Drop : constant := 16#13#; -- 0 + DW_OP_Over : constant := 16#14#; -- 0 + DW_OP_Pick : constant := 16#15#; -- 1 1-byte stack index + DW_OP_Swap : constant := 16#16#; -- 0 + DW_OP_Rot : constant := 16#17#; -- 0 + DW_OP_Xderef : constant := 16#18#; -- 0 + DW_OP_Abs : constant := 16#19#; -- 0 + DW_OP_And : constant := 16#1a#; -- 0 + DW_OP_Div : constant := 16#1b#; -- 0 + DW_OP_Minus : constant := 16#1c#; -- 0 + DW_OP_Mod : constant := 16#1d#; -- 0 + DW_OP_Mul : constant := 16#1e#; -- 0 + DW_OP_Neg : constant := 16#1f#; -- 0 + DW_OP_Not : constant := 16#20#; -- 0 + DW_OP_Or : constant := 16#21#; -- 0 + DW_OP_Plus : constant := 16#22#; -- 0 + DW_OP_Plus_Uconst : constant := 16#23#; -- 1 ULEB128 addend + DW_OP_Shl : constant := 16#24#; -- 0 + DW_OP_Shr : constant := 16#25#; -- 0 + DW_OP_Shra : constant := 16#26#; -- 0 + DW_OP_Xor : constant := 16#27#; -- 0 + DW_OP_Skip : constant := 16#2f#; -- 1 signed 2-byte constant + DW_OP_Bra : constant := 16#28#; -- 1 signed 2-byte constant + DW_OP_Eq : constant := 16#29#; -- 0 + DW_OP_Ge : constant := 16#2a#; -- 0 + DW_OP_Gt : constant := 16#2b#; -- 0 + DW_OP_Le : constant := 16#2c#; -- 0 + DW_OP_Lt : constant := 16#2d#; -- 0 + DW_OP_Ne : constant := 16#2e#; -- 0 + DW_OP_Lit0 : constant := 16#30#; -- 0 + DW_OP_Lit1 : constant := 16#31#; -- 0 + DW_OP_Lit2 : constant := 16#32#; -- 0 + DW_OP_Lit3 : constant := 16#33#; -- 0 + DW_OP_Lit4 : constant := 16#34#; -- 0 + DW_OP_Lit5 : constant := 16#35#; -- 0 + DW_OP_Lit6 : constant := 16#36#; -- 0 + DW_OP_Lit7 : constant := 16#37#; -- 0 + DW_OP_Lit8 : constant := 16#38#; -- 0 + DW_OP_Lit9 : constant := 16#39#; -- 0 + DW_OP_Lit10 : constant := 16#3a#; -- 0 + DW_OP_Lit11 : constant := 16#3b#; -- 0 + DW_OP_Lit12 : constant := 16#3c#; -- 0 + DW_OP_Lit13 : constant := 16#3d#; -- 0 + DW_OP_Lit14 : constant := 16#3e#; -- 0 + DW_OP_Lit15 : constant := 16#3f#; -- 0 + DW_OP_Lit16 : constant := 16#40#; -- 0 + DW_OP_Lit17 : constant := 16#41#; -- 0 + DW_OP_Lit18 : constant := 16#42#; -- 0 + DW_OP_Lit19 : constant := 16#43#; -- 0 + DW_OP_Lit20 : constant := 16#44#; -- 0 + DW_OP_Lit21 : constant := 16#45#; -- 0 + DW_OP_Lit22 : constant := 16#46#; -- 0 + DW_OP_Lit23 : constant := 16#47#; -- 0 + DW_OP_Lit24 : constant := 16#48#; -- 0 + DW_OP_Lit25 : constant := 16#49#; -- 0 + DW_OP_Lit26 : constant := 16#4a#; -- 0 + DW_OP_Lit27 : constant := 16#4b#; -- 0 + DW_OP_Lit28 : constant := 16#4c#; -- 0 + DW_OP_Lit29 : constant := 16#4d#; -- 0 + DW_OP_Lit30 : constant := 16#4e#; -- 0 + DW_OP_Lit31 : constant := 16#4f#; -- 0 + DW_OP_Reg0 : constant := 16#50#; -- 0 + DW_OP_Reg1 : constant := 16#51#; -- 0 + DW_OP_Reg2 : constant := 16#52#; -- 0 + DW_OP_Reg3 : constant := 16#53#; -- 0 + DW_OP_Reg4 : constant := 16#54#; -- 0 + DW_OP_Reg5 : constant := 16#55#; -- 0 + DW_OP_Reg6 : constant := 16#56#; -- 0 + DW_OP_Reg7 : constant := 16#57#; -- 0 + DW_OP_Reg8 : constant := 16#58#; -- 0 + DW_OP_Reg9 : constant := 16#59#; -- 0 + DW_OP_Reg10 : constant := 16#5a#; -- 0 + DW_OP_Reg11 : constant := 16#5b#; -- 0 + DW_OP_Reg12 : constant := 16#5c#; -- 0 + DW_OP_Reg13 : constant := 16#5d#; -- 0 + DW_OP_Reg14 : constant := 16#5e#; -- 0 + DW_OP_Reg15 : constant := 16#5f#; -- 0 + DW_OP_Reg16 : constant := 16#60#; -- 0 + DW_OP_Reg17 : constant := 16#61#; -- 0 + DW_OP_Reg18 : constant := 16#62#; -- 0 + DW_OP_Reg19 : constant := 16#63#; -- 0 + DW_OP_Reg20 : constant := 16#64#; -- 0 + DW_OP_Reg21 : constant := 16#65#; -- 0 + DW_OP_Reg22 : constant := 16#66#; -- 0 + DW_OP_Reg23 : constant := 16#67#; -- 0 + DW_OP_Reg24 : constant := 16#68#; -- 0 + DW_OP_Reg25 : constant := 16#69#; -- 0 + DW_OP_Reg26 : constant := 16#6a#; -- 0 + DW_OP_Reg27 : constant := 16#6b#; -- 0 + DW_OP_Reg28 : constant := 16#6c#; -- 0 + DW_OP_Reg29 : constant := 16#6d#; -- 0 + DW_OP_Reg30 : constant := 16#6e#; -- 0 + DW_OP_Reg31 : constant := 16#6f#; -- 0 reg 0..31 + DW_OP_Breg0 : constant := 16#70#; -- 1 SLEB128 offset base reg + DW_OP_Breg1 : constant := 16#71#; -- 1 SLEB128 offset base reg + DW_OP_Breg2 : constant := 16#72#; -- 1 SLEB128 offset base reg + DW_OP_Breg3 : constant := 16#73#; -- 1 SLEB128 offset base reg + DW_OP_Breg4 : constant := 16#74#; -- 1 SLEB128 offset base reg + DW_OP_Breg5 : constant := 16#75#; -- 1 SLEB128 offset base reg + DW_OP_Breg6 : constant := 16#76#; -- 1 SLEB128 offset base reg + DW_OP_Breg7 : constant := 16#77#; -- 1 SLEB128 offset base reg + DW_OP_Breg8 : constant := 16#78#; -- 1 SLEB128 offset base reg + DW_OP_Breg9 : constant := 16#79#; -- 1 SLEB128 offset base reg + DW_OP_Breg10 : constant := 16#7a#; -- 1 SLEB128 offset base reg + DW_OP_Breg11 : constant := 16#7b#; -- 1 SLEB128 offset base reg + DW_OP_Breg12 : constant := 16#7c#; -- 1 SLEB128 offset base reg + DW_OP_Breg13 : constant := 16#7d#; -- 1 SLEB128 offset base reg + DW_OP_Breg14 : constant := 16#7e#; -- 1 SLEB128 offset base reg + DW_OP_Breg15 : constant := 16#7f#; -- 1 SLEB128 offset base reg + DW_OP_Breg16 : constant := 16#80#; -- 1 SLEB128 offset base reg + DW_OP_Breg17 : constant := 16#81#; -- 1 SLEB128 offset base reg + DW_OP_Breg18 : constant := 16#82#; -- 1 SLEB128 offset base reg + DW_OP_Breg19 : constant := 16#83#; -- 1 SLEB128 offset base reg + DW_OP_Breg20 : constant := 16#84#; -- 1 SLEB128 offset base reg + DW_OP_Breg21 : constant := 16#85#; -- 1 SLEB128 offset base reg + DW_OP_Breg22 : constant := 16#86#; -- 1 SLEB128 offset base reg + DW_OP_Breg23 : constant := 16#87#; -- 1 SLEB128 offset base reg + DW_OP_Breg24 : constant := 16#88#; -- 1 SLEB128 offset base reg + DW_OP_Breg25 : constant := 16#89#; -- 1 SLEB128 offset base reg + DW_OP_Breg26 : constant := 16#8a#; -- 1 SLEB128 offset base reg + DW_OP_Breg27 : constant := 16#8b#; -- 1 SLEB128 offset base reg + DW_OP_Breg28 : constant := 16#8c#; -- 1 SLEB128 offset base reg + DW_OP_Breg29 : constant := 16#8d#; -- 1 SLEB128 offset base reg + DW_OP_Breg30 : constant := 16#8e#; -- 1 SLEB128 offset base reg + DW_OP_Breg31 : constant := 16#8f#; -- 1 SLEB128 offset base reg 0..31 + DW_OP_Regx : constant := 16#90#; -- 1 ULEB128 register + DW_OP_Fbreg : constant := 16#91#; -- 1 SLEB128 offset + DW_OP_Bregx : constant := 16#92#; -- 2 ULEB128 reg + SLEB128 offset + DW_OP_Piece : constant := 16#93#; -- 1 ULEB128 size of piece addressed + DW_OP_Deref_Size : constant := 16#94#; -- 1 1-byte size of data retrieved + DW_OP_Xderef_Size : constant := 16#95#; -- 1 1-byte size of data retrieved + DW_OP_Nop : constant := 16#96#; -- 0 + DW_OP_Push_Object_Address : constant := 16#97#; -- 0 + DW_OP_Call2 : constant := 16#98#; -- 1 2-byte offset of DIE + DW_OP_Call4 : constant := 16#99#; -- 1 4-byte offset of DIE + DW_OP_Call_Ref : constant := 16#9a#; -- 1 4- or 8-byte offset of DIE + DW_OP_Lo_User : constant := 16#E0#; -- + DW_OP_Hi_User : constant := 16#ff#; -- + + DW_ATE_Address : constant := 16#1#; + DW_ATE_Boolean : constant := 16#2#; + DW_ATE_Complex_Float : constant := 16#3#; + DW_ATE_Float : constant := 16#4#; + DW_ATE_Signed : constant := 16#5#; + DW_ATE_Signed_Char : constant := 16#6#; + DW_ATE_Unsigned : constant := 16#7#; + DW_ATE_Unsigned_Char : constant := 16#8#; + DW_ATE_Imaginary_Float : constant := 16#9#; + DW_ATE_Lo_User : constant := 16#80#; + DW_ATE_Hi_User : constant := 16#ff#; + + DW_ACCESS_Public : constant := 1; + DW_ACCESS_Protected : constant := 2; + DW_ACCESS_Private : constant := 3; + + DW_LANG_C89 : constant := 16#0001#; + DW_LANG_C : constant := 16#0002#; + DW_LANG_Ada83 : constant := 16#0003#; + DW_LANG_C_Plus_Plus : constant := 16#0004#; + DW_LANG_Cobol74 : constant := 16#0005#; + DW_LANG_Cobol85 : constant := 16#0006#; + DW_LANG_Fortran77 : constant := 16#0007#; + DW_LANG_Fortran90 : constant := 16#0008#; + DW_LANG_Pascal83 : constant := 16#0009#; + DW_LANG_Modula2 : constant := 16#000a#; + DW_LANG_Java : constant := 16#000b#; + DW_LANG_C99 : constant := 16#000c#; + DW_LANG_Ada95 : constant := 16#000d#; + DW_LANG_Fortran95 : constant := 16#000e#; + DW_LANG_PLI : constant := 16#000f#; + DW_LANG_Lo_User : constant := 16#8000#; + DW_LANG_Hi_User : constant := 16#ffff#; + + DW_ID_Case_Sensitive : constant := 0; + DW_ID_Up_Case : constant := 1; + DW_ID_Down_Case : constant := 2; + DW_ID_Case_Insensitive : constant := 3; + + DW_CC_Normal : constant := 16#1#; + DW_CC_Program : constant := 16#2#; + DW_CC_Nocall : constant := 16#3#; + DW_CC_Lo_User : constant := 16#40#; + DW_CC_Hi_User : constant := 16#Ff#; + + DW_INL_Not_Inlined : constant := 0; + DW_INL_Inlined : constant := 1; + DW_INL_Declared_Not_Inlined : constant := 2; + DW_INL_Declared_Inlined : constant := 3; + + -- Line number information. + -- Line number standard opcode. + DW_LNS_Copy : constant Unsigned_8 := 1; + DW_LNS_Advance_Pc : constant Unsigned_8 := 2; + DW_LNS_Advance_Line : constant Unsigned_8 := 3; + DW_LNS_Set_File : constant Unsigned_8 := 4; + DW_LNS_Set_Column : constant Unsigned_8 := 5; + DW_LNS_Negate_Stmt : constant Unsigned_8 := 6; + DW_LNS_Set_Basic_Block : constant Unsigned_8 := 7; + DW_LNS_Const_Add_Pc : constant Unsigned_8 := 8; + DW_LNS_Fixed_Advance_Pc : constant Unsigned_8 := 9; + DW_LNS_Set_Prologue_End : constant Unsigned_8 := 10; + DW_LNS_Set_Epilogue_Begin : constant Unsigned_8 := 11; + DW_LNS_Set_Isa : constant Unsigned_8 := 12; + + -- Line number extended opcode. + DW_LNE_End_Sequence : constant Unsigned_8 := 1; + DW_LNE_Set_Address : constant Unsigned_8 := 2; + DW_LNE_Define_File : constant Unsigned_8 := 3; + DW_LNE_Lo_User : constant Unsigned_8 := 128; + DW_LNE_Hi_User : constant Unsigned_8 := 255; + + DW_CFA_Advance_Loc : constant Unsigned_8 := 16#40#; + DW_CFA_Advance_Loc_Min : constant Unsigned_8 := 16#40#; + DW_CFA_Advance_Loc_Max : constant Unsigned_8 := 16#7f#; + DW_CFA_Offset : constant Unsigned_8 := 16#80#; + DW_CFA_Offset_Min : constant Unsigned_8 := 16#80#; + DW_CFA_Offset_Max : constant Unsigned_8 := 16#Bf#; + DW_CFA_Restore : constant Unsigned_8 := 16#C0#; + DW_CFA_Restore_Min : constant Unsigned_8 := 16#C0#; + DW_CFA_Restore_Max : constant Unsigned_8 := 16#FF#; + DW_CFA_Nop : constant Unsigned_8 := 16#00#; + DW_CFA_Set_Loc : constant Unsigned_8 := 16#01#; + DW_CFA_Advance_Loc1 : constant Unsigned_8 := 16#02#; + DW_CFA_Advance_Loc2 : constant Unsigned_8 := 16#03#; + DW_CFA_Advance_Loc4 : constant Unsigned_8 := 16#04#; + DW_CFA_Offset_Extended : constant Unsigned_8 := 16#05#; + DW_CFA_Restore_Extended : constant Unsigned_8 := 16#06#; + DW_CFA_Undefined : constant Unsigned_8 := 16#07#; + DW_CFA_Same_Value : constant Unsigned_8 := 16#08#; + DW_CFA_Register : constant Unsigned_8 := 16#09#; + DW_CFA_Remember_State : constant Unsigned_8 := 16#0a#; + DW_CFA_Restore_State : constant Unsigned_8 := 16#0b#; + DW_CFA_Def_Cfa : constant Unsigned_8 := 16#0c#; + DW_CFA_Def_Cfa_Register : constant Unsigned_8 := 16#0d#; + DW_CFA_Def_Cfa_Offset : constant Unsigned_8 := 16#0e#; + DW_CFA_Def_Cfa_Expression : constant Unsigned_8 := 16#0f#; + + DW_EH_PE_Omit : constant Unsigned_8 := 16#Ff#; + DW_EH_PE_Uleb128 : constant Unsigned_8 := 16#01#; + DW_EH_PE_Udata2 : constant Unsigned_8 := 16#02#; + DW_EH_PE_Udata4 : constant Unsigned_8 := 16#03#; + DW_EH_PE_Udata8 : constant Unsigned_8 := 16#04#; + DW_EH_PE_Sleb128 : constant Unsigned_8 := 16#09#; + DW_EH_PE_Sdata2 : constant Unsigned_8 := 16#0A#; + DW_EH_PE_Sdata4 : constant Unsigned_8 := 16#0B#; + DW_EH_PE_Sdata8 : constant Unsigned_8 := 16#0C#; + DW_EH_PE_Absptr : constant Unsigned_8 := 16#00#; + DW_EH_PE_Pcrel : constant Unsigned_8 := 16#10#; + DW_EH_PE_Datarel : constant Unsigned_8 := 16#30#; + DW_EH_PE_Format_Mask : constant Unsigned_8 := 16#0f#; +end Dwarf; + + diff --git a/src/ortho/mcode/elf32.adb b/src/ortho/mcode/elf32.adb new file mode 100644 index 000000000..ef58fe64b --- /dev/null +++ b/src/ortho/mcode/elf32.adb @@ -0,0 +1,48 @@ +-- ELF32 definitions. +-- 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. +package body Elf32 is + function Elf32_St_Bind (Info : Elf32_Uchar) return Elf32_Uchar is + begin + return Shift_Right (Info, 4); + end Elf32_St_Bind; + + function Elf32_St_Type (Info : Elf32_Uchar) return Elf32_Uchar is + begin + return Info and 16#0F#; + end Elf32_St_Type; + + function Elf32_St_Info (B, T : Elf32_Uchar) return Elf32_Uchar is + begin + return Shift_Left (B, 4) or T; + end Elf32_St_Info; + + function Elf32_R_Sym (I : Elf32_Word) return Elf32_Word is + begin + return Shift_Right (I, 8); + end Elf32_R_Sym; + + function Elf32_R_Type (I : Elf32_Word) return Elf32_Word is + begin + return I and 16#Ff#; + end Elf32_R_Type; + + function Elf32_R_Info (S, T : Elf32_Word) return Elf32_Word is + begin + return Shift_Left (S, 8) or T; + end Elf32_R_Info; +end Elf32; diff --git a/src/ortho/mcode/elf32.ads b/src/ortho/mcode/elf32.ads new file mode 100644 index 000000000..5afd317f6 --- /dev/null +++ b/src/ortho/mcode/elf32.ads @@ -0,0 +1,124 @@ +-- ELF32 definitions. +-- 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 Interfaces; use Interfaces; +with System; +with Elf_Common; use Elf_Common; + +package Elf32 is + subtype Elf32_Addr is Unsigned_32; + subtype Elf32_Half is Unsigned_16; + subtype Elf32_Off is Unsigned_32; + subtype Elf32_Sword is Integer_32; + subtype Elf32_Word is Unsigned_32; + subtype Elf32_Uchar is Unsigned_8; + + type Elf32_Ehdr is record + E_Ident : E_Ident_Type; + E_Type : Elf32_Half; + E_Machine : Elf32_Half; + E_Version : Elf32_Word; + E_Entry : Elf32_Addr; + E_Phoff : Elf32_Off; + E_Shoff : Elf32_Off; + E_Flags : Elf32_Word; + E_Ehsize : Elf32_Half; + E_Phentsize : Elf32_Half; + E_Phnum : Elf32_Half; + E_Shentsize : Elf32_Half; + E_Shnum : Elf32_Half; + E_Shstrndx : Elf32_Half; + end record; + + Elf32_Ehdr_Size : constant Natural := Elf32_Ehdr'Size / System.Storage_Unit; + + type Elf32_Shdr is record + Sh_Name : Elf32_Word; + Sh_Type : Elf32_Word; + Sh_Flags : Elf32_Word; + Sh_Addr : Elf32_Addr; + Sh_Offset : Elf32_Off; + Sh_Size : Elf32_Word; + Sh_Link : Elf32_Word; + Sh_Info : Elf32_Word; + Sh_Addralign : Elf32_Word; + Sh_Entsize : Elf32_Word; + end record; + Elf32_Shdr_Size : constant Natural := Elf32_Shdr'Size / System.Storage_Unit; + + -- Symbol table. + type Elf32_Sym is record + St_Name : Elf32_Word; + St_Value : Elf32_Addr; + St_Size : Elf32_Word; + St_Info : Elf32_Uchar; + St_Other : Elf32_Uchar; + St_Shndx : Elf32_Half; + end record; + Elf32_Sym_Size : constant Natural := Elf32_Sym'Size / System.Storage_Unit; + + function Elf32_St_Bind (Info : Elf32_Uchar) return Elf32_Uchar; + function Elf32_St_Type (Info : Elf32_Uchar) return Elf32_Uchar; + function Elf32_St_Info (B, T : Elf32_Uchar) return Elf32_Uchar; + pragma Inline (Elf32_St_Bind); + pragma Inline (Elf32_St_Type); + pragma Inline (Elf32_St_Info); + + -- Relocation. + type Elf32_Rel is record + R_Offset : Elf32_Addr; + R_Info : Elf32_Word; + end record; + Elf32_Rel_Size : constant Natural := Elf32_Rel'Size / System.Storage_Unit; + + type Elf32_Rela is record + R_Offset : Elf32_Addr; + R_Info : Elf32_Word; + R_Addend : Elf32_Sword; + end record; + Elf32_Rela_Size : constant Natural := Elf32_Rela'Size / System.Storage_Unit; + + function Elf32_R_Sym (I : Elf32_Word) return Elf32_Word; + function Elf32_R_Type (I : Elf32_Word) return Elf32_Word; + function Elf32_R_Info (S, T : Elf32_Word) return Elf32_Word; + + -- For i386 + R_386_NONE : constant Elf32_Word := 0; -- none none + R_386_32 : constant Elf32_Word := 1; -- word32 S+A + R_386_PC32 : constant Elf32_Word := 2; -- word32 S+A-P + + -- For sparc + R_SPARC_NONE : constant Elf32_Word := 0; -- none + R_SPARC_32 : constant Elf32_Word := 3; -- (S + A) + R_SPARC_WDISP30 : constant Elf32_Word := 7; -- (S + A - P) >> 2 + R_SPARC_WDISP22 : constant Elf32_Word := 8; -- (S + A - P) >> 2 + R_SPARC_HI22 : constant Elf32_Word := 9; -- (S + A) >> 10 + R_SPARC_LO10 : constant Elf32_Word := 12; -- (S + A) & 0x3ff + R_SPARC_UA32 : constant Elf32_Word := 23; -- (S + A) + + type Elf32_Phdr is record + P_Type : Elf32_Word; + P_Offset : Elf32_Off; + P_Vaddr : Elf32_Addr; + P_Paddr : Elf32_Addr; + P_Filesz : Elf32_Word; + P_Memsz : Elf32_Word; + P_Flags : Elf32_Word; + P_Align : Elf32_Word; + end record; + Elf32_Phdr_Size : constant Natural := Elf32_Phdr'Size / System.Storage_Unit; +end Elf32; diff --git a/src/ortho/mcode/elf64.ads b/src/ortho/mcode/elf64.ads new file mode 100644 index 000000000..217e5557a --- /dev/null +++ b/src/ortho/mcode/elf64.ads @@ -0,0 +1,105 @@ +-- ELF64 definitions. +-- 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 Interfaces; use Interfaces; +with System; +with Elf_Common; use Elf_Common; + +package Elf64 is + subtype Elf64_Addr is Unsigned_64; + subtype Elf64_Off is Unsigned_64; + subtype Elf64_Uchar is Unsigned_8; + subtype Elf64_Half is Unsigned_16; + subtype Elf64_Sword is Integer_32; + subtype Elf64_Word is Unsigned_32; + subtype Elf64_Xword is Unsigned_64; + subtype Elf64_Sxword is Integer_64; + + type Elf64_Ehdr is record + E_Ident : E_Ident_Type; + E_Type : Elf64_Half; + E_Machine : Elf64_Half; + E_Version : Elf64_Word; + E_Entry : Elf64_Addr; + E_Phoff : Elf64_Off; + E_Shoff : Elf64_Off; + E_Flags : Elf64_Word; + E_Ehsize : Elf64_Half; + E_Phentsize : Elf64_Half; + E_Phnum : Elf64_Half; + E_Shentsize : Elf64_Half; + E_Shnum : Elf64_Half; + E_Shstrndx : Elf64_Half; + end record; + + Elf64_Ehdr_Size : constant Natural := Elf64_Ehdr'Size / System.Storage_Unit; + + type Elf64_Shdr is record + Sh_Name : Elf64_Word; + Sh_Type : Elf64_Word; + Sh_Flags : Elf64_Xword; + Sh_Addr : Elf64_Addr; + Sh_Offset : Elf64_Off; + Sh_Size : Elf64_Xword; + Sh_Link : Elf64_Word; + Sh_Info : Elf64_Word; + Sh_Addralign : Elf64_Xword; + Sh_Entsize : Elf64_Xword; + end record; + Elf64_Shdr_Size : constant Natural := Elf64_Shdr'Size / System.Storage_Unit; + + -- Symbol table. + type Elf64_Sym is record + St_Name : Elf64_Word; + St_Info : Elf64_Uchar; + St_Other : Elf64_Uchar; + St_Shndx : Elf64_Half; + St_Value : Elf64_Addr; + St_Size : Elf64_Xword; + end record; + Elf64_Sym_Size : constant Natural := Elf64_Sym'Size / System.Storage_Unit; + + -- Relocation. + type Elf64_Rel is record + R_Offset : Elf64_Addr; + R_Info : Elf64_Xword; + end record; + Elf64_Rel_Size : constant Natural := Elf64_Rel'Size / System.Storage_Unit; + + type Elf64_Rela is record + R_Offset : Elf64_Addr; + R_Info : Elf64_Xword; + R_Addend : Elf64_Sxword; + end record; + Elf64_Rela_Size : constant Natural := Elf64_Rela'Size / System.Storage_Unit; + +-- function Elf64_R_Sym (I : Elf64_Word) return Elf64_Word; +-- function Elf64_R_Type (I : Elf64_Word) return Elf64_Word; +-- function Elf64_R_Info (S, T : Elf64_Word) return Elf64_Word; + + type Elf64_Phdr is record + P_Type : Elf64_Word; + P_Flags : Elf64_Word; + P_Offset : Elf64_Off; + P_Vaddr : Elf64_Addr; + P_Paddr : Elf64_Addr; + P_Filesz : Elf64_Xword; + P_Memsz : Elf64_Xword; + P_Align : Elf64_Xword; + end record; + Elf64_Phdr_Size : constant Natural := Elf64_Phdr'Size / System.Storage_Unit; +end Elf64; diff --git a/src/ortho/mcode/elf_arch.ads b/src/ortho/mcode/elf_arch.ads new file mode 100644 index 000000000..325c4e5e3 --- /dev/null +++ b/src/ortho/mcode/elf_arch.ads @@ -0,0 +1,2 @@ +with Elf_Arch32; +package Elf_Arch renames Elf_Arch32; diff --git a/src/ortho/mcode/elf_arch32.ads b/src/ortho/mcode/elf_arch32.ads new file mode 100644 index 000000000..5e987b1e6 --- /dev/null +++ b/src/ortho/mcode/elf_arch32.ads @@ -0,0 +1,37 @@ +-- ELF32 view of ELF. +-- 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 Elf_Common; use Elf_Common; +with Elf32; use Elf32; + +package Elf_Arch32 is + subtype Elf_Ehdr is Elf32_Ehdr; + subtype Elf_Shdr is Elf32_Shdr; + subtype Elf_Sym is Elf32_Sym; + subtype Elf_Rel is Elf32_Rel; + subtype Elf_Rela is Elf32_Rela; + subtype Elf_Phdr is Elf32_Phdr; + + subtype Elf_Off is Elf32_Off; + subtype Elf_Size is Elf32_Word; + Elf_Ehdr_Size : constant Natural := Elf32_Ehdr_Size; + Elf_Shdr_Size : constant Natural := Elf32_Shdr_Size; + Elf_Phdr_Size : constant Natural := Elf32_Phdr_Size; + Elf_Sym_Size : constant Natural := Elf32_Sym_Size; + + Elf_Arch_Class : constant Elf_Uchar := ELFCLASS32; +end Elf_Arch32; diff --git a/src/ortho/mcode/elf_arch64.ads b/src/ortho/mcode/elf_arch64.ads new file mode 100644 index 000000000..504cd66b3 --- /dev/null +++ b/src/ortho/mcode/elf_arch64.ads @@ -0,0 +1,37 @@ +-- ELF64 view of ELF. +-- 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 Elf_Common; use Elf_Common; +with Elf64; use Elf64; + +package Elf_Arch64 is + subtype Elf_Ehdr is Elf64_Ehdr; + subtype Elf_Shdr is Elf64_Shdr; + subtype Elf_Sym is Elf64_Sym; + subtype Elf_Rel is Elf64_Rel; + subtype Elf_Rela is Elf64_Rela; + subtype Elf_Phdr is Elf64_Phdr; + + subtype Elf_Off is Elf64_Off; + subtype Elf_Size is Elf64_Xword; + Elf_Ehdr_Size : constant Natural := Elf64_Ehdr_Size; + Elf_Shdr_Size : constant Natural := Elf64_Shdr_Size; + Elf_Phdr_Size : constant Natural := Elf64_Phdr_Size; + Elf_Sym_Size : constant Natural := Elf64_Sym_Size; + + Elf_Arch_Class : constant Elf_Uchar := ELFCLASS64; +end Elf_Arch64; diff --git a/src/ortho/mcode/elf_common.adb b/src/ortho/mcode/elf_common.adb new file mode 100644 index 000000000..5d05a2dc7 --- /dev/null +++ b/src/ortho/mcode/elf_common.adb @@ -0,0 +1,48 @@ +-- ELF definitions. +-- 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. +package body Elf_Common is + function Elf_St_Bind (Info : Elf_Uchar) return Elf_Uchar is + begin + return Shift_Right (Info, 4); + end Elf_St_Bind; + + function Elf_St_Type (Info : Elf_Uchar) return Elf_Uchar is + begin + return Info and 16#0F#; + end Elf_St_Type; + + function Elf_St_Info (B, T : Elf_Uchar) return Elf_Uchar is + begin + return Shift_Left (B, 4) or T; + end Elf_St_Info; + +-- function Elf32_R_Sym (I : Elf32_Word) return Elf32_Word is +-- begin +-- return Shift_Right (I, 8); +-- end Elf32_R_Sym; + +-- function Elf32_R_Type (I : Elf32_Word) return Elf32_Word is +-- begin +-- return I and 16#Ff#; +-- end Elf32_R_Type; + +-- function Elf32_R_Info (S, T : Elf32_Word) return Elf32_Word is +-- begin +-- return Shift_Left (S, 8) or T; +-- end Elf32_R_Info; +end Elf_Common; diff --git a/src/ortho/mcode/elf_common.ads b/src/ortho/mcode/elf_common.ads new file mode 100644 index 000000000..28186d094 --- /dev/null +++ b/src/ortho/mcode/elf_common.ads @@ -0,0 +1,250 @@ +-- ELF definitions. +-- 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 Interfaces; use Interfaces; + +package Elf_Common is + subtype Elf_Half is Unsigned_16; + subtype Elf_Sword is Integer_32; + subtype Elf_Word is Unsigned_32; + subtype Elf_Uchar is Unsigned_8; + + EI_NIDENT : constant Natural := 16; + type E_Ident_Type is array (Natural range 0 .. EI_NIDENT - 1) + of Elf_Uchar; + + -- e_type values. + ET_NONE : constant Elf_Half := 0; -- No file type + ET_REL : constant Elf_Half := 1; -- Relocatable file + ET_EXEC : constant Elf_Half := 2; -- Executable file + ET_DYN : constant Elf_Half := 3; -- Shared object file + ET_CORE : constant Elf_Half := 4; -- Core file + ET_LOPROC : constant Elf_Half := 16#Ff00#; -- Processor-specific + ET_HIPROC : constant Elf_Half := 16#Ffff#; -- Processor-specific + + -- e_machine values. + EM_NONE : constant Elf_Half := 0; -- No machine + EM_M32 : constant Elf_Half := 1; -- AT&T WE 32100 + EM_SPARC : constant Elf_Half := 2; -- SPARC + EM_386 : constant Elf_Half := 3; -- Intel Architecture + EM_68K : constant Elf_Half := 4; -- Motorola 68000 + EM_88K : constant Elf_Half := 5; -- Motorola 88000 + EM_860 : constant Elf_Half := 7; -- Intel 80860 + EM_MIPS : constant Elf_Half := 8; -- MIPS RS3000 Big-Endian + EM_MIPS_RS4_BE : constant Elf_Half := 10; -- MIPS RS4000 Big-Endian + -- RESERVED : constant Elf_Half := 11; -- -16 Reserved for future use + + -- e_version + EV_NONE : constant Elf_Uchar := 0; -- Invalid versionn + EV_CURRENT : constant Elf_Uchar := 1; -- Current version + + -- e_ident identification indexes. + EI_MAG0 : constant Natural := 0; -- File identification + EI_MAG1 : constant Natural := 1; -- File identification + EI_MAG2 : constant Natural := 2; -- File identification + EI_MAG3 : constant Natural := 3; -- File identification + EI_CLASS : constant Natural := 4; -- File class + EI_DATA : constant Natural := 5; -- Data encoding + EI_VERSION : constant Natural := 6; -- File version + EI_PAD : constant Natural := 7; -- Start of padding bytes + --EI_NIDENT : constant Natural := 16; -- Size of e_ident[] + + -- Magic values. + ELFMAG0 : constant Elf_Uchar := 16#7f#; -- e_ident[EI_MAG0] + ELFMAG1 : constant Elf_Uchar := Character'Pos ('E'); -- e_ident[EI_MAG1] + ELFMAG2 : constant Elf_Uchar := Character'Pos ('L'); -- e_ident[EI_MAG2] + ELFMAG3 : constant Elf_Uchar := Character'Pos ('F'); -- e_ident[EI_MAG3] + + ELFCLASSNONE : constant Elf_Uchar := 0; -- Invalid class + ELFCLASS32 : constant Elf_Uchar := 1; -- 32-bit objects + ELFCLASS64 : constant Elf_Uchar := 2; -- 64-bit objects + + ELFDATANONE : constant Elf_Uchar := 0; -- Invalid data encoding + ELFDATA2LSB : constant Elf_Uchar := 1; -- See below + ELFDATA2MSB : constant Elf_Uchar := 2; -- See below + + SHN_UNDEF : constant Elf_Half := 0; -- + SHN_LORESERVE : constant Elf_Half := 16#Ff00#; -- + SHN_LOPROC : constant Elf_Half := 16#ff00#; -- + SHN_HIPROC : constant Elf_Half := 16#ff1f#; -- + SHN_ABS : constant Elf_Half := 16#fff1#; -- + SHN_COMMON : constant Elf_Half := 16#fff2#; -- + SHN_HIRESERVE : constant Elf_Half := 16#ffff#; -- + + -- Sh_type. + SHT_NULL : constant Elf_Word := 0; + SHT_PROGBITS : constant Elf_Word := 1; + SHT_SYMTAB : constant Elf_Word := 2; + SHT_STRTAB : constant Elf_Word := 3; + SHT_RELA : constant Elf_Word := 4; + SHT_HASH : constant Elf_Word := 5; + SHT_DYNAMIC : constant Elf_Word := 6; + SHT_NOTE : constant Elf_Word := 7; + SHT_NOBITS : constant Elf_Word := 8; + SHT_REL : constant Elf_Word := 9; + SHT_SHLIB : constant Elf_Word := 10; + SHT_DYNSYM : constant Elf_Word := 11; + SHT_INIT_ARRAY : constant Elf_Word := 14; + SHT_FINI_ARRAY : constant Elf_Word := 15; + SHT_PREINIT_ARRAY : constant Elf_Word := 16; + SHT_GROUP : constant Elf_Word := 17; + SHT_SYMTAB_SHNDX : constant Elf_Word := 18; + SHT_NUM : constant Elf_Word := 19; + SHT_LOOS : constant Elf_Word := 16#60000000#; + SHT_GNU_LIBLIST : constant Elf_Word := 16#6ffffff7#; + SHT_CHECKSUM : constant Elf_Word := 16#6ffffff8#; + SHT_LOSUNW : constant Elf_Word := 16#6ffffffa#; + SHT_SUNW_Move : constant Elf_Word := 16#6ffffffa#; + SHT_SUNW_COMDAT : constant Elf_Word := 16#6ffffffb#; + SHT_SUNW_Syminfo : constant Elf_Word := 16#6ffffffc#; + SHT_GNU_Verdef : constant Elf_Word := 16#6ffffffd#; + SHT_GNU_Verneed : constant Elf_Word := 16#6ffffffe#; + SHT_GNU_Versym : constant Elf_Word := 16#6fffffff#; + SHT_HISUNW : constant Elf_Word := 16#6fffffff#; + SHT_HIOS : constant Elf_Word := 16#6fffffff#; + SHT_LOPROC : constant Elf_Word := 16#70000000#; + SHT_HIPROC : constant Elf_Word := 16#7fffffff#; + SHT_LOUSER : constant Elf_Word := 16#80000000#; + SHT_HIUSER : constant Elf_Word := 16#ffffffff#; + + + SHF_WRITE : constant := 16#1#; + SHF_ALLOC : constant := 16#2#; + SHF_EXECINSTR : constant := 16#4#; + SHF_MASKPROC : constant := 16#F0000000#; + + function Elf_St_Bind (Info : Elf_Uchar) return Elf_Uchar; + function Elf_St_Type (Info : Elf_Uchar) return Elf_Uchar; + function Elf_St_Info (B, T : Elf_Uchar) return Elf_Uchar; + pragma Inline (Elf_St_Bind); + pragma Inline (Elf_St_Type); + pragma Inline (Elf_St_Info); + + -- Symbol binding. + STB_LOCAL : constant Elf_Uchar := 0; + STB_GLOBAL : constant Elf_Uchar := 1; + STB_WEAK : constant Elf_Uchar := 2; + STB_LOPROC : constant Elf_Uchar := 13; + STB_HIPROC : constant Elf_Uchar := 15; + + -- Symbol types. + STT_NOTYPE : constant Elf_Uchar := 0; + STT_OBJECT : constant Elf_Uchar := 1; + STT_FUNC : constant Elf_Uchar := 2; + STT_SECTION : constant Elf_Uchar := 3; + STT_FILE : constant Elf_Uchar := 4; + STT_LOPROC : constant Elf_Uchar := 13; + STT_HIPROC : constant Elf_Uchar := 15; + + + PT_NULL : constant Elf_Word := 0; + PT_LOAD : constant Elf_Word := 1; + PT_DYNAMIC : constant Elf_Word := 2; + PT_INTERP : constant Elf_Word := 3; + PT_NOTE : constant Elf_Word := 4; + PT_SHLIB : constant Elf_Word := 5; + PT_PHDR : constant Elf_Word := 6; + PT_TLS : constant Elf_Word := 7; + PT_NUM : constant Elf_Word := 8; + PT_LOOS : constant Elf_Word := 16#60000000#; + PT_GNU_EH_FRAME : constant Elf_Word := 16#6474e550#; + PT_LOSUNW : constant Elf_Word := 16#6ffffffa#; + PT_SUNWBSS : constant Elf_Word := 16#6ffffffa#; + PT_SUNWSTACK : constant Elf_Word := 16#6ffffffb#; + PT_HISUNW : constant Elf_Word := 16#6fffffff#; + PT_HIOS : constant Elf_Word := 16#6fffffff#; + PT_LOPROC : constant Elf_Word := 16#70000000#; + PT_HIPROC : constant Elf_Word := 16#7fffffff#; + + PF_X : constant Elf_Word := 1; + PF_W : constant Elf_Word := 2; + PF_R : constant Elf_Word := 4; + + DT_NULL : constant Elf_Word := 0; + DT_NEEDED : constant Elf_Word := 1; + DT_PLTRELSZ : constant Elf_Word := 2; + DT_PLTGOT : constant Elf_Word := 3; + DT_HASH : constant Elf_Word := 4; + DT_STRTAB : constant Elf_Word := 5; + DT_SYMTAB : constant Elf_Word := 6; + DT_RELA : constant Elf_Word := 7; + DT_RELASZ : constant Elf_Word := 8; + DT_RELAENT : constant Elf_Word := 9; + DT_STRSZ : constant Elf_Word := 10; + DT_SYMENT : constant Elf_Word := 11; + DT_INIT : constant Elf_Word := 12; + DT_FINI : constant Elf_Word := 13; + DT_SONAME : constant Elf_Word := 14; + DT_RPATH : constant Elf_Word := 15; + DT_SYMBOLIC : constant Elf_Word := 16; + DT_REL : constant Elf_Word := 17; + DT_RELSZ : constant Elf_Word := 18; + DT_RELENT : constant Elf_Word := 19; + DT_PLTREL : constant Elf_Word := 20; + DT_DEBUG : constant Elf_Word := 21; + DT_TEXTREL : constant Elf_Word := 22; + DT_JMPREL : constant Elf_Word := 23; + DT_BIND_NOW : constant Elf_Word := 24; + DT_INIT_ARRAY : constant Elf_Word := 25; + DT_FINI_ARRAY : constant Elf_Word := 26; + DT_INIT_ARRAYSZ : constant Elf_Word := 27; + DT_FINI_ARRAYSZ : constant Elf_Word := 28; + DT_RUNPATH : constant Elf_Word := 29; + DT_FLAGS : constant Elf_Word := 30; + DT_ENCODING : constant Elf_Word := 32; + DT_PREINIT_ARRAY : constant Elf_Word := 32; + DT_PREINIT_ARRAYSZ : constant Elf_Word := 33; + DT_NUM : constant Elf_Word := 34; + DT_LOOS : constant Elf_Word := 16#60000000#; + DT_HIOS : constant Elf_Word := 16#6fffffff#; + DT_LOPROC : constant Elf_Word := 16#70000000#; + DT_HIPROC : constant Elf_Word := 16#7fffffff#; + DT_VALRNGLO : constant Elf_Word := 16#6ffffd00#; + DT_GNU_PRELINKED : constant Elf_Word := 16#6ffffdf5#; + DT_GNU_CONFLICTSZ : constant Elf_Word := 16#6ffffdf6#; + DT_GNU_LIBLISTSZ : constant Elf_Word := 16#6ffffdf7#; + DT_CHECKSUM : constant Elf_Word := 16#6ffffdf8#; + DT_PLTPADSZ : constant Elf_Word := 16#6ffffdf9#; + DT_MOVEENT : constant Elf_Word := 16#6ffffdfa#; + DT_MOVESZ : constant Elf_Word := 16#6ffffdfb#; + DT_FEATURE_1 : constant Elf_Word := 16#6ffffdfc#; + DT_POSFLAG_1 : constant Elf_Word := 16#6ffffdfd#; + DT_SYMINSZ : constant Elf_Word := 16#6ffffdfe#; + DT_SYMINENT : constant Elf_Word := 16#6ffffdff#; + DT_VALRNGHI : constant Elf_Word := 16#6ffffdff#; + DT_ADDRRNGLO : constant Elf_Word := 16#6ffffe00#; + DT_GNU_CONFLICT : constant Elf_Word := 16#6ffffef8#; + DT_GNU_LIBLIST : constant Elf_Word := 16#6ffffef9#; + DT_CONFIG : constant Elf_Word := 16#6ffffefa#; + DT_DEPAUDIT : constant Elf_Word := 16#6ffffefb#; + DT_AUDIT : constant Elf_Word := 16#6ffffefc#; + DT_PLTPAD : constant Elf_Word := 16#6ffffefd#; + DT_MOVETAB : constant Elf_Word := 16#6ffffefe#; + DT_SYMINFO : constant Elf_Word := 16#6ffffeff#; + DT_ADDRRNGHI : constant Elf_Word := 16#6ffffeff#; + DT_VERSYM : constant Elf_Word := 16#6ffffff0#; + DT_RELACOUNT : constant Elf_Word := 16#6ffffff9#; + DT_RELCOUNT : constant Elf_Word := 16#6ffffffa#; + DT_FLAGS_1 : constant Elf_Word := 16#6ffffffb#; + DT_VERDEF : constant Elf_Word := 16#6ffffffc#; + DT_VERDEFNUM : constant Elf_Word := 16#6ffffffd#; + DT_VERNEED : constant Elf_Word := 16#6ffffffe#; + DT_VERNEEDNUM : constant Elf_Word := 16#6fffffff#; + DT_AUXILIARY : constant Elf_Word := 16#7ffffffd#; + DT_FILTER : constant Elf_Word := 16#7fffffff#; + +end Elf_Common; diff --git a/src/ortho/mcode/elfdump.adb b/src/ortho/mcode/elfdump.adb new file mode 100644 index 000000000..d49275912 --- /dev/null +++ b/src/ortho/mcode/elfdump.adb @@ -0,0 +1,267 @@ +-- ELF dumper (main program). +-- 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; use Ada.Text_IO; +with Elf_Common; use Elf_Common; +with Ada.Command_Line; use Ada.Command_Line; +with Hex_Images; use Hex_Images; +with Interfaces; use Interfaces; +with Elfdumper; use Elfdumper; + +procedure Elfdump is + Flag_Ehdr : Boolean := False; + Flag_Shdr : Boolean := False; + Flag_Strtab : Boolean := False; + Flag_Symtab : Boolean := False; + Flag_Dwarf_Info : Boolean := False; + Flag_Dwarf_Abbrev : Boolean := False; + Flag_Dwarf_Pubnames : Boolean := False; + Flag_Dwarf_Aranges : Boolean := False; + Flag_Dwarf_Line : Boolean := False; + Flag_Dwarf_Frame : Boolean := False; + Flag_Eh_Frame_Hdr : Boolean := False; + Flag_Long_Shdr : Boolean := False; + Flag_Phdr : Boolean := False; + Flag_Note : Boolean := False; + Flag_Dynamic : Boolean := False; + + procedure Disp_Max_Len (Str : String; Len : Natural) + is + begin + if Str'Length > Len then + Put (Str (Str'First .. Str'First + Len - 1)); + else + Put (Str); + Put ((Str'Length + 1 .. Len => ' ')); + end if; + end Disp_Max_Len; + + procedure Disp_Section_Header (File : Elf_File; Index : Elf_Half) is + begin + Put ("Section " & Hex_Image (Index)); + Put (" "); + Put (Get_Section_Name (File, Index)); + New_Line; + end Disp_Section_Header; + + procedure Disp_Elf_File (Filename : String) + is + File : Elf_File; + Ehdr : Elf_Ehdr_Acc; + Shdr : Elf_Shdr_Acc; + Phdr : Elf_Phdr_Acc; + Sh_Strtab : Strtab_Type; + begin + Open_File (File, Filename); + if Get_Status (File) /= Status_Ok then + Put_Line ("cannot open elf file '" & Filename & "': " & + Elf_File_Status'Image (Get_Status (File))); + return; + end if; + + Ehdr := Get_Ehdr (File); + + if Flag_Ehdr then + Disp_Ehdr (Ehdr.all); + end if; + + Load_Shdr (File); + Sh_Strtab := Get_Sh_Strtab (File); + + if Flag_Long_Shdr then + if Ehdr.E_Shnum = 0 then + Put ("no section"); + else + for I in 0 .. Ehdr.E_Shnum - 1 loop + Put ("Section " & Hex_Image (I)); + New_Line; + Disp_Shdr (Get_Shdr (File, I).all, Sh_Strtab); + end loop; + end if; + end if; + if Flag_Shdr then + if Ehdr.E_Shnum = 0 then + Put ("no section"); + else + Put ("Num Name Type "); + Put ("Offset Size Link Info Al Es"); + New_Line; + for I in 0 .. Ehdr.E_Shnum - 1 loop + declare + Shdr : Elf_Shdr_Acc := Get_Shdr (File, I); + begin + Put (Hex_Image (I)); + Put (" "); + Disp_Max_Len (Get_Section_Name (File, I), 20); + Put (" "); + Disp_Max_Len (Get_Shdr_Type_Name (Shdr.Sh_Type), 10); + Put (" "); + Put (Hex_Image (Shdr.Sh_Offset)); + Put (" "); + Put (Hex_Image (Shdr.Sh_Size)); + Put (" "); + Put (Hex_Image (Unsigned_16 (Shdr.Sh_Link and 16#Ffff#))); + Put (" "); + Put (Hex_Image (Unsigned_16 (Shdr.Sh_Info and 16#Ffff#))); + Put (" "); + Put (Hex_Image (Unsigned_8 (Shdr.Sh_Addralign and 16#ff#))); + Put (" "); + Put (Hex_Image (Unsigned_8 (Shdr.Sh_Entsize and 16#ff#))); + New_Line; + end; + end loop; + end if; + end if; + + if Flag_Phdr then + Load_Phdr (File); + if Ehdr.E_Phnum = 0 then + Put ("no program segment"); + else + for I in 0 .. Ehdr.E_Phnum - 1 loop + Put ("segment " & Hex_Image (I)); + New_Line; + Disp_Phdr (Get_Phdr (File, I).all); + end loop; + end if; + end if; + + -- Dump each section. + if Ehdr.E_Shnum > 0 then + for I in 0 .. Ehdr.E_Shnum - 1 loop + Shdr := Get_Shdr (File, I); + case Shdr.Sh_Type is + when SHT_SYMTAB => + if Flag_Symtab then + Disp_Section_Header (File, I); + Disp_Symtab (File, I); + end if; + when SHT_STRTAB => + if Flag_Strtab then + Disp_Section_Header (File, I); + Disp_Strtab (File, I); + end if; + when SHT_PROGBITS => + declare + Name : String := Get_Section_Name (File, I); + begin + if Flag_Dwarf_Abbrev and then Name = ".debug_abbrev" then + Disp_Section_Header (File, I); + Disp_Debug_Abbrev (File, I); + elsif Flag_Dwarf_Info and then Name = ".debug_info" then + Disp_Section_Header (File, I); + Disp_Debug_Info (File, I); + elsif Flag_Dwarf_Line and then Name = ".debug_line" then + Disp_Section_Header (File, I); + Disp_Debug_Line (File, I); + elsif Flag_Dwarf_Frame and then Name = ".debug_frame" then + Disp_Section_Header (File, I); + Disp_Debug_Frame (File, I); + elsif Flag_Dwarf_Pubnames + and then Name = ".debug_pubnames" + then + Disp_Section_Header (File, I); + Disp_Debug_Pubnames (File, I); + elsif Flag_Eh_Frame_Hdr and then Name = ".eh_frame_hdr" + then + Disp_Section_Header (File, I); + Disp_Eh_Frame_Hdr (File, I); + elsif Flag_Dwarf_Aranges + and then Name = ".debug_aranges" + then + Disp_Section_Header (File, I); + Disp_Debug_Aranges (File, I); + end if; + end; + when SHT_NOTE => + if Flag_Note then + Disp_Section_Header (File, I); + Disp_Section_Note (File, I); + end if; + when SHT_DYNAMIC => + if Flag_Dynamic then + Disp_Section_Header (File, I); + Disp_Dynamic (File, I); + end if; + when others => + null; + end case; + end loop; + elsif Ehdr.E_Phnum > 0 then + Load_Phdr (File); + for I in 0 .. Ehdr.E_Phnum - 1 loop + Phdr := Get_Phdr (File, I); + case Phdr.P_Type is + when PT_NOTE => + if Flag_Note then + Disp_Segment_Note (File, I); + end if; + when others => + null; + end case; + end loop; + end if; + end Disp_Elf_File; + +begin + for I in 1 .. Argument_Count loop + declare + Arg : String := Argument (I); + begin + if Arg (1) = '-' then + -- An option. + if Arg = "-e" then + Flag_Ehdr := True; + elsif Arg = "-t" then + Flag_Strtab := True; + elsif Arg = "-S" then + Flag_Symtab := True; + elsif Arg = "-s" then + Flag_Shdr := True; + elsif Arg = "-p" then + Flag_Phdr := True; + elsif Arg = "-n" then + Flag_Note := True; + elsif Arg = "-d" then + Flag_Dynamic := True; + elsif Arg = "--dwarf-info" then + Flag_Dwarf_Info := True; + elsif Arg = "--dwarf-abbrev" then + Flag_Dwarf_Abbrev := True; + elsif Arg = "--dwarf-line" then + Flag_Dwarf_Line := True; + elsif Arg = "--dwarf-frame" then + Flag_Dwarf_Frame := True; + elsif Arg = "--dwarf-pubnames" then + Flag_Dwarf_Pubnames := True; + elsif Arg = "--dwarf-aranges" then + Flag_Dwarf_Aranges := True; + elsif Arg = "--eh-frame-hdr" then + Flag_Eh_Frame_Hdr := True; + elsif Arg = "--long-shdr" then + Flag_Long_Shdr := True; + else + Put_Line ("unknown option '" & Arg & "'"); + return; + end if; + else + Disp_Elf_File (Arg); + end if; + end; + end loop; +end Elfdump; + diff --git a/src/ortho/mcode/elfdumper.adb b/src/ortho/mcode/elfdumper.adb new file mode 100644 index 000000000..b3a3b70f2 --- /dev/null +++ b/src/ortho/mcode/elfdumper.adb @@ -0,0 +1,2818 @@ +-- ELF dumper (library). +-- 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 System.Storage_Elements; use System.Storage_Elements; +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Unchecked_Deallocation; +with GNAT.OS_Lib; +with Interfaces; use Interfaces; +with Hex_Images; use Hex_Images; +with Elf_Common; use Elf_Common; +with Dwarf; + +package body Elfdumper is + function Get_String (Strtab : Strtab_Type; N : Elf_Size) return String + is + E : Elf_Size; + begin + E := N; + while Strtab.Base (E) /= Nul loop + E := E + 1; + end loop; + if E = N then + return ""; + else + return String (Strtab.Base (N .. E - 1)); + end if; + end Get_String; + + procedure Disp_Ehdr (Ehdr : Elf_Ehdr) is + begin + Put ("File class: "); + case Ehdr.E_Ident (EI_CLASS) is + when ELFCLASSNONE => + Put ("none"); + when ELFCLASS32 => + Put ("class_32"); + when ELFCLASS64 => + Put ("class_64"); + when others => + Put ("others"); + end case; + New_Line; + + Put ("encoding : "); + case Ehdr.E_Ident (EI_DATA) is + when ELFDATANONE => + Put ("none"); + when ELFDATA2LSB => + Put ("LSB byte order"); + when ELFDATA2MSB => + Put ("MSB byte order"); + when others => + Put ("unknown"); + end case; + New_Line; + + Put ("version : "); + case Ehdr.E_Ident (EI_VERSION) is + when EV_NONE => + Put ("none"); + when EV_CURRENT => + Put ("current (1)"); + when others => + Put ("future"); + end case; + New_Line; + + if Ehdr.E_Ident (EI_CLASS) /= Elf_Arch_Class +-- or Ehdr.E_Ident (EI_DATA) /= ELFDATA2LSB + or Ehdr.E_Ident (EI_VERSION) /= EV_CURRENT + then + Put_Line ("bad class/data encoding/version"); + return; + end if; + + Put ("File type : "); + case Ehdr.E_Type is + when ET_NONE => + Put ("no file type"); + when ET_REL => + Put ("relocatable file"); + when ET_EXEC => + Put ("executable file"); + when ET_CORE => + Put ("core file"); + when ET_LOPROC .. ET_HIPROC => + Put ("processor-specific"); + when others => + Put ("unknown"); + end case; + New_Line; + + Put ("machine : "); + case Ehdr.E_Machine is + when EM_NONE => + Put ("no machine"); + when EM_M32 => + Put ("AT&T WE 32100"); + when EM_SPARC => + Put ("SPARC"); + when EM_386 => + Put ("Intel architecture"); + when EM_68K => + Put ("Motorola 68000"); + when EM_88K => + Put ("Motorola 88000"); + when EM_860 => + Put ("Intel 80860"); + when EM_MIPS => + Put ("MIPS RS3000 Big-Endian"); + when EM_MIPS_RS4_BE => + Put ("MIPS RS4000 Big-Endian"); + when others => + Put ("unknown"); + end case; + New_Line; + + Put_Line ("Version : " & Hex_Image (Ehdr.E_Version)); + Put_Line ("Phoff : " & Hex_Image (Ehdr.E_Phoff)); + Put_Line ("Shoff : " & Hex_Image (Ehdr.E_Shoff)); + Put_Line ("flags : " & Hex_Image (Ehdr.E_Flags)); + Put_Line ("phentsize : " & Hex_Image (Ehdr.E_Ehsize)); + Put_Line ("phnum : " & Hex_Image (Ehdr.E_Phentsize)); + Put_Line ("shentsize : " & Hex_Image (Ehdr.E_Shentsize)); + Put_Line ("shnum : " & Hex_Image (Ehdr.E_Shnum)); + Put_Line ("shstrndx : " & Hex_Image (Ehdr.E_Shstrndx)); + end Disp_Ehdr; + + function Get_Shdr_Type_Name (Stype : Elf_Word) return String is + begin + case Stype is + when SHT_NULL => + return "NULL"; + when SHT_PROGBITS => + return "PROGBITS"; + when SHT_SYMTAB => + return "SYMTAB"; + when SHT_STRTAB => + return "STRTAB"; + when SHT_RELA => + return "RELA"; + when SHT_HASH => + return "HASH"; + when SHT_DYNAMIC => + return "DYNAMIC"; + when SHT_NOTE => + return "NOTE"; + when SHT_NOBITS => + return "NOBITS"; + when SHT_REL => + return "REL"; + when SHT_SHLIB => + return "SHLIB"; + when SHT_DYNSYM => + return "DYNSYM"; + when SHT_INIT_ARRAY => + return "INIT_ARRAY"; + when SHT_FINI_ARRAY => + return "FINI_ARRAY"; + when SHT_PREINIT_ARRAY => + return "PREINIT_ARRAY"; + when SHT_GROUP => + return "GROUP"; + when SHT_SYMTAB_SHNDX => + return "SYMTAB_SHNDX"; + when SHT_NUM => + return "NUM"; + when SHT_LOOS => + return "LOOS"; + when SHT_GNU_LIBLIST => + return "GNU_LIBLIST"; + when SHT_CHECKSUM => + return "CHECKSUM"; + when SHT_SUNW_Move => + return "SUNW_move"; + when SHT_SUNW_COMDAT => + return "SUNW_COMDAT"; + when SHT_SUNW_Syminfo => + return "SUNW_syminfo"; + when SHT_GNU_Verdef => + return "GNU_verdef"; + when SHT_GNU_Verneed => + return "GNU_verneed"; + when SHT_GNU_Versym => + return "GNU_versym"; + when SHT_LOPROC .. SHT_HIPROC => + return "Processor dependant"; + when SHT_LOUSER .. SHT_HIUSER => + return "User dependant"; + when others => + return "unknown"; + end case; + end Get_Shdr_Type_Name; + + procedure Disp_Shdr (Shdr : Elf_Shdr; Sh_Strtab : Strtab_Type) + is + begin + Put_Line ("name : " & Hex_Image (Shdr.Sh_Name) & " """ + & Get_String (Sh_Strtab, Elf_Size (Shdr.Sh_Name)) & """"); + Put ("type : " & Hex_Image (Shdr.Sh_Type) & " "); + Put (Get_Shdr_Type_Name (Shdr.Sh_Type)); + New_Line; + Put ("flags : " & Hex_Image (Shdr.Sh_Flags)); + if (Shdr.Sh_Flags and SHF_WRITE) /= 0 then + Put (" WRITE"); + end if; + if (Shdr.Sh_Flags and SHF_ALLOC) /= 0 then + Put (" ALLOC"); + end if; + if (Shdr.Sh_Flags and SHF_EXECINSTR) /= 0 then + Put (" EXEC"); + end if; + New_Line; + Put ("addr : " & Hex_Image (Shdr.Sh_Addr)); + Put (" offset : " & Hex_Image (Shdr.Sh_Offset)); + Put (" size : " & Hex_Image (Shdr.Sh_Size)); + New_Line; + Put ("link : " & Hex_Image (Shdr.Sh_Link)); + Put (" info : " & Hex_Image (Shdr.Sh_Info)); + Put (" addralign : " & Hex_Image (Shdr.Sh_Addralign)); + Put (" entsize : " & Hex_Image (Shdr.Sh_Entsize)); + New_Line; + end Disp_Shdr; + + procedure Disp_Sym (File : Elf_File; + Sym : Elf_Sym; + Strtab : Strtab_Type) + is + begin + Put (Hex_Image (Sym.St_Value)); + Put (" " & Hex_Image (Sym.St_Size)); + Put (' '); + --Put (" info:" & Hex_Image (Sym.St_Info) & " "); + case Elf_St_Bind (Sym.St_Info) is + when STB_LOCAL => + Put ("loc "); + when STB_GLOBAL => + Put ("glob"); + when STB_WEAK => + Put ("weak"); + when others => + Put ("? "); + end case; + Put (' '); + case Elf_St_Type (Sym.St_Info) is + when STT_NOTYPE => + Put ("none"); + when STT_OBJECT => + Put ("obj "); + when STT_FUNC => + Put ("func"); + when STT_SECTION => + Put ("sect"); + when STT_FILE => + Put ("file"); + when others => + Put ("? "); + end case; + --Put (" other:" & Hex_Image (Sym.St_Other)); + Put (' '); + case Sym.St_Shndx is + when SHN_UNDEF => + Put ("UNDEF "); + when 1 .. SHN_LORESERVE - 1 => + declare + S : String := Get_Section_Name (File, Sym.St_Shndx); + Max : constant Natural := 8; + begin + if S'Length <= Max then + Put (S); + for I in S'Length + 1 .. Max loop + Put (' '); + end loop; + else + Put (S (S'First .. S'First + Max - 1)); + end if; + end; + when SHN_LOPROC .. SHN_HIPROC => + Put ("*proc* "); + when SHN_ABS => + Put ("*ABS* "); + when SHN_COMMON => + Put ("*COMMON*"); + when others => + Put ("?? "); + end case; + --Put (" sect:" & Hex_Image (Sym.St_Shndx)); + Put (' '); + Put_Line (Get_String (Strtab, Elf_Size (Sym.St_Name))); + end Disp_Sym; + + function Get_Offset (File : Elf_File; Off : Elf_Off; Size : Elf_Size) + return Address + is + begin + if Off > File.Length or Off + Size > File.Length then + return Null_Address; + end if; + return File.Base + Storage_Offset (Off); + end Get_Offset; + + function Get_Section_Base (File : Elf_File; Shdr : Elf_Shdr) + return Address + is + begin + return Get_Offset (File, Shdr.Sh_Offset, Shdr.Sh_Size); + end Get_Section_Base; + + function Get_Section_Base (File : Elf_File; Index : Elf_Half) + return Address + is + Shdr : Elf_Shdr_Acc; + begin + Shdr := Get_Shdr (File, Index); + return Get_Section_Base (File, Shdr.all); + end Get_Section_Base; + + function Get_Segment_Base (File : Elf_File; Phdr : Elf_Phdr) + return Address + is + begin + return Get_Offset (File, Phdr.P_Offset, Phdr.P_Filesz); + end Get_Segment_Base; + + function Get_Segment_Base (File : Elf_File; Index : Elf_Half) + return Address + is + Phdr : Elf_Phdr_Acc; + begin + Phdr := Get_Phdr (File, Index); + return Get_Segment_Base (File, Phdr.all); + end Get_Segment_Base; + + procedure Open_File (File : out Elf_File; Filename : String) + is + function Malloc (Size : Integer) return Address; + pragma Import (C, Malloc); + + use GNAT.OS_Lib; + Length : Long_Integer; + Len : Integer; + Fd : File_Descriptor; + begin + File := (Filename => new String'(Filename), + Status => Status_Ok, + Length => 0, + Base => Null_Address, + Ehdr => null, + Shdr_Base => Null_Address, + Sh_Strtab => (null, 0), + Phdr_Base => Null_Address); + + -- Open the file. + Fd := Open_Read (Filename, Binary); + if Fd = Invalid_FD then + File.Status := Status_Open_Failure; + return; + end if; + + -- Get length. + Length := File_Length (Fd); + Len := Integer (Length); + if Len < Elf_Ehdr_Size then + File.Status := Status_Bad_File; + Close (Fd); + return; + end if; + + File.Length := Elf_Off (Len); + + -- Allocate memory for the file. + File.Base := Malloc (Len); + if File.Base = Null_Address then + File.Status := Status_Memory; + Close (Fd); + return; + end if; + + -- Read the whole file. + if Read (Fd, File.Base, Integer (Length)) /= Integer (Length) then + File.Status := Status_Read_Error; + Close (Fd); + return; + end if; + + Close (Fd); + + File.Ehdr := To_Elf_Ehdr_Acc (File.Base); + + if File.Ehdr.E_Ident (EI_MAG0) /= ELFMAG0 + or File.Ehdr.E_Ident (EI_MAG1) /= ELFMAG1 + or File.Ehdr.E_Ident (EI_MAG2) /= ELFMAG2 + or File.Ehdr.E_Ident (EI_MAG3) /= ELFMAG3 + then + File.Status := Status_Bad_Magic; + return; + end if; + + if File.Ehdr.E_Ident (EI_CLASS) /= Elf_Arch_Class +-- or Ehdr.E_Ident (EI_DATA) /= ELFDATA2LSB + or File.Ehdr.E_Ident (EI_VERSION) /= EV_CURRENT + then + File.Status := Status_Bad_Class; + return; + end if; + end Open_File; + + function Get_Status (File : Elf_File) return Elf_File_Status is + begin + return File.Status; + end Get_Status; + + function Get_Ehdr (File : Elf_File) return Elf_Ehdr_Acc is + begin + return File.Ehdr; + end Get_Ehdr; + + function Get_Shdr (File : Elf_File; Index : Elf_Half) + return Elf_Shdr_Acc + is + begin + if Index >= File.Ehdr.E_Shnum then + raise Constraint_Error; + end if; + return To_Elf_Shdr_Acc + (File.Shdr_Base + + Storage_Offset (Index * Elf_Half (Elf_Shdr_Size))); + end Get_Shdr; + + procedure Load_Phdr (File : in out Elf_File) + is + begin + if Get_Ehdr (File).E_Phentsize /= Elf_Half (Elf_Phdr_Size) then + return; + end if; + + File.Phdr_Base := + Get_Offset (File, Get_Ehdr (File).E_Phoff, + Elf_Size (Get_Ehdr (File).E_Phnum + * Elf_Half (Elf_Phdr_Size))); + end Load_Phdr; + + function Get_Phdr (File : Elf_File; Index : Elf_Half) + return Elf_Phdr_Acc + is + begin + if Index >= File.Ehdr.E_Phnum then + raise Constraint_Error; + end if; + return To_Elf_Phdr_Acc + (File.Phdr_Base + + Storage_Offset (Index * Elf_Half (Elf_Phdr_Size))); + end Get_Phdr; + + function Get_Strtab (File : Elf_File; Index : Elf_Half) + return Strtab_Type + is + Shdr : Elf_Shdr_Acc; + begin + Shdr := Get_Shdr (File, Index); + if Shdr = null or Shdr.Sh_Type /= SHT_STRTAB then + return Null_Strtab; + end if; + return (Base => To_Strtab_Fat_Acc (Get_Section_Base (File, Shdr.all)), + Length => Shdr.Sh_Size); + end Get_Strtab; + + procedure Load_Shdr (File : in out Elf_File) + is + begin + if Get_Ehdr (File).E_Shentsize /= Elf_Half (Elf_Shdr_Size) then + return; + end if; + + File.Shdr_Base := + Get_Offset (File, Get_Ehdr (File).E_Shoff, + Elf_Size (Get_Ehdr (File).E_Shnum + * Elf_Half (Elf_Shdr_Size))); + File.Sh_Strtab := Get_Strtab (File, Get_Ehdr (File).E_Shstrndx); + end Load_Shdr; + + function Get_Sh_Strtab (File : Elf_File) return Strtab_Type is + begin + return File.Sh_Strtab; + end Get_Sh_Strtab; + + function Get_Section_Name (File : Elf_File; Index : Elf_Half) + return String + is + begin + return Get_String (Get_Sh_Strtab (File), + Elf_Size (Get_Shdr (File, Index).Sh_Name)); + end Get_Section_Name; + + function Get_Section_By_Name (File : Elf_File; Name : String) + return Elf_Half + is + Ehdr : Elf_Ehdr_Acc; + Shdr : Elf_Shdr_Acc; + Sh_Strtab : Strtab_Type; + begin + Ehdr := Get_Ehdr (File); + Sh_Strtab := Get_Sh_Strtab (File); + for I in 1 .. Ehdr.E_Shnum - 1 loop + Shdr := Get_Shdr (File, I); + if Get_String (Sh_Strtab, Elf_Size (Shdr.Sh_Name)) = Name then + return I; + end if; + end loop; + return 0; + end Get_Section_By_Name; + + procedure Disp_Symtab (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + S_Strtab : Strtab_Type; + Base : Address; + Off : Storage_Offset; + begin + Shdr := Get_Shdr (File, Index); + if Shdr.Sh_Entsize /= Elf_Size (Elf_Sym_Size) then + return; + end if; + S_Strtab := Get_Strtab (File, Elf_Half (Shdr.Sh_Link)); + Base := Get_Section_Base (File, Shdr.all); + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Disp_Sym (File, To_Elf_Sym_Acc (Base + Off).all, S_Strtab); + Off := Off + Storage_Offset (Elf_Sym_Size); + end loop; + end Disp_Symtab; + + procedure Disp_Strtab (File : Elf_File; Index : Elf_Half) + is + Strtab : Strtab_Type; + S, E : Elf_Size; + begin + Strtab := Get_Strtab (File, Index); + S := 1; + while S < Strtab.Length loop + E := S; + while Strtab.Base (E) /= Nul loop + E := E + 1; + end loop; + Put_Line (Hex_Image (S) & ": " + & String (Strtab.Base (S .. E - 1))); + S := E + 1; + end loop; + end Disp_Strtab; + + function Read_Byte (Addr : Address) return Unsigned_8 + is + type Unsigned_8_Acc is access all Unsigned_8; + function To_Unsigned_8_Acc is new Ada.Unchecked_Conversion + (Address, Unsigned_8_Acc); + begin + return To_Unsigned_8_Acc (Addr).all; + end Read_Byte; + + procedure Read_ULEB128 (Base : Address; + Off : in out Storage_Offset; + Res : out Unsigned_32) + is + B : Unsigned_8; + Shift : Integer; + begin + Res := 0; + Shift := 0; + loop + B := Read_Byte (Base + Off); + Off := Off + 1; + Res := Res or Shift_Left (Unsigned_32 (B and 16#7f#), Shift); + exit when (B and 16#80#) = 0; + Shift := Shift + 7; + end loop; + end Read_ULEB128; + + procedure Read_SLEB128 (Base : Address; + Off : in out Storage_Offset; + Res : out Unsigned_32) + is + B : Unsigned_8; + Shift : Integer; + begin + Res := 0; + Shift := 0; + loop + B := Read_Byte (Base + Off); + Off := Off + 1; + Res := Res or Shift_Left (Unsigned_32 (B and 16#7f#), Shift); + Shift := Shift + 7; + exit when (B and 16#80#) = 0; + end loop; + if Shift < 32 and (Res and Shift_Left (1, Shift - 1)) /= 0 then + Res := Res or Shift_Left (-1, Shift); + end if; + end Read_SLEB128; + + procedure Read_Word4 (Base : Address; + Off : in out Storage_Offset; + Res : out Unsigned_32) + is + B0, B1, B2, B3 : Unsigned_8; + begin + B0 := Read_Byte (Base + Off + 0); + B1 := Read_Byte (Base + Off + 1); + B2 := Read_Byte (Base + Off + 2); + B3 := Read_Byte (Base + Off + 3); + Res := Shift_Left (Unsigned_32 (B3), 24) + or Shift_Left (Unsigned_32 (B2), 16) + or Shift_Left (Unsigned_32 (B1), 8) + or Shift_Left (Unsigned_32 (B0), 0); + Off := Off + 4; + end Read_Word4; + + procedure Read_Word2 (Base : Address; + Off : in out Storage_Offset; + Res : out Unsigned_16) + is + B0, B1 : Unsigned_8; + begin + B0 := Read_Byte (Base + Off + 0); + B1 := Read_Byte (Base + Off + 1); + Res := Shift_Left (Unsigned_16 (B1), 8) + or Shift_Left (Unsigned_16 (B0), 0); + Off := Off + 2; + end Read_Word2; + + procedure Read_Byte (Base : Address; + Off : in out Storage_Offset; + Res : out Unsigned_8) + is + begin + Res := Read_Byte (Base + Off); + Off := Off + 1; + end Read_Byte; + + procedure Disp_Note (Base : Address; Size : Storage_Offset) + is + Off : Storage_Offset; + Namesz : Unsigned_32; + Descsz : Unsigned_32; + Ntype : Unsigned_32; + B : Unsigned_8; + Is_Full : Boolean; + begin + Off := 0; + while Off < Size loop + Read_Word4 (Base, Off, Namesz); + Read_Word4 (Base, Off, Descsz); + Read_Word4 (Base, Off, Ntype); + Put ("type : "); + Put (Hex_Image (Ntype)); + New_Line; + Put ("name : "); + Put (Hex_Image (Namesz)); + Put (" "); + for I in 1 .. Namesz loop + Read_Byte (Base, Off, B); + if B /= 0 then + Put (Character'Val (B)); + end if; + end loop; + if Namesz mod 4 /= 0 then + for I in (Namesz mod 4) .. 3 loop + Read_Byte (Base, Off, B); + end loop; + end if; + New_Line; + Put ("desc : "); + Put (Hex_Image (Descsz)); + Put (" "); + Is_Full := Descsz >= 20; + for I in 1 .. Descsz loop + if Is_Full and (I mod 16) = 1 then + New_Line; + end if; + Read_Byte (Base, Off, B); + Put (' '); + Put (Hex_Image (B)); + end loop; + if Descsz mod 4 /= 0 then + for I in (Descsz mod 4) .. 3 loop + Read_Byte (Base, Off, B); + end loop; + end if; + New_Line; + end loop; + end Disp_Note; + + procedure Disp_Section_Note (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + Base : Address; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + Disp_Note (Base, Storage_Offset (Shdr.Sh_Size)); + end Disp_Section_Note; + + procedure Disp_Segment_Note (File : Elf_File; Index : Elf_Half) + is + Phdr : Elf_Phdr_Acc; + Base : Address; + begin + Phdr := Get_Phdr (File, Index); + Base := Get_Segment_Base (File, Phdr.all); + Disp_Note (Base, Storage_Offset (Phdr.P_Filesz)); + end Disp_Segment_Note; + + + function Get_Dt_Name (Name : Elf_Word) return String is + begin + case Name is + when DT_NULL => + return "NULL"; + when DT_NEEDED => + return "NEEDED"; + when DT_PLTRELSZ => + return "PLTRELSZ"; + when DT_PLTGOT => + return "PLTGOT"; + when DT_HASH => + return "HASH"; + when DT_STRTAB => + return "STRTAB"; + when DT_SYMTAB => + return "SYMTAB"; + when DT_RELA => + return "RELA"; + when DT_RELASZ => + return "RELASZ"; + when DT_RELAENT => + return "RELAENT"; + when DT_STRSZ => + return "STRSZ"; + when DT_SYMENT => + return "SYMENT"; + when DT_INIT => + return "INIT"; + when DT_FINI => + return "FINI"; + when DT_SONAME => + return "SONAME"; + when DT_RPATH => + return "RPATH"; + when DT_SYMBOLIC => + return "SYMBOLIC"; + when DT_REL => + return "REL"; + when DT_RELSZ => + return "RELSZ"; + when DT_RELENT => + return "RELENT"; + when DT_PLTREL => + return "PLTREL"; + when DT_DEBUG => + return "DEBUG"; + when DT_TEXTREL => + return "TEXTREL"; + when DT_JMPREL => + return "JMPREL"; + when DT_BIND_NOW => + return "BIND_NOW"; + when DT_INIT_ARRAY => + return "INIT_ARRAY"; + when DT_FINI_ARRAY => + return "FINI_ARRAY"; + when DT_INIT_ARRAYSZ => + return "INIT_ARRAYSZ"; + when DT_FINI_ARRAYSZ => + return "FINI_ARRAYSZ"; + when DT_RUNPATH => + return "RUNPATH"; + when DT_FLAGS => + return "FLAGS"; +-- when DT_ENCODING => +-- return "ENCODING"; + when DT_PREINIT_ARRAY => + return "PREINIT_ARRAY"; + when DT_PREINIT_ARRAYSZ => + return "PREINIT_ARRAYSZ"; + when DT_NUM => + return "NUM"; + when DT_LOOS => + return "LOOS"; +-- when DT_HIOS => +-- return "HIOS"; + when DT_LOPROC => + return "LOPROC"; +-- when DT_HIPROC => +-- return "HIPROC"; + when DT_VALRNGLO => + return "VALRNGLO"; + when DT_GNU_PRELINKED => + return "GNU_PRELINKED"; + when DT_GNU_CONFLICTSZ => + return "GNU_CONFLICTSZ"; + when DT_GNU_LIBLISTSZ => + return "GNU_LIBLISTSZ"; + when DT_CHECKSUM => + return "CHECKSUM"; + when DT_PLTPADSZ => + return "PLTPADSZ"; + when DT_MOVEENT => + return "MOVEENT"; + when DT_MOVESZ => + return "MOVESZ"; + when DT_FEATURE_1 => + return "FEATURE_1"; + when DT_POSFLAG_1 => + return "POSFLAG_1"; + when DT_SYMINSZ => + return "SYMINSZ"; + when DT_SYMINENT => + return "SYMINENT"; +-- when DT_VALRNGHI => +-- return "VALRNGHI"; + when DT_ADDRRNGLO => + return "ADDRRNGLO"; + when DT_GNU_CONFLICT => + return "GNU_CONFLICT"; + when DT_GNU_LIBLIST => + return "GNU_LIBLIST"; + when DT_CONFIG => + return "CONFIG"; + when DT_DEPAUDIT => + return "DEPAUDIT"; + when DT_AUDIT => + return "AUDIT"; + when DT_PLTPAD => + return "PLTPAD"; + when DT_MOVETAB => + return "MOVETAB"; + when DT_SYMINFO => + return "SYMINFO"; +-- when DT_ADDRRNGHI => +-- return "ADDRRNGHI"; + when DT_VERSYM => + return "VERSYM"; + when DT_RELACOUNT => + return "RELACOUNT"; + when DT_RELCOUNT => + return "RELCOUNT"; + when DT_FLAGS_1 => + return "FLAGS_1"; + when DT_VERDEF => + return "VERDEF"; + when DT_VERDEFNUM => + return "VERDEFNUM"; + when DT_VERNEED => + return "VERNEED"; + when DT_VERNEEDNUM => + return "VERNEEDNUM"; + when DT_AUXILIARY => + return "AUXILIARY"; + when DT_FILTER => + return "FILTER"; + when others => + return "?unknown?"; + end case; + end Get_Dt_Name; + + procedure Disp_Dynamic (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + Base : Address; + Off : Storage_Offset; + Tag : Unsigned_32; + Val : Unsigned_32; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Read_Word4 (Base, Off, Tag); + Read_Word4 (Base, Off, Val); + Put ("tag : "); + Put (Hex_Image (Tag)); + Put (" ("); + Put (Get_Dt_Name (Tag)); + Put (")"); + Set_Col (34); + Put ("val : "); + Put (Hex_Image (Val)); + New_Line; + end loop; + end Disp_Dynamic; + + function Get_Dwarf_Form_Name (Name : Unsigned_32) return String + is + use Dwarf; + begin + case Name is + when DW_FORM_Addr => + return "addr"; + when DW_FORM_Block2 => + return "block2"; + when DW_FORM_Block4 => + return "block4"; + when DW_FORM_Data2 => + return "data2"; + when DW_FORM_Data4 => + return "data4"; + when DW_FORM_Data8 => + return "data8"; + when DW_FORM_String => + return "string"; + when DW_FORM_Block => + return "block"; + when DW_FORM_Block1 => + return "block1"; + when DW_FORM_Data1 => + return "data1"; + when DW_FORM_Flag => + return "flag"; + when DW_FORM_Sdata => + return "sdata"; + when DW_FORM_Strp => + return "strp"; + when DW_FORM_Udata => + return "udata"; + when DW_FORM_Ref_Addr => + return "ref_addr"; + when DW_FORM_Ref1 => + return "ref1"; + when DW_FORM_Ref2 => + return "ref2"; + when DW_FORM_Ref4 => + return "ref4"; + when DW_FORM_Ref8 => + return "ref8"; + when DW_FORM_Ref_Udata => + return "ref_udata"; + when DW_FORM_Indirect => + return "indirect"; + when others => + return "unknown"; + end case; + end Get_Dwarf_Form_Name; + + function Get_Dwarf_Tag_Name (Tag : Unsigned_32) return String + is + use Dwarf; + begin + case Tag is + when DW_TAG_Array_Type => + return "array_type"; + when DW_TAG_Class_Type => + return "class_type"; + when DW_TAG_Entry_Point => + return "entry_point"; + when DW_TAG_Enumeration_Type => + return "enumeration_type"; + when DW_TAG_Formal_Parameter => + return "formal_parameter"; + when DW_TAG_Imported_Declaration => + return "imported_declaration"; + when DW_TAG_Label => + return "label"; + when DW_TAG_Lexical_Block => + return "lexical_block"; + when DW_TAG_Member => + return "member"; + when DW_TAG_Pointer_Type => + return "pointer_type"; + when DW_TAG_Reference_Type => + return "reference_type"; + when DW_TAG_Compile_Unit => + return "compile_unit"; + when DW_TAG_String_Type => + return "string_type"; + when DW_TAG_Structure_Type => + return "structure_type"; + when DW_TAG_Subroutine_Type => + return "subroutine_type"; + when DW_TAG_Typedef => + return "typedef"; + when DW_TAG_Union_Type => + return "union_type"; + when DW_TAG_Unspecified_Parameters => + return "unspecified_parameters"; + when DW_TAG_Variant => + return "variant"; + when DW_TAG_Common_Block => + return "common_block"; + when DW_TAG_Common_Inclusion => + return "common_inclusion"; + when DW_TAG_Inheritance => + return "inheritance"; + when DW_TAG_Inlined_Subroutine => + return "inlined_subroutine"; + when DW_TAG_Module => + return "module"; + when DW_TAG_Ptr_To_Member_Type => + return "ptr_to_member_type"; + when DW_TAG_Set_Type => + return "set_type"; + when DW_TAG_Subrange_Type => + return "subrange_type"; + when DW_TAG_With_Stmt => + return "with_stmt"; + when DW_TAG_Access_Declaration => + return "access_declaration"; + when DW_TAG_Base_Type => + return "base_type"; + when DW_TAG_Catch_Block => + return "catch_block"; + when DW_TAG_Const_Type => + return "const_type"; + when DW_TAG_Constant => + return "constant"; + when DW_TAG_Enumerator => + return "enumerator"; + when DW_TAG_File_Type => + return "file_type"; + when DW_TAG_Friend => + return "friend"; + when DW_TAG_Namelist => + return "namelist"; + when DW_TAG_Namelist_Item => + return "namelist_item"; + when DW_TAG_Packed_Type => + return "packed_type"; + when DW_TAG_Subprogram => + return "subprogram"; + when DW_TAG_Template_Type_Parameter => + return "template_type_parameter"; + when DW_TAG_Template_Value_Parameter => + return "template_value_parameter"; + when DW_TAG_Thrown_Type => + return "thrown_type"; + when DW_TAG_Try_Block => + return "try_block"; + when DW_TAG_Variant_Part => + return "variant_part"; + when DW_TAG_Variable => + return "variable"; + when DW_TAG_Volatile_Type => + return "volatile_type"; + when DW_TAG_Dwarf_Procedure => + return "dwarf_procedure"; + when DW_TAG_Restrict_Type => + return "restrict_type"; + when DW_TAG_Interface_Type => + return "interface_type"; + when DW_TAG_Namespace => + return "namespace"; + when DW_TAG_Imported_Module => + return "imported_module"; + when DW_TAG_Unspecified_Type => + return "unspecified_type"; + when DW_TAG_Partial_Unit => + return "partial_unit"; + when DW_TAG_Imported_Unit => + return "imported_unit"; + when DW_TAG_Mutable_Type => + return "mutable_type"; + when others => + return "unknown"; + end case; + end Get_Dwarf_Tag_Name; + + function Get_Dwarf_At_Name (Attr : Unsigned_32) return String + is + use Dwarf; + begin + case Attr is + when DW_AT_Sibling => + return "sibling"; + when DW_AT_Location => + return "location"; + when DW_AT_Name => + return "name"; + when DW_AT_Ordering => + return "ordering"; + when DW_AT_Byte_Size => + return "byte_size"; + when DW_AT_Bit_Offset => + return "bit_offset"; + when DW_AT_Bit_Size => + return "bit_size"; + when DW_AT_Stmt_List => + return "stmt_list"; + when DW_AT_Low_Pc => + return "low_pc"; + when DW_AT_High_Pc => + return "high_pc"; + when DW_AT_Language => + return "language"; + when DW_AT_Discr => + return "discr"; + when DW_AT_Discr_Value => + return "discr_value"; + when DW_AT_Visibility => + return "visibility"; + when DW_AT_Import => + return "import"; + when DW_AT_String_Length => + return "string_length"; + when DW_AT_Common_Reference => + return "common_reference"; + when DW_AT_Comp_Dir => + return "comp_dir"; + when DW_AT_Const_Value => + return "const_value"; + when DW_AT_Containing_Type => + return "containing_type"; + when DW_AT_Default_Value => + return "default_value"; + when DW_AT_Inline => + return "inline"; + when DW_AT_Is_Optional => + return "is_optional"; + when DW_AT_Lower_Bound => + return "lower_bound"; + when DW_AT_Producer => + return "producer"; + when DW_AT_Prototyped => + return "prototyped"; + when DW_AT_Return_Addr => + return "return_addr"; + when DW_AT_Start_Scope => + return "start_scope"; + when DW_AT_Stride_Size => + return "stride_size"; + when DW_AT_Upper_Bound => + return "upper_bound"; + when DW_AT_Abstract_Origin => + return "abstract_origin"; + when DW_AT_Accessibility => + return "accessibility"; + when DW_AT_Address_Class => + return "address_class"; + when DW_AT_Artificial => + return "artificial"; + when DW_AT_Base_Types => + return "base_types"; + when DW_AT_Calling_Convention => + return "calling_convention"; + when DW_AT_Count => + return "count"; + when DW_AT_Data_Member_Location => + return "data_member_location"; + when DW_AT_Decl_Column => + return "decl_column"; + when DW_AT_Decl_File => + return "decl_file"; + when DW_AT_Decl_Line => + return "decl_line"; + when DW_AT_Declaration => + return "declaration"; + when DW_AT_Discr_List => + return "discr_list"; + when DW_AT_Encoding => + return "encoding"; + when DW_AT_External => + return "external"; + when DW_AT_Frame_Base => + return "frame_base"; + when DW_AT_Friend => + return "friend"; + when DW_AT_Identifier_Case => + return "identifier_case"; + when DW_AT_Macro_Info => + return "macro_info"; + when DW_AT_Namelist_Item => + return "namelist_item"; + when DW_AT_Priority => + return "priority"; + when DW_AT_Segment => + return "segment"; + when DW_AT_Specification => + return "specification"; + when DW_AT_Static_Link => + return "static_link"; + when DW_AT_Type => + return "type"; + when DW_AT_Use_Location => + return "use_location"; + when DW_AT_Variable_Parameter => + return "variable_parameter"; + when DW_AT_Virtuality => + return "virtuality"; + when DW_AT_Vtable_Elem_Location => + return "vtable_elem_location"; + when DW_AT_Allocated => + return "allocated"; + when DW_AT_Associated => + return "associated"; + when DW_AT_Data_Location => + return "data_location"; + when DW_AT_Stride => + return "stride"; + when DW_AT_Entry_Pc => + return "entry_pc"; + when DW_AT_Use_UTF8 => + return "use_utf8"; + when DW_AT_Extension => + return "extension"; + when DW_AT_Ranges => + return "ranges"; + when DW_AT_Trampoline => + return "trampoline"; + when DW_AT_Call_Column => + return "call_column"; + when DW_AT_Call_File => + return "call_file"; + when DW_AT_Call_Line => + return "call_line"; + when DW_AT_Description => + return "description"; + when others => + return "unknown"; + end case; + end Get_Dwarf_At_Name; + + procedure Disp_Debug_Abbrev (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + Base : Address; + Old_Off : Storage_Offset; + Off : Storage_Offset; + V : Unsigned_32; + Tag : Unsigned_32; + Name : Unsigned_32; + Form : Unsigned_32; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Old_Off := Off; + Read_ULEB128 (Base, Off, V); + Put_Line ("abbrev #" & Hex_Image (V) & " at " + & Hex_Image (Unsigned_32 (Old_Off)) & ':'); + if V = 0 then + Put_Line ("pad"); + goto Again; + end if; + Read_ULEB128 (Base, Off, Tag); + Put (" tag: " & Hex_Image (Tag)); + Put (" ("); + Put (Get_Dwarf_Tag_Name (Tag)); + Put ("), children: " & Hex_Image (Read_Byte (Base + Off))); + New_Line; + Off := Off + 1; + loop + Read_ULEB128 (Base, Off, Name); + Read_ULEB128 (Base, Off, Form); + Put (" name: " & Hex_Image (Name)); + Put (" ("); + Put (Get_Dwarf_At_Name (Name)); + Put (")"); + Set_Col (42); + Put ("form: " & Hex_Image (Form)); + Put (" ("); + Put (Get_Dwarf_Form_Name (Form)); + Put (")"); + New_Line; + exit when Name = 0 and Form = 0; + end loop; + << Again >> null; + end loop; + end Disp_Debug_Abbrev; + + type Abbrev_Map_Type is array (Unsigned_32 range <>) of Address; + type Abbrev_Map_Acc is access Abbrev_Map_Type; + procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation + (Abbrev_Map_Type, Abbrev_Map_Acc); + + procedure Build_Abbrev_Map (Base : Address; Res : out Abbrev_Map_Acc) + is + Max : Unsigned_32; + Off : Storage_Offset; + V : Unsigned_32; + V1 : Unsigned_32; + N_Res : Abbrev_Map_Acc; + begin + Off := 0; + Max := 0; + Res := new Abbrev_Map_Type (0 .. 128); + Res.all := (others => Null_Address); + loop + Read_ULEB128 (Base, Off, V); + if V > Max then + Max := V; + end if; + exit when V = 0; + if Max > Res.all'Last then + N_Res := new Abbrev_Map_Type (0 .. 2 * Max); + N_Res (Res'Range) := Res.all; + N_Res (Res'Last + 1 .. N_Res'Last) := (others => Null_Address); + Unchecked_Deallocation (Res); + Res := N_Res; + end if; + if Res (V) /= Null_Address then + Put_Line ("!! abbrev override !!"); + return; + end if; + Res (V) := Base + Off; + Read_ULEB128 (Base, Off, V); + -- Skip child flag. + Off := Off + 1; + loop + Read_ULEB128 (Base, Off, V); + Read_ULEB128 (Base, Off, V1); + exit when V = 0 and V1 = 0; + end loop; + end loop; + end Build_Abbrev_Map; + + procedure Disp_Block (Base : Address; + Off : in out Storage_Offset; + Cnt : Unsigned_32) + is + begin + for I in 1 .. Cnt loop + Put (" "); + Put (Hex_Image (Read_Byte (Base + Off + Storage_Offset (I - 1)))); + end loop; + Off := Off + Storage_Offset (Cnt); + end Disp_Block; + + procedure Disp_Dwarf_Form (Base : Address; + Off : in out Storage_Offset; + Form : Unsigned_32) + is + use Dwarf; + begin + case Form is + when DW_FORM_Addr => + declare + V : Unsigned_32; + begin + Read_Word4 (Base, Off, V); + Put ("address: " & Hex_Image (V)); + end; + when DW_FORM_Flag => + declare + V : Unsigned_8; + begin + Read_Byte (Base, Off, V); + Put ("flag: " & Hex_Image (V)); + end; + when DW_FORM_Block1 => + declare + V : Unsigned_8; + begin + Read_Byte (Base, Off, V); + Put ("block1: " & Hex_Image (V)); + Disp_Block (Base, Off, Unsigned_32 (V)); + end; + when DW_FORM_Data1 => + declare + V : Unsigned_8; + begin + Read_Byte (Base, Off, V); + Put ("data1: " & Hex_Image (V)); + end; + when DW_FORM_Data2 => + declare + V : Unsigned_16; + begin + Read_Word2 (Base, Off, V); + Put ("data2: " & Hex_Image (V)); + end; + when DW_FORM_Data4 => + declare + V : Unsigned_32; + begin + Read_Word4 (Base, Off, V); + Put ("data4: " & Hex_Image (V)); + end; + when DW_FORM_Sdata => + declare + V : Unsigned_32; + begin + Read_SLEB128 (Base, Off, V); + Put ("sdata: " & Hex_Image (V)); + end; + when DW_FORM_Udata => + declare + V : Unsigned_32; + begin + Read_ULEB128 (Base, Off, V); + Put ("udata: " & Hex_Image (V)); + end; + when DW_FORM_Ref4 => + declare + V : Unsigned_32; + begin + Read_Word4 (Base, Off, V); + Put ("ref4: " & Hex_Image (V)); + end; + when DW_FORM_Strp => + declare + V : Unsigned_32; + begin + Read_Word4 (Base, Off, V); + Put ("strp: " & Hex_Image (V)); + end; + when DW_FORM_String => + declare + C : Unsigned_8; + begin + Put ("string: "); + loop + Read_Byte (Base, Off, C); + exit when C = 0; + Put (Character'Val (C)); + end loop; + end; + when others => + Put ("???"); + raise Program_Error; + end case; + end Disp_Dwarf_Form; + + function Get_Dwarf_ATE_Name (Val : Unsigned_32) return String + is + use Dwarf; + begin + case Val is + when DW_ATE_Address => + return "address"; + when DW_ATE_Boolean => + return "boolean"; + when DW_ATE_Complex_Float => + return "complex_float"; + when DW_ATE_Float => + return "float"; + when DW_ATE_Signed => + return "signed"; + when DW_ATE_Signed_Char => + return "signed_char"; + when DW_ATE_Unsigned => + return "unsigned"; + when DW_ATE_Unsigned_Char => + return "unsigned_char"; + when DW_ATE_Imaginary_Float => + return "imaginary_float"; + when others => + return "unknown"; + end case; + end Get_Dwarf_ATE_Name; + + procedure Read_Dwarf_Constant (Base : Address; + Off : in out Storage_Offset; + Form : Unsigned_32; + Res : out Unsigned_32) + is + use Dwarf; + begin + case Form is + when DW_FORM_Data1 => + declare + V : Unsigned_8; + begin + Read_Byte (Base, Off, V); + Res := Unsigned_32 (V); + end; + when DW_FORM_Data2 => + declare + V : Unsigned_16; + begin + Read_Word2 (Base, Off, V); + Res := Unsigned_32 (V); + end; + when DW_FORM_Data4 => + declare + V : Unsigned_32; + begin + Read_Word4 (Base, Off, V); + Res := V; + end; + when DW_FORM_Sdata => + declare + V : Unsigned_32; + begin + Read_SLEB128 (Base, Off, V); + Res := V; + end; + when others => + raise Program_Error; + end case; + end Read_Dwarf_Constant; + + procedure Disp_Dwarf_Encoding + (Base : Address; Off : in out Storage_Offset; Form : Unsigned_32) + is + Val : Unsigned_32; + begin + Read_Dwarf_Constant (Base, Off, Form, Val); + Put (Get_Dwarf_ATE_Name (Val)); + end Disp_Dwarf_Encoding; + + function Get_Dwarf_Lang_Name (Lang : Unsigned_32) return String + is + use Dwarf; + begin + case Lang is + when DW_LANG_C89 => + return "C89"; + when DW_LANG_C => + return "C"; + when DW_LANG_Ada83 => + return "Ada83"; + when DW_LANG_C_Plus_Plus => + return "C_Plus_Plus"; + when DW_LANG_Cobol74 => + return "Cobol74"; + when DW_LANG_Cobol85 => + return "Cobol85"; + when DW_LANG_Fortran77 => + return "Fortran77"; + when DW_LANG_Fortran90 => + return "Fortran90"; + when DW_LANG_Pascal83 => + return "Pascal83"; + when DW_LANG_Modula2 => + return "Modula2"; + when DW_LANG_Java => + return "Java"; + when DW_LANG_C99 => + return "C99"; + when DW_LANG_Ada95 => + return "Ada95"; + when DW_LANG_Fortran95 => + return "Fortran95"; + when DW_LANG_PLI => + return "PLI"; + when others => + return "?unknown?"; + end case; + end Get_Dwarf_Lang_Name; + + procedure Disp_Dwarf_Language + (Base : Address; Off : in out Storage_Offset; Form : Unsigned_32) + is + Val : Unsigned_32; + begin + Read_Dwarf_Constant (Base, Off, Form, Val); + Put (Get_Dwarf_Lang_Name (Val)); + end Disp_Dwarf_Language; + + function Get_Dwarf_Op_Name (Op : Unsigned_8) return String + is + use Dwarf; + begin + case Op is + when DW_OP_Addr => + return "addr"; + when DW_OP_Deref => + return "deref"; + when DW_OP_Const1u => + return "const1u"; + when DW_OP_Const1s => + return "const1s"; + when DW_OP_Const2u => + return "const2u"; + when DW_OP_Const2s => + return "const2s"; + when DW_OP_Const4u => + return "const4u"; + when DW_OP_Const4s => + return "const4s"; + when DW_OP_Const8u => + return "const8u"; + when DW_OP_Const8s => + return "const8s"; + when DW_OP_Constu => + return "constu"; + when DW_OP_Consts => + return "consts"; + when DW_OP_Dup => + return "dup"; + when DW_OP_Drop => + return "drop"; + when DW_OP_Over => + return "over"; + when DW_OP_Pick => + return "pick"; + when DW_OP_Swap => + return "swap"; + when DW_OP_Rot => + return "rot"; + when DW_OP_Xderef => + return "xderef"; + when DW_OP_Abs => + return "abs"; + when DW_OP_And => + return "and"; + when DW_OP_Div => + return "div"; + when DW_OP_Minus => + return "minus"; + when DW_OP_Mod => + return "mod"; + when DW_OP_Mul => + return "mul"; + when DW_OP_Neg => + return "neg"; + when DW_OP_Not => + return "not"; + when DW_OP_Or => + return "or"; + when DW_OP_Plus => + return "plus"; + when DW_OP_Plus_Uconst => + return "plus_uconst"; + when DW_OP_Shl => + return "shl"; + when DW_OP_Shr => + return "shr"; + when DW_OP_Shra => + return "shra"; + when DW_OP_Xor => + return "xor"; + when DW_OP_Skip => + return "skip"; + when DW_OP_Bra => + return "bra"; + when DW_OP_Eq => + return "eq"; + when DW_OP_Ge => + return "ge"; + when DW_OP_Gt => + return "gt"; + when DW_OP_Le => + return "le"; + when DW_OP_Lt => + return "lt"; + when DW_OP_Ne => + return "ne"; + when DW_OP_Lit0 => + return "lit0"; + when DW_OP_Lit1 => + return "lit1"; + when DW_OP_Lit2 => + return "lit2"; + when DW_OP_Lit3 => + return "lit3"; + when DW_OP_Lit4 => + return "lit4"; + when DW_OP_Lit5 => + return "lit5"; + when DW_OP_Lit6 => + return "lit6"; + when DW_OP_Lit7 => + return "lit7"; + when DW_OP_Lit8 => + return "lit8"; + when DW_OP_Lit9 => + return "lit9"; + when DW_OP_Lit10 => + return "lit10"; + when DW_OP_Lit11 => + return "lit11"; + when DW_OP_Lit12 => + return "lit12"; + when DW_OP_Lit13 => + return "lit13"; + when DW_OP_Lit14 => + return "lit14"; + when DW_OP_Lit15 => + return "lit15"; + when DW_OP_Lit16 => + return "lit16"; + when DW_OP_Lit17 => + return "lit17"; + when DW_OP_Lit18 => + return "lit18"; + when DW_OP_Lit19 => + return "lit19"; + when DW_OP_Lit20 => + return "lit20"; + when DW_OP_Lit21 => + return "lit21"; + when DW_OP_Lit22 => + return "lit22"; + when DW_OP_Lit23 => + return "lit23"; + when DW_OP_Lit24 => + return "lit24"; + when DW_OP_Lit25 => + return "lit25"; + when DW_OP_Lit26 => + return "lit26"; + when DW_OP_Lit27 => + return "lit27"; + when DW_OP_Lit28 => + return "lit28"; + when DW_OP_Lit29 => + return "lit29"; + when DW_OP_Lit30 => + return "lit30"; + when DW_OP_Lit31 => + return "lit31"; + when DW_OP_Reg0 => + return "reg0"; + when DW_OP_Reg1 => + return "reg1"; + when DW_OP_Reg2 => + return "reg2"; + when DW_OP_Reg3 => + return "reg3"; + when DW_OP_Reg4 => + return "reg4"; + when DW_OP_Reg5 => + return "reg5"; + when DW_OP_Reg6 => + return "reg6"; + when DW_OP_Reg7 => + return "reg7"; + when DW_OP_Reg8 => + return "reg8"; + when DW_OP_Reg9 => + return "reg9"; + when DW_OP_Reg10 => + return "reg10"; + when DW_OP_Reg11 => + return "reg11"; + when DW_OP_Reg12 => + return "reg12"; + when DW_OP_Reg13 => + return "reg13"; + when DW_OP_Reg14 => + return "reg14"; + when DW_OP_Reg15 => + return "reg15"; + when DW_OP_Reg16 => + return "reg16"; + when DW_OP_Reg17 => + return "reg17"; + when DW_OP_Reg18 => + return "reg18"; + when DW_OP_Reg19 => + return "reg19"; + when DW_OP_Reg20 => + return "reg20"; + when DW_OP_Reg21 => + return "reg21"; + when DW_OP_Reg22 => + return "reg22"; + when DW_OP_Reg23 => + return "reg23"; + when DW_OP_Reg24 => + return "reg24"; + when DW_OP_Reg25 => + return "reg25"; + when DW_OP_Reg26 => + return "reg26"; + when DW_OP_Reg27 => + return "reg27"; + when DW_OP_Reg28 => + return "reg28"; + when DW_OP_Reg29 => + return "reg29"; + when DW_OP_Reg30 => + return "reg30"; + when DW_OP_Reg31 => + return "reg31"; + when DW_OP_Breg0 => + return "breg0"; + when DW_OP_Breg1 => + return "breg1"; + when DW_OP_Breg2 => + return "breg2"; + when DW_OP_Breg3 => + return "breg3"; + when DW_OP_Breg4 => + return "breg4"; + when DW_OP_Breg5 => + return "breg5"; + when DW_OP_Breg6 => + return "breg6"; + when DW_OP_Breg7 => + return "breg7"; + when DW_OP_Breg8 => + return "breg8"; + when DW_OP_Breg9 => + return "breg9"; + when DW_OP_Breg10 => + return "breg10"; + when DW_OP_Breg11 => + return "breg11"; + when DW_OP_Breg12 => + return "breg12"; + when DW_OP_Breg13 => + return "breg13"; + when DW_OP_Breg14 => + return "breg14"; + when DW_OP_Breg15 => + return "breg15"; + when DW_OP_Breg16 => + return "breg16"; + when DW_OP_Breg17 => + return "breg17"; + when DW_OP_Breg18 => + return "breg18"; + when DW_OP_Breg19 => + return "breg19"; + when DW_OP_Breg20 => + return "breg20"; + when DW_OP_Breg21 => + return "breg21"; + when DW_OP_Breg22 => + return "breg22"; + when DW_OP_Breg23 => + return "breg23"; + when DW_OP_Breg24 => + return "breg24"; + when DW_OP_Breg25 => + return "breg25"; + when DW_OP_Breg26 => + return "breg26"; + when DW_OP_Breg27 => + return "breg27"; + when DW_OP_Breg28 => + return "breg28"; + when DW_OP_Breg29 => + return "breg29"; + when DW_OP_Breg30 => + return "breg30"; + when DW_OP_Breg31 => + return "breg31"; + when DW_OP_Regx => + return "regx"; + when DW_OP_Fbreg => + return "fbreg"; + when DW_OP_Bregx => + return "bregx"; + when DW_OP_Piece => + return "piece"; + when DW_OP_Deref_Size => + return "deref_size"; + when DW_OP_Xderef_Size => + return "xderef_size"; + when DW_OP_Nop => + return "nop"; + when DW_OP_Push_Object_Address => + return "push_object_address"; + when DW_OP_Call2 => + return "call2"; + when DW_OP_Call4 => + return "call4"; + when DW_OP_Call_Ref => + return "call_ref"; + when others => + return "unknown"; + end case; + end Get_Dwarf_Op_Name; + + procedure Read_Dwarf_Block (Base : Address; + Off : in out Storage_Offset; + Form : Unsigned_32; + B : out Address; + L : out Unsigned_32) + is + use Dwarf; + begin + case Form is + when DW_FORM_Block1 => + B := Base + Off + 1; + L := Unsigned_32 (Read_Byte (Base + Off)); + Off := Off + 1; + when others => + raise Program_Error; + end case; + Off := Off + Storage_Offset (L); + end Read_Dwarf_Block; + + procedure Disp_Dwarf_Location + (Base : Address; Off : in out Storage_Offset; Form : Unsigned_32) + is + use Dwarf; + B : Address; + L : Unsigned_32; + Op : Unsigned_8; + Boff : Storage_Offset; + Is_Full : Boolean; + begin + Read_Dwarf_Block (Base, Off, Form, B, L); + if L = 0 then + return; + end if; + Is_Full := L > 6; + Boff := 0; + while Boff < Storage_Offset (L) loop + if Is_Full then + New_Line; + Put (" "); + Put (Hex_Image (Unsigned_32 (Boff))); + Put (": "); + end if; + Op := Read_Byte (B + Boff); + Put (' '); + Put (Get_Dwarf_Op_Name (Op)); + Boff := Boff + 1; + case Op is + when DW_OP_Addr => + declare + V : Unsigned_32; + begin + Read_Word4 (B, Boff, V); + Put (':'); + Put (Hex_Image (V)); + end; + when DW_OP_Deref => + null; + when DW_OP_Const1u + | DW_OP_Const1s => + declare + V : Unsigned_8; + begin + Read_Byte (B, Boff, V); + Put (':'); + Put (Hex_Image (V)); + end; +-- DW_OP_Const2u : constant := 16#0a#; -- 1 2-byte constant +-- DW_OP_Const2s : constant := 16#0b#; -- 1 2-byte constant +-- DW_OP_Const4u : constant := 16#0c#; -- 1 4-byte constant +-- DW_OP_Const4s : constant := 16#0d#; -- 1 4-byte constant +-- DW_OP_Const8u : constant := 16#0e#; -- 1 8-byte constant +-- DW_OP_Const8s : constant := 16#0f#; -- 1 8-byte constant +-- DW_OP_Constu : constant := 16#10#; -- 1 ULEB128 constant +-- DW_OP_Consts : constant := 16#11#; -- 1 SLEB128 constant +-- DW_OP_Dup : constant := 16#12#; -- 0 +-- DW_OP_Drop : constant := 16#13#; -- 0 +-- DW_OP_Over : constant := 16#14#; -- 0 +-- DW_OP_Pick : constant := 16#15#; -- 1 1-byte stack index + + when DW_OP_Swap + | DW_OP_Rot + | DW_OP_Xderef + | DW_OP_Abs + | DW_OP_And + | DW_OP_Div + | DW_OP_Minus + | DW_OP_Mod + | DW_OP_Mul + | DW_OP_Neg + | DW_OP_Not + | DW_OP_Or + | DW_OP_Plus => + null; + when DW_OP_Plus_Uconst + | DW_OP_Piece + | DW_OP_Regx => + declare + V : Unsigned_32; + begin + Read_ULEB128 (B, Boff, V); + Put (':'); + Put (Hex_Image (V)); + end; + when DW_OP_Shl + | DW_OP_Shr + | DW_OP_Shra + | DW_OP_Xor => + null; + when DW_OP_Skip + | DW_OP_Bra => + declare + V : Unsigned_16; + begin + Read_Word2 (B, Boff, V); + Put (':'); + Put (Hex_Image (V)); + Put (" (@"); + -- FIXME: signed + Put (Hex_Image (Unsigned_32 (Boff) + Unsigned_32 (V))); + Put (")"); + end; + when DW_OP_Eq + | DW_OP_Ge + | DW_OP_Gt + | DW_OP_Le + | DW_OP_Lt + | DW_OP_Ne => + null; + when DW_OP_Lit0 .. DW_OP_Lit31 => + null; + when DW_OP_Reg0 .. DW_OP_Reg31 => + null; + when DW_OP_Breg0 .. DW_OP_Breg31 + | DW_OP_Fbreg => + declare + V : Unsigned_32; + begin + Read_SLEB128 (B, Boff, V); + Put (':'); + Put (Hex_Image (V)); + end; + +-- DW_OP_Regx : constant := 16#90#; -- 1 ULEB128 register +-- DW_OP_Bregx : constant := 16#92#; -- 2 ULEB128 reg + SLEB128 offset +-- DW_OP_Deref_Size : constant := 16#94#; -- 1 1-byte size of data retrieved +-- DW_OP_Xderef_Size : constant := 16#95#; -- 1 1-byte size of data retrieved + when DW_OP_Nop => + null; +-- DW_OP_Push_Object_Address : constant := 16#97#; -- 0 +-- DW_OP_Call2 : constant := 16#98#; -- 1 2-byte offset of DIE +-- DW_OP_Call4 : constant := 16#99#; -- 1 4-byte offset of DIE +-- DW_OP_Call_Ref : constant := 16#9a#; -- 1 4- or 8-byte offset of DIE + when others => + raise Program_Error; + end case; + end loop; + end Disp_Dwarf_Location; + + procedure Disp_Debug_Info (File : Elf_File; Index : Elf_Half) + is + use Dwarf; + + Abbrev_Index : Elf_Half; + Abbrev_Base : Address; + Map : Abbrev_Map_Acc; + Abbrev : Address; + + Shdr : Elf_Shdr_Acc; + Base : Address; + Off : Storage_Offset; + Aoff : Storage_Offset; + Old_Off : Storage_Offset; + + Len : Unsigned_32; + Ver : Unsigned_16; + Abbrev_Off : Unsigned_32; + Ptr_Sz : Unsigned_8; + Last : Storage_Offset; + Num : Unsigned_32; + + Tag : Unsigned_32; + Name : Unsigned_32; + Form : Unsigned_32; + + Level : Unsigned_8; + begin + Abbrev_Index := Get_Section_By_Name (File, ".debug_abbrev"); + Abbrev_Base := Get_Section_Base (File, Abbrev_Index); + Map := null; + + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Put_Line ("Compilation unit at #" + & Hex_Image (Unsigned_32 (Off)) & ":"); + Read_Word4 (Base, Off, Len); + Last := Off + Storage_Offset (Len); + Read_Word2 (Base, Off, Ver); + Read_Word4 (Base, Off, Abbrev_Off); + Read_Byte (Base, Off, Ptr_Sz); + Put (' '); + Put ("length: " & Hex_Image (Len)); + Put (", version: " & Hex_Image (Ver)); + Put (", abbrev offset: " & Hex_Image (Abbrev_Off)); + Put (", ptr_sz: " & Hex_Image (Ptr_Sz)); + New_Line; + Level := 0; + + Build_Abbrev_Map (Abbrev_Base + Storage_Offset (Abbrev_Off), Map); + loop + << Again >> null; + exit when Off >= Last; + Old_Off := Off; + Read_ULEB128 (Base, Off, Num); + Put ("<" & Hex_Image (Unsigned_32 (Old_Off)) & ">"); + Put ("<" & Hex_Image (Level) & ">"); + Put (" with abbrev #" & Hex_Image (Num)); + if Num = 0 then + Level := Level - 1; + New_Line; + goto Again; + end if; + if Num <= Map.all'Last then + Abbrev := Map (Num); + else + Abbrev := Null_Address; + end if; + if Abbrev = Null_Address then + New_Line; + Put ("!! abbrev #" & Hex_Image (Num) & " does not exist !!"); + New_Line; + return; + end if; + Aoff := 0; + Read_ULEB128 (Abbrev, Aoff, Tag); + if Read_Byte (Abbrev + Aoff) /= 0 then + Put (" [has_child]"); + Level := Level + 1; + end if; + New_Line; + + -- skip child. + Aoff := Aoff + 1; + Put (" tag: " & Hex_Image (Tag)); + Put (" ("); + Put (Get_Dwarf_Tag_Name (Tag)); + Put (")"); + New_Line; + + loop + Read_ULEB128 (Abbrev, Aoff, Name); + Read_ULEB128 (Abbrev, Aoff, Form); + exit when Name = 0 and Form = 0; + Put (" "); + Put (Get_Dwarf_At_Name (Name)); + Set_Col (24); + Put (": "); + Old_Off := Off; + Disp_Dwarf_Form (Base, Off, Form); + case Name is + when DW_AT_Encoding => + Put (": "); + Disp_Dwarf_Encoding (Base, Old_Off, Form); + when DW_AT_Location + | DW_AT_Frame_Base + | DW_AT_Data_Member_Location => + Put (":"); + Disp_Dwarf_Location (Base, Old_Off, Form); + when DW_AT_Language => + Put (": "); + Disp_Dwarf_Language (Base, Old_Off, Form); + when others => + null; + end case; + New_Line; + end loop; + end loop; + Unchecked_Deallocation (Map); + New_Line; + end loop; + end Disp_Debug_Info; + + function Get_Phdr_Type_Name (Ptype : Elf_Word) return String is + begin + case Ptype is + when PT_NULL => + return "NULL"; + when PT_LOAD => + return "LOAD"; + when PT_DYNAMIC => + return "DYNAMIC"; + when PT_INTERP => + return "INTERP"; + when PT_NOTE => + return "NOTE"; + when PT_SHLIB => + return "SHLIB"; + when PT_PHDR => + return "PHDR"; + when PT_TLS => + return "TLS"; + when PT_NUM => + return "NUM"; + when PT_GNU_EH_FRAME => + return "GNU_EH_FRAME"; + when PT_SUNWBSS => + return "SUNWBSS"; + when PT_SUNWSTACK => + return "SUNWSTACK"; + when others => + return "?unknown?"; + end case; + end Get_Phdr_Type_Name; + + procedure Disp_Phdr (Phdr : Elf_Phdr) + is + begin + Put ("type : " & Hex_Image (Phdr.P_Type)); + Put (" "); + Put (Get_Phdr_Type_Name (Phdr.P_Type)); + New_Line; + Put ("offset: " & Hex_Image (Phdr.P_Offset)); + Put (" vaddr: " & Hex_Image (Phdr.P_Vaddr)); + Put (" paddr: " & Hex_Image (Phdr.P_Paddr)); + New_Line; + Put ("filesz: " & Hex_Image (Phdr.P_Filesz)); + Put (" memsz: " & Hex_Image (Phdr.P_Memsz)); + Put (" align: " & Hex_Image (Phdr.P_Align)); + --New_Line; + Put (" flags: " & Hex_Image (Phdr.P_Flags)); + Put (" ("); + if (Phdr.P_Flags and PF_X) /= 0 then + Put ('X'); + end if; + if (Phdr.P_Flags and PF_W) /= 0 then + Put ('W'); + end if; + if (Phdr.P_Flags and PF_R) /= 0 then + Put ('R'); + end if; + Put (")"); + New_Line; + end Disp_Phdr; + + procedure Disp_Debug_Pubnames (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + Base : Address; + Off : Storage_Offset; + B : Unsigned_8; + + Len : Unsigned_32; + Ver : Unsigned_16; + Info_Off : Unsigned_32; + Info_Length : Unsigned_32; + Last : Storage_Offset; + Ioff : Unsigned_32; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Read_Word4 (Base, Off, Len); + Last := Off + Storage_Offset (Len); + Read_Word2 (Base, Off, Ver); + Read_Word4 (Base, Off, Info_Off); + Read_Word4 (Base, Off, Info_Length); + Put ("length: " & Hex_Image (Len)); + Put (", version: " & Hex_Image (Ver)); + Put (", offset: " & Hex_Image (Info_Off)); + Put (", length: " & Hex_Image (Info_Length)); + New_Line; + + loop + Read_Word4 (Base, Off, Ioff); + Put (" "); + Put (Hex_Image (Ioff)); + if Ioff /= 0 then + Put (": "); + loop + Read_Byte (Base, Off, B); + exit when B = 0; + Put (Character'Val (B)); + end loop; + end if; + New_Line; + exit when Ioff = 0; + end loop; + end loop; + end Disp_Debug_Pubnames; + + procedure Disp_Debug_Aranges (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + Base : Address; + Off : Storage_Offset; + + Set_Len : Unsigned_32; + Ver : Unsigned_16; + Info_Off : Unsigned_32; + Last : Storage_Offset; + Addr_Sz : Unsigned_8; + Seg_Sz : Unsigned_8; + Pad : Unsigned_32; + + Addr : Unsigned_32; + Len : Unsigned_32; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Read_Word4 (Base, Off, Set_Len); + Last := Off + Storage_Offset (Set_Len); + Read_Word2 (Base, Off, Ver); + Read_Word4 (Base, Off, Info_Off); + Read_Byte (Base, Off, Addr_Sz); + Read_Byte (Base, Off, Seg_Sz); + Read_Word4 (Base, Off, Pad); + Put ("length: " & Hex_Image (Set_Len)); + Put (", version: " & Hex_Image (Ver)); + Put (", offset: " & Hex_Image (Info_Off)); + Put (", ptr_sz: " & Hex_Image (Addr_Sz)); + Put (", seg_sz: " & Hex_Image (Seg_Sz)); + New_Line; + + loop + Read_Word4 (Base, Off, Addr); + Read_Word4 (Base, Off, Len); + Put (" "); + Put (Hex_Image (Addr)); + Put ('+'); + Put (Hex_Image (Len)); + New_Line; + exit when Addr = 0 and Len = 0; + end loop; + end loop; + end Disp_Debug_Aranges; + + procedure Disp_String (Base : Address; Off : in out Storage_Offset) + is + B : Unsigned_8; + begin + loop + B := Read_Byte (Base + Off); + Off := Off + 1; + exit when B = 0; + Put (Character'Val (B)); + end loop; + end Disp_String; + + procedure Read_String (Base : Address; Off : in out Storage_Offset) + is + B : Unsigned_8; + begin + loop + Read_Byte (Base, Off, B); + exit when B = 0; + end loop; + end Read_String; + + function Get_Dwarf_LNS_Name (Lns : Unsigned_8) return String + is + use Dwarf; + begin + case Lns is + when DW_LNS_Copy => + return "copy"; + when DW_LNS_Advance_Pc => + return "advance_pc"; + when DW_LNS_Advance_Line => + return "advance_line"; + when DW_LNS_Set_File => + return "set_file"; + when DW_LNS_Set_Column => + return "set_column"; + when DW_LNS_Negate_Stmt => + return "negate_stmt"; + when DW_LNS_Set_Basic_Block => + return "set_basic_block"; + when DW_LNS_Const_Add_Pc => + return "const_add_pc"; + when DW_LNS_Fixed_Advance_Pc => + return "fixed_advance_pc"; + when DW_LNS_Set_Prologue_End => + return "set_prologue_end"; + when DW_LNS_Set_Epilogue_Begin => + return "set_epilogue_begin"; + when DW_LNS_Set_Isa => + return "set_isa"; + when others => + return "?unknown?"; + end case; + end Get_Dwarf_LNS_Name; + + procedure Disp_Debug_Line (File : Elf_File; Index : Elf_Half) + is + use Dwarf; + Shdr : Elf_Shdr_Acc; + Base : Address; + Off : Storage_Offset; + + type Opc_Length_Type is array (Unsigned_8 range <>) of Unsigned_8; + type Opc_Length_Acc is access Opc_Length_Type; + Opc_Length : Opc_Length_Acc; + + Total_Len : Unsigned_32; + Version : Unsigned_16; + Prolog_Len : Unsigned_32; + Min_Insn_Len : Unsigned_8; + Dflt_Is_Stmt : Unsigned_8; + Line_Base : Unsigned_8; + Line_Range : Unsigned_8; + Opc_Base : Unsigned_8; + + B : Unsigned_8; + Arg : Unsigned_32; + + Old_Off : Storage_Offset; + File_Dir : Unsigned_32; + File_Time : Unsigned_32; + File_Len : Unsigned_32; + + Ext_Len : Unsigned_32; + Ext_Opc : Unsigned_8; + + Last : Storage_Offset; + + Pc : Unsigned_32; + Line : Unsigned_32; + Line_Base2 : Unsigned_32; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Read_Word4 (Base, Off, Total_Len); + Last := Off + Storage_Offset (Total_Len); + Read_Word2 (Base, Off, Version); + Read_Word4 (Base, Off, Prolog_Len); + Read_Byte (Base, Off, Min_Insn_Len); + Read_Byte (Base, Off, Dflt_Is_Stmt); + Read_Byte (Base, Off, Line_Base); + Read_Byte (Base, Off, Line_Range); + Read_Byte (Base, Off, Opc_Base); + + Pc := 0; + Line := 1; + + Put ("length: " & Hex_Image (Total_Len)); + Put (", version: " & Hex_Image (Version)); + Put (", prolog_len: " & Hex_Image (Prolog_Len)); + New_Line; + Put (" minimum_instruction_len: " & Hex_Image (Min_Insn_Len)); + Put (", default_is_stmt: " & Hex_Image (Dflt_Is_Stmt)); + New_Line; + Put (" line_base: " & Hex_Image (Line_Base)); + Put (", line_range: " & Hex_Image (Line_Range)); + Put (", opc_base: " & Hex_Image (Opc_Base)); + New_Line; + Line_Base2 := Unsigned_32 (Line_Base); + if (Line_Base and 16#80#) /= 0 then + Line_Base2 := Line_Base2 or 16#Ff_Ff_Ff_00#; + end if; + Put_Line ("standard_opcode_length:"); + Opc_Length := new Opc_Length_Type (1 .. Opc_Base - 1); + for I in 1 .. Opc_Base - 1 loop + Read_Byte (Base, Off, B); + Put (' '); + Put (Hex_Image (I)); + Put (" => "); + Put (Hex_Image (B)); + Opc_Length (I) := B; + New_Line; + end loop; + Put_Line ("include_directories:"); + loop + B := Read_Byte (Base + Off); + exit when B = 0; + Put (' '); + Disp_String (Base, Off); + New_Line; + end loop; + Off := Off + 1; + Put_Line ("file_names:"); + loop + B := Read_Byte (Base + Off); + exit when B = 0; + Old_Off := Off; + Read_String (Base, Off); + Read_ULEB128 (Base, Off, File_Dir); + Read_ULEB128 (Base, Off, File_Time); + Read_ULEB128 (Base, Off, File_Len); + Put (' '); + Put (Hex_Image (File_Dir)); + Put (' '); + Put (Hex_Image (File_Time)); + Put (' '); + Put (Hex_Image (File_Len)); + Put (' '); + Disp_String (Base, Old_Off); + New_Line; + end loop; + Off := Off + 1; + + while Off < Last loop + Put (" "); + Read_Byte (Base, Off, B); + Put (Hex_Image (B)); + Old_Off := Off; + if B < Opc_Base then + case B is + when 0 => + Put (" (extended)"); + Read_ULEB128 (Base, Off, Ext_Len); + Put (", len: "); + Put (Hex_Image (Ext_Len)); + Old_Off := Off; + Read_Byte (Base, Off, Ext_Opc); + Put (" opc:"); + Put (Hex_Image (Ext_Opc)); + Off := Old_Off + Storage_Offset (Ext_Len); + when others => + Put (" ("); + Put (Get_Dwarf_LNS_Name (B)); + Put (")"); + Set_Col (20); + for J in 1 .. Opc_Length (B) loop + Read_ULEB128 (Base, Off, Arg); + Put (" "); + Put (Hex_Image (Arg)); + end loop; + end case; + case B is + when DW_LNS_Copy => + Put (" pc="); + Put (Hex_Image (Pc)); + Put (", line="); + Put (Unsigned_32'Image (Line)); + when DW_LNS_Advance_Pc => + Read_ULEB128 (Base, Old_Off, Arg); + Pc := Pc + Arg * Unsigned_32 (Min_Insn_Len); + Put (" pc="); + Put (Hex_Image (Pc)); + when DW_LNS_Advance_Line => + Read_SLEB128 (Base, Old_Off, Arg); + Line := Line + Arg; + Put (" line="); + Put (Unsigned_32'Image (Line)); + when DW_LNS_Set_File => + null; + when DW_LNS_Set_Column => + null; + when DW_LNS_Negate_Stmt => + null; + when DW_LNS_Set_Basic_Block => + null; + when DW_LNS_Const_Add_Pc => + Pc := Pc + Unsigned_32 ((255 - Opc_Base) / Line_Range) + * Unsigned_32 (Min_Insn_Len); + Put (" pc="); + Put (Hex_Image (Pc)); + when others => + null; + end case; + New_Line; + else + B := B - Opc_Base; + Pc := Pc + Unsigned_32 (B / Line_Range) + * Unsigned_32 (Min_Insn_Len); + Line := Line + Line_Base2 + Unsigned_32 (B mod Line_Range); + Put (" pc="); + Put (Hex_Image (Pc)); + Put (", line="); + Put (Unsigned_32'Image (Line)); + New_Line; + end if; + end loop; + end loop; + end Disp_Debug_Line; + + function Get_Dwarf_Cfi_Name (Cfi : Unsigned_8) return String + is + use Dwarf; + begin + case Cfi is + when DW_CFA_Advance_Loc_Min .. DW_CFA_Advance_Loc_Max => + return "advance_loc"; + when DW_CFA_Offset_Min .. DW_CFA_Offset_Max => + return "offset"; + when DW_CFA_Restore_Min .. DW_CFA_Restore_Max => + return "restore"; + when DW_CFA_Nop => + return "nop"; + when DW_CFA_Set_Loc => + return "set_loc"; + when DW_CFA_Advance_Loc1 => + return "advance_loc1"; + when DW_CFA_Advance_Loc2 => + return "advance_loc2"; + when DW_CFA_Advance_Loc4 => + return "advance_loc4"; + when DW_CFA_Offset_Extended => + return "offset_extended"; + when DW_CFA_Restore_Extended => + return "restore_extended"; + when DW_CFA_Undefined => + return "undefined"; + when DW_CFA_Same_Value => + return "same_value"; + when DW_CFA_Register => + return "register"; + when DW_CFA_Remember_State => + return "remember_state"; + when DW_CFA_Restore_State => + return "restore_state"; + when DW_CFA_Def_Cfa => + return "def_cfa"; + when DW_CFA_Def_Cfa_Register => + return "def_cfa_register"; + when DW_CFA_Def_Cfa_Offset => + return "def_cfa_offset"; + when DW_CFA_Def_Cfa_Expression => + return "def_cfa_expression"; + when others => + return "?unknown?"; + end case; + end Get_Dwarf_Cfi_Name; + + procedure Disp_Cfi (Base : Address; Length : Storage_Count) + is + use Dwarf; + L : Storage_Offset; + Op : Unsigned_8; + Off : Unsigned_32; + Reg : Unsigned_32; + begin + L := 0; + while L < Length loop + Op := Read_Byte (Base + L); + Put (" "); + Put (Hex_Image (Op)); + Put (" "); + Put (Get_Dwarf_Cfi_Name (Op)); + Put (" "); + L := L + 1; + case Op is + when DW_CFA_Nop => + null; + when DW_CFA_Advance_Loc_Min .. DW_CFA_Advance_Loc_Max => + Put (Hex_Image (Op and 16#3f#)); + when DW_CFA_Offset_Min .. DW_CFA_Offset_Max => + Read_ULEB128 (Base, L, Off); + Put ("reg:"); + Put (Hex_Image (Op and 16#3f#)); + Put (", offset:"); + Put (Hex_Image (Off)); + when DW_CFA_Def_Cfa => + Read_ULEB128 (Base, L, Reg); + Read_ULEB128 (Base, L, Off); + Put ("reg:"); + Put (Hex_Image (Reg)); + Put (", offset:"); + Put (Hex_Image (Off)); + when DW_CFA_Def_Cfa_Offset => + Read_ULEB128 (Base, L, Off); + Put (Hex_Image (Off)); + when DW_CFA_Def_Cfa_Register => + Read_ULEB128 (Base, L, Reg); + Put ("reg:"); + Put (Hex_Image (Reg)); + when others => + Put ("?unknown?"); + New_Line; + exit; + end case; + New_Line; + end loop; + end Disp_Cfi; + + procedure Disp_Debug_Frame (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + Base : Address; + Off : Storage_Offset; + Old_Off : Storage_Offset; + + Length : Unsigned_32; + Cie_Id : Unsigned_32; + Version : Unsigned_8; + Augmentation : Unsigned_8; + Code_Align : Unsigned_32; + Data_Align : Unsigned_32; + Ret_Addr_Reg : Unsigned_8; + + Init_Loc : Unsigned_32; + Addr_Rng : Unsigned_32; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Read_Word4 (Base, Off, Length); + Old_Off := Off; + + Read_Word4 (Base, Off, Cie_Id); + if Cie_Id = 16#Ff_Ff_Ff_Ff# then + Read_Byte (Base, Off, Version); + Read_Byte (Base, Off, Augmentation); + Put ("length: "); + Put (Hex_Image (Length)); + Put (", CIE_id: "); + Put (Hex_Image (Cie_Id)); + Put (", version: "); + Put (Hex_Image (Version)); + if Augmentation /= 0 then + Put (" +augmentation"); + New_Line; + else + New_Line; + Read_ULEB128 (Base, Off, Code_Align); + Read_SLEB128 (Base, Off, Data_Align); + Read_Byte (Base, Off, Ret_Addr_Reg); + Put ("code_align: "); + Put (Hex_Image (Code_Align)); + Put (", data_align: "); + Put (Hex_Image (Data_Align)); + Put (", ret_addr_reg: "); + Put (Hex_Image (Ret_Addr_Reg)); + New_Line; + Put ("initial instructions:"); + New_Line; + Disp_Cfi (Base + Off, Old_Off + Storage_Offset (Length) - Off); + end if; + else + Read_Word4 (Base, Off, Init_Loc); + Read_Word4 (Base, Off, Addr_Rng); + Put ("length: "); + Put (Hex_Image (Length)); + Put (", CIE_pointer: "); + Put (Hex_Image (Cie_Id)); + Put (", address_range: "); + Put (Hex_Image (Init_Loc)); + Put ("-"); + Put (Hex_Image (Init_Loc + Addr_Rng)); + New_Line; + Put ("instructions:"); + New_Line; + Disp_Cfi (Base + Off, Old_Off + Storage_Offset (Length) - Off); + end if; + Off := Old_Off + Storage_Offset (Length); + end loop; + end Disp_Debug_Frame; + + procedure Read_Coded (Base : Address; + Offset : in out Storage_Offset; + Code : Unsigned_8; + Val : out Unsigned_32) + is + use Dwarf; + + V2 : Unsigned_16; + begin + if Code = DW_EH_PE_Omit then + return; + end if; + case Code and DW_EH_PE_Format_Mask is + when DW_EH_PE_Uleb128 => + Read_ULEB128 (Base, Offset, Val); + when DW_EH_PE_Udata2 => + Read_Word2 (Base, Offset, V2); + Val := Unsigned_32 (V2); + when DW_EH_PE_Udata4 => + Read_Word4 (Base, Offset, Val); + when DW_EH_PE_Sleb128 => + Read_SLEB128 (Base, Offset, Val); + when DW_EH_PE_Sdata2 => + Read_Word2 (Base, Offset, V2); + Val := Unsigned_32 (V2); + if (V2 and 16#80_00#) /= 0 then + Val := Val or 16#Ff_Ff_00_00#; + end if; + when DW_EH_PE_Sdata4 => + Read_Word4 (Base, Offset, Val); + when others => + raise Program_Error; + end case; + end Read_Coded; + + procedure Disp_Eh_Frame_Hdr (File : Elf_File; Index : Elf_Half) + is + Shdr : Elf_Shdr_Acc; + Base : Address; + Off : Storage_Offset; + + Version : Unsigned_8; + Eh_Frame_Ptr_Enc : Unsigned_8; + Fde_Count_Enc : Unsigned_8; + Table_Enc : Unsigned_8; + + Eh_Frame_Ptr : Unsigned_32; + Fde_Count : Unsigned_32; + + Loc : Unsigned_32; + Addr : Unsigned_32; + begin + Shdr := Get_Shdr (File, Index); + Base := Get_Section_Base (File, Shdr.all); + + Off := 0; + while Off < Storage_Offset (Shdr.Sh_Size) loop + Read_Byte (Base, Off, Version); + Read_Byte (Base, Off, Eh_Frame_Ptr_Enc); + Read_Byte (Base, Off, Fde_Count_Enc); + Read_Byte (Base, Off, Table_Enc); + Put ("version: "); + Put (Hex_Image (Version)); + Put (", encodings: ptr:"); + Put (Hex_Image (Eh_Frame_Ptr_Enc)); + Put (" count:"); + Put (Hex_Image (Fde_Count_Enc)); + Put (" table:"); + Put (Hex_Image (Table_Enc)); + New_Line; + Read_Coded (Base, Off, Eh_Frame_Ptr_Enc, Eh_Frame_Ptr); + Read_Coded (Base, Off, Fde_Count_Enc, Fde_Count); + Put ("eh_frame_ptr: "); + Put (Hex_Image (Eh_Frame_Ptr)); + Put (", fde_count: "); + Put (Hex_Image (Fde_Count)); + New_Line; + for I in 1 .. Fde_Count loop + Read_Coded (Base, Off, Table_Enc, Loc); + Read_Coded (Base, Off, Table_Enc, Addr); + Put (" init loc: "); + Put (Hex_Image (Loc)); + Put (", addr : "); + Put (Hex_Image (Addr)); + New_Line; + end loop; + end loop; + end Disp_Eh_Frame_Hdr; +end Elfdumper; diff --git a/src/ortho/mcode/elfdumper.ads b/src/ortho/mcode/elfdumper.ads new file mode 100644 index 000000000..0227f0f41 --- /dev/null +++ b/src/ortho/mcode/elfdumper.ads @@ -0,0 +1,164 @@ +-- ELF dumper (library). +-- 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 System; use System; +with Elf_Common; use Elf_Common; +with Elf_Arch; use Elf_Arch; +with Ada.Unchecked_Conversion; + +package Elfdumper is + procedure Disp_Ehdr (Ehdr : Elf_Ehdr); + + type Strtab_Fat_Type is array (Elf_Size) of Character; + type Strtab_Fat_Acc is access all Strtab_Fat_Type; + + type Strtab_Type is record + Base : Strtab_Fat_Acc; + Length : Elf_Size; + end record; + + Null_Strtab : constant Strtab_Type := (null, 0); + + Nul : constant Character := Character'Val (0); + + function Get_String (Strtab : Strtab_Type; N : Elf_Size) + return String; + + procedure Disp_Shdr (Shdr : Elf_Shdr; Sh_Strtab : Strtab_Type); + + type Elf_Shdr_Array is array (Elf_Half range <>) of Elf_Shdr; + + type Elf_File is limited private; + type Elf_File_Status is + ( + -- No error. + Status_Ok, + + -- Cannot open file. + Status_Open_Failure, + + Status_Bad_File, + Status_Memory, + Status_Read_Error, + Status_Bad_Magic, + Status_Bad_Class + ); + + procedure Open_File (File : out Elf_File; Filename : String); + + function Get_Status (File : Elf_File) return Elf_File_Status; + + type Elf_Ehdr_Acc is access all Elf_Ehdr; + + function Get_Ehdr (File : Elf_File) return Elf_Ehdr_Acc; + + procedure Load_Shdr (File : in out Elf_File); + + type Elf_Shdr_Acc is access all Elf_Shdr; + + function Get_Shdr (File : Elf_File; Index : Elf_Half) + return Elf_Shdr_Acc; + + function Get_Shdr_Type_Name (Stype : Elf_Word) return String; + + procedure Load_Phdr (File : in out Elf_File); + + type Elf_Phdr_Acc is access all Elf_Phdr; + + function Get_Phdr (File : Elf_File; Index : Elf_Half) + return Elf_Phdr_Acc; + + function Get_Segment_Base (File : Elf_File; Index : Elf_Half) + return Address; + + function Get_Sh_Strtab (File : Elf_File) return Strtab_Type; + + procedure Disp_Sym (File : Elf_File; + Sym : Elf_Sym; + Strtab : Strtab_Type); + + procedure Disp_Symtab (File : Elf_File; Index : Elf_Half); + procedure Disp_Strtab (File : Elf_File; Index : Elf_Half); + + function Get_Section_Name (File : Elf_File; Index : Elf_Half) + return String; + + function Get_Section_By_Name (File : Elf_File; Name : String) + return Elf_Half; + + procedure Disp_Debug_Abbrev (File : Elf_File; Index : Elf_Half); + procedure Disp_Debug_Info (File : Elf_File; Index : Elf_Half); + procedure Disp_Debug_Pubnames (File : Elf_File; Index : Elf_Half); + procedure Disp_Debug_Aranges (File : Elf_File; Index : Elf_Half); + procedure Disp_Debug_Line (File : Elf_File; Index : Elf_Half); + procedure Disp_Debug_Frame (File : Elf_File; Index : Elf_Half); + procedure Disp_Eh_Frame_Hdr (File : Elf_File; Index : Elf_Half); + + procedure Disp_Phdr (Phdr : Elf_Phdr); + + procedure Disp_Segment_Note (File : Elf_File; Index : Elf_Half); + procedure Disp_Section_Note (File : Elf_File; Index : Elf_Half); + + procedure Disp_Dynamic (File : Elf_File; Index : Elf_Half); +private + use System; + + function To_Strtab_Fat_Acc is new Ada.Unchecked_Conversion + (Address, Strtab_Fat_Acc); + + type String_Acc is access String; + + function To_Elf_Ehdr_Acc is new Ada.Unchecked_Conversion + (Address, Elf_Ehdr_Acc); + + function To_Elf_Phdr_Acc is new Ada.Unchecked_Conversion + (Address, Elf_Phdr_Acc); + + function To_Elf_Shdr_Acc is new Ada.Unchecked_Conversion + (Address, Elf_Shdr_Acc); + + type Elf_Sym_Acc is access all Elf_Sym; + function To_Elf_Sym_Acc is new Ada.Unchecked_Conversion + (Address, Elf_Sym_Acc); + + type Elf_Shdr_Arr is array (Elf_Half) of Elf_Shdr; + + type Elf_Shdr_Arr_Acc is access all Elf_Shdr_Arr; + function To_Elf_Shdr_Arr_Acc is new Ada.Unchecked_Conversion + (Address, Elf_Shdr_Arr_Acc); + + type Elf_File is record + -- Name of the file. + Filename : String_Acc; + + -- Status, used to report errors. + Status : Elf_File_Status; + + -- Length of the file. + Length : Elf_Off; + + -- File contents. + Base : Address; + + Ehdr : Elf_Ehdr_Acc; + + Shdr_Base : Address; + Sh_Strtab : Strtab_Type; + + Phdr_Base : Address; + end record; +end Elfdumper; diff --git a/src/ortho/mcode/hex_images.adb b/src/ortho/mcode/hex_images.adb new file mode 100644 index 000000000..a9dca324d --- /dev/null +++ b/src/ortho/mcode/hex_images.adb @@ -0,0 +1,71 @@ +-- To hexadecimal conversions. +-- 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.Unchecked_Conversion; + +package body Hex_Images is + type Hex_Str_Type is array (0 .. 15) of Character; + Hexdigits : constant Hex_Str_Type := "0123456789abcdef"; + + function Hex_Image (B : Unsigned_8) return String is + Res : String (1 .. 2); + begin + for I in 1 .. 2 loop + Res (I) := Hexdigits + (Natural (Shift_Right (B, 8 - 4 * I) and 16#0f#)); + end loop; + return Res; + end Hex_Image; + + function Conv is new Ada.Unchecked_Conversion + (Source => Integer_32, Target => Unsigned_32); + + function Hex_Image (W : Unsigned_32) return String is + Res : String (1 .. 8); + begin + for I in 1 .. 8 loop + Res (I) := Hexdigits + (Natural (Shift_Right (W, 32 - 4 * I) and 16#0f#)); + end loop; + return Res; + end Hex_Image; + + function Hex_Image (W : Unsigned_64) return String is + Res : String (1 .. 16); + begin + for I in 1 .. 16 loop + Res (I) := Hexdigits + (Natural (Shift_Right (W, 64 - 4 * I) and 16#0f#)); + end loop; + return Res; + end Hex_Image; + + function Hex_Image (W : Unsigned_16) return String is + Res : String (1 .. 4); + begin + for I in 1 .. 4 loop + Res (I) := Hexdigits + (Natural (Shift_Right (W, 16 - 4 * I) and 16#0f#)); + end loop; + return Res; + end Hex_Image; + + function Hex_Image (W : Integer_32) return String is + begin + return Hex_Image (Conv (W)); + end Hex_Image; +end Hex_Images; diff --git a/src/ortho/mcode/hex_images.ads b/src/ortho/mcode/hex_images.ads new file mode 100644 index 000000000..830d2ec43 --- /dev/null +++ b/src/ortho/mcode/hex_images.ads @@ -0,0 +1,26 @@ +-- To hexadecimal conversions. +-- 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 Interfaces; use Interfaces; + +package Hex_Images is + function Hex_Image (W : Integer_32) return String; + function Hex_Image (W : Unsigned_32) return String; + function Hex_Image (B : Unsigned_8) return String; + function Hex_Image (W : Unsigned_16) return String; + function Hex_Image (W : Unsigned_64) return String; +end Hex_Images; diff --git a/src/ortho/mcode/memsegs.ads b/src/ortho/mcode/memsegs.ads new file mode 100644 index 000000000..ff7f8947e --- /dev/null +++ b/src/ortho/mcode/memsegs.ads @@ -0,0 +1,3 @@ +with Memsegs_Mmap; +package Memsegs renames Memsegs_Mmap; + diff --git a/src/ortho/mcode/memsegs_c.c b/src/ortho/mcode/memsegs_c.c new file mode 100644 index 000000000..f0a0e27d5 --- /dev/null +++ b/src/ortho/mcode/memsegs_c.c @@ -0,0 +1,133 @@ +/* Memory segment 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. +*/ +#ifndef WINNT + +#define _GNU_SOURCE +#include <sys/mman.h> +#include <stddef.h> +/* #include <stdio.h> */ + +/* TODO: init (get pagesize) + round size, + set rights. +*/ + +#ifdef __APPLE__ +#define MAP_ANONYMOUS MAP_ANON +#else +#define HAVE_MREMAP +#endif + +#ifndef HAVE_MREMAP +#include <string.h> +#endif + +void * +mmap_malloc (int size) +{ + void *res; + res = mmap (NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + /* printf ("mmap (%d) = %p\n", size, res); */ + if (res == MAP_FAILED) + return NULL; + return res; +} + +void * +mmap_realloc (void *ptr, int old_size, int size) +{ + void *res; +#ifdef HAVE_MREMAP + res = mremap (ptr, old_size, size, MREMAP_MAYMOVE); +#else + res = mmap (NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (res == MAP_FAILED) + return NULL; + memcpy (res, ptr, old_size); + munmap (ptr, old_size); +#endif + /* printf ("mremap (%p, %d, %d) = %p\n", ptr, old_size, size, res); */ +#if 0 + if (res == MAP_FAILED) + return NULL; +#endif + return res; +} + +void +mmap_free (void * ptr, int size) +{ + munmap (ptr, size); +} + +void +mmap_rx (void *ptr, int size) +{ + mprotect (ptr, size, PROT_READ | PROT_EXEC); +} + +#else +#include <windows.h> + +void * +mmap_malloc (int size) +{ + void *res; + res = VirtualAlloc (NULL, size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + return res; +} + +void * +mmap_realloc (void *ptr, int old_size, int size) +{ + void *res; + + res = VirtualAlloc (NULL, size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + + if (ptr != NULL) + { + CopyMemory (res, ptr, size > old_size ? old_size : size); + VirtualFree (ptr, old_size, MEM_RELEASE); + } + + return res; +} + +void +mmap_free (void * ptr, int size) +{ + VirtualFree (ptr, size, MEM_RELEASE); +} + +void +mmap_rx (void *ptr, int size) +{ + DWORD old; + + /* This is not supported on every version. + In case of failure, this should still work. */ + VirtualProtect (ptr, size, PAGE_EXECUTE_READ, &old); +} +#endif diff --git a/src/ortho/mcode/memsegs_mmap.adb b/src/ortho/mcode/memsegs_mmap.adb new file mode 100644 index 000000000..1ee8e7bcf --- /dev/null +++ b/src/ortho/mcode/memsegs_mmap.adb @@ -0,0 +1,64 @@ +-- Memory segments. +-- 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. +package body Memsegs_Mmap is + function Mmap_Malloc (Size : Natural) return Address; + pragma Import (C, Mmap_Malloc, "mmap_malloc"); + + function Mmap_Realloc (Ptr : Address; Old_Size : Natural; Size : Natural) + return Address; + pragma Import (C, Mmap_Realloc, "mmap_realloc"); + + procedure Mmap_Free (Ptr : Address; Size : Natural); + pragma Import (C, Mmap_Free, "mmap_free"); + + procedure Mmap_Rx (Ptr : Address; Size : Natural); + pragma Import (C, Mmap_Rx, "mmap_rx"); + + function Create return Memseg_Type is + begin + return (Base => Null_Address, Size => 0); + end Create; + + procedure Resize (Seg : in out Memseg_Type; Size : Natural) is + begin + if Seg.Size = 0 then + Seg.Base := Mmap_Malloc (Size); + else + Seg.Base := Mmap_Realloc (Seg.Base, Seg.Size, Size); + end if; + Seg.Size := Size; + end Resize; + + function Get_Address (Seg : Memseg_Type) return Address is + begin + return Seg.Base; + end Get_Address; + + procedure Delete (Seg : in out Memseg_Type) is + begin + Mmap_Free (Seg.Base, Seg.Size); + Seg.Base := Null_Address; + Seg.Size := 0; + end Delete; + + procedure Set_Rx (Seg : in out Memseg_Type) is + begin + Mmap_Rx (Seg.Base, Seg.Size); + end Set_Rx; +end Memsegs_Mmap; + diff --git a/src/ortho/mcode/memsegs_mmap.ads b/src/ortho/mcode/memsegs_mmap.ads new file mode 100644 index 000000000..ba7d76618 --- /dev/null +++ b/src/ortho/mcode/memsegs_mmap.ads @@ -0,0 +1,49 @@ +-- Memory segments. +-- 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 System; use System; + +package Memsegs_Mmap is + -- A memseg is a growable memory space. It can be resized with Resize. + -- After each operation the base address can change and must be get + -- with Get_Address. + type Memseg_Type is private; + + -- Create a new memseg. + function Create return Memseg_Type; + + -- Resize the memseg. + procedure Resize (Seg : in out Memseg_Type; Size : Natural); + + -- Get the base address. + function Get_Address (Seg : Memseg_Type) return Address; + + -- Free all the memory and initialize the memseg. + procedure Delete (Seg : in out Memseg_Type); + + -- Set the protection to read+execute. + procedure Set_Rx (Seg : in out Memseg_Type); + + pragma Inline (Create); + pragma Inline (Get_Address); +private + type Memseg_Type is record + Base : Address := Null_Address; + Size : Natural := 0; + end record; +end Memsegs_Mmap; + diff --git a/src/ortho/mcode/ortho_code-abi.ads b/src/ortho/mcode/ortho_code-abi.ads new file mode 100644 index 000000000..e75b08509 --- /dev/null +++ b/src/ortho/mcode/ortho_code-abi.ads @@ -0,0 +1,3 @@ +with Ortho_Code.X86.Abi; + +package Ortho_Code.Abi renames Ortho_Code.X86.Abi; diff --git a/src/ortho/mcode/ortho_code-binary.adb b/src/ortho/mcode/ortho_code-binary.adb new file mode 100644 index 000000000..7bb6bdd28 --- /dev/null +++ b/src/ortho/mcode/ortho_code-binary.adb @@ -0,0 +1,37 @@ +-- Interface with binary writer for mcode. +-- 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 Ortho_Code.Decls; +with Ortho_Code.Exprs; + +package body Ortho_Code.Binary is + function Get_Decl_Symbol (Decl : O_Dnode) return Symbol + is + begin + return To_Symbol (Decls.Get_Decl_Info (Decl)); + end Get_Decl_Symbol; + + function Get_Label_Symbol (Label : O_Enode) return Symbol is + begin + return To_Symbol (Exprs.Get_Label_Info (Label)); + end Get_Label_Symbol; + + procedure Set_Label_Symbol (Label : O_Enode; Sym : Symbol) is + begin + Exprs.Set_Label_Info (Label, To_Int32 (Sym)); + end Set_Label_Symbol; +end Ortho_Code.Binary; diff --git a/src/ortho/mcode/ortho_code-binary.ads b/src/ortho/mcode/ortho_code-binary.ads new file mode 100644 index 000000000..58c79d3b2 --- /dev/null +++ b/src/ortho/mcode/ortho_code-binary.ads @@ -0,0 +1,31 @@ +-- Interface with binary writer for mcode. +-- 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 Binary_File; use Binary_File; + +package Ortho_Code.Binary is + function To_Symbol is new Ada.Unchecked_Conversion + (Source => Int32, Target => Symbol); + + function To_Int32 is new Ada.Unchecked_Conversion + (Source => Symbol, Target => Int32); + + function Get_Decl_Symbol (Decl : O_Dnode) return Symbol; + function Get_Label_Symbol (Label : O_Enode) return Symbol; + procedure Set_Label_Symbol (Label : O_Enode; Sym : Symbol); +end Ortho_Code.Binary; + diff --git a/src/ortho/mcode/ortho_code-consts.adb b/src/ortho/mcode/ortho_code-consts.adb new file mode 100644 index 000000000..d09a13c34 --- /dev/null +++ b/src/ortho/mcode/ortho_code-consts.adb @@ -0,0 +1,559 @@ +-- Mcode back-end for ortho - Constants 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.Unchecked_Conversion; +with GNAT.Table; +with Ada.Text_IO; +with Ortho_Code.Types; use Ortho_Code.Types; +with Ortho_Code.Debug; + +package body Ortho_Code.Consts is + type Cnode_Common is record + Kind : OC_Kind; + Lit_Type : O_Tnode; + end record; + for Cnode_Common use record + Kind at 0 range 0 .. 31; + Lit_Type at 4 range 0 .. 31; + end record; + for Cnode_Common'Size use 64; + + type Cnode_Signed is record + Val : Integer_64; + end record; + for Cnode_Signed'Size use 64; + + type Cnode_Unsigned is record + Val : Unsigned_64; + end record; + for Cnode_Unsigned'Size use 64; + + type Cnode_Float is record + Val : IEEE_Float_64; + end record; + for Cnode_Float'Size use 64; + + type Cnode_Enum is record + Id : O_Ident; + Val : Uns32; + end record; + for Cnode_Enum'Size use 64; + + type Cnode_Addr is record + Decl : O_Dnode; + Pad : Int32; + end record; + for Cnode_Addr'Size use 64; + + type Cnode_Aggr is record + Els : Int32; + Nbr : Int32; + end record; + for Cnode_Aggr'Size use 64; + + type Cnode_Sizeof is record + Atype : O_Tnode; + Pad : Int32; + end record; + for Cnode_Sizeof'Size use 64; + + type Cnode_Union is record + El : O_Cnode; + Field : O_Fnode; + end record; + for Cnode_Union'Size use 64; + + package Cnodes is new GNAT.Table + (Table_Component_Type => Cnode_Common, + Table_Index_Type => O_Cnode, + Table_Low_Bound => 2, + Table_Initial => 128, + Table_Increment => 100); + + function Get_Const_Kind (Cst : O_Cnode) return OC_Kind is + begin + return Cnodes.Table (Cst).Kind; + end Get_Const_Kind; + + function Get_Const_Type (Cst : O_Cnode) return O_Tnode is + begin + return Cnodes.Table (Cst).Lit_Type; + end Get_Const_Type; + + function Get_Const_U64 (Cst : O_Cnode) return Unsigned_64 + is + function To_Cnode_Unsigned is new Ada.Unchecked_Conversion + (Cnode_Common, Cnode_Unsigned); + begin + return To_Cnode_Unsigned (Cnodes.Table (Cst + 1)).Val; + end Get_Const_U64; + + function Get_Const_I64 (Cst : O_Cnode) return Integer_64 + is + function To_Cnode_Signed is new Ada.Unchecked_Conversion + (Cnode_Common, Cnode_Signed); + begin + return To_Cnode_Signed (Cnodes.Table (Cst + 1)).Val; + end Get_Const_I64; + + function Get_Const_F64 (Cst : O_Cnode) return IEEE_Float_64 + is + function To_Cnode_Float is new Ada.Unchecked_Conversion + (Cnode_Common, Cnode_Float); + begin + return To_Cnode_Float (Cnodes.Table (Cst + 1)).Val; + end Get_Const_F64; + + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Signed, Target => Cnode_Common); + + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode + is + Res : O_Cnode; + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Signed, + Lit_Type => Ltype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Signed'(Val => Value))); + return Res; + end New_Signed_Literal; + + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Unsigned_64, Target => Cnode_Common); + + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode + is + Res : O_Cnode; + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Unsigned, + Lit_Type => Ltype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Value)); + return Res; + end New_Unsigned_Literal; + +-- function Get_Const_Literal (Cst : O_Cnode) return Uns32 is +-- begin +-- return Cnodes.Table (Cst).Val; +-- end Get_Const_Literal; + + function To_Uns64 is new Ada.Unchecked_Conversion + (Source => Cnode_Common, Target => Uns64); + + function Get_Const_U32 (Cst : O_Cnode) return Uns32 is + begin + return Uns32 (To_Uns64 (Cnodes.Table (Cst + 1))); + end Get_Const_U32; + + function Get_Const_R64 (Cst : O_Cnode) return Uns64 is + begin + return To_Uns64 (Cnodes.Table (Cst + 1)); + end Get_Const_R64; + + function Get_Const_Low (Cst : O_Cnode) return Uns32 + is + V : Uns64; + begin + V := Get_Const_R64 (Cst); + return Uns32 (V and 16#Ffff_Ffff#); + end Get_Const_Low; + + function Get_Const_High (Cst : O_Cnode) return Uns32 + is + V : Uns64; + begin + V := Get_Const_R64 (Cst); + return Uns32 (Shift_Right (V, 32) and 16#Ffff_Ffff#); + end Get_Const_High; + + function Get_Const_Low (Cst : O_Cnode) return Int32 + is + V : Uns64; + begin + V := Get_Const_R64 (Cst); + return To_Int32 (Uns32 (V and 16#Ffff_Ffff#)); + end Get_Const_Low; + + function Get_Const_High (Cst : O_Cnode) return Int32 + is + V : Uns64; + begin + V := Get_Const_R64 (Cst); + return To_Int32 (Uns32 (Shift_Right (V, 32) and 16#Ffff_Ffff#)); + end Get_Const_High; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode + is + Res : O_Cnode; + + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Float, Target => Cnode_Common); + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Float, + Lit_Type => Ltype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Float'(Val => Value))); + return Res; + end New_Float_Literal; + + function New_Null_Access (Ltype : O_Tnode) return O_Cnode is + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Null, + Lit_Type => Ltype)); + return Cnodes.Last; + end New_Null_Access; + + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Addr, Target => Cnode_Common); + + function To_Cnode_Addr is new Ada.Unchecked_Conversion + (Source => Cnode_Common, Target => Cnode_Addr); + + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode + is + Res : O_Cnode; + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Address, + Lit_Type => Atype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Addr'(Decl => Decl, + Pad => 0))); + return Res; + end New_Global_Unchecked_Address; + + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode + is + Res : O_Cnode; + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Address, + Lit_Type => Atype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Addr'(Decl => Decl, + Pad => 0))); + return Res; + end New_Global_Address; + + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode + is + Res : O_Cnode; + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Subprg_Address, + Lit_Type => Atype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Addr'(Decl => Subprg, + Pad => 0))); + return Res; + end New_Subprogram_Address; + + function Get_Const_Decl (Cst : O_Cnode) return O_Dnode is + begin + return To_Cnode_Addr (Cnodes.Table (Cst + 1)).Decl; + end Get_Const_Decl; + + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Enum, Target => Cnode_Common); + + function To_Cnode_Enum is new Ada.Unchecked_Conversion + (Source => Cnode_Common, Target => Cnode_Enum); + + --function Get_Named_Literal_Id (Lit : O_Cnode) return O_Ident is + --begin + -- return To_Cnode_Enum (Cnodes.Table (Lit + 1)).Id; + --end Get_Named_Literal_Id; + + function New_Named_Literal + (Atype : O_Tnode; Id : O_Ident; Val : Uns32; Prev : O_Cnode) + return O_Cnode + is + Res : O_Cnode; + begin + Cnodes.Append (Cnode_Common'(Kind => OC_Lit, + Lit_Type => Atype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Enum'(Id => Id, + Val => Val))); + if Prev /= O_Cnode_Null then + if Prev + 2 /= Res then + raise Syntax_Error; + end if; + end if; + return Res; + end New_Named_Literal; + + function Get_Lit_Ident (L : O_Cnode) return O_Ident is + begin + return To_Cnode_Enum (Cnodes.Table (L + 1)).Id; + end Get_Lit_Ident; + + function Get_Lit_Value (L : O_Cnode) return Uns32 is + begin + return To_Cnode_Enum (Cnodes.Table (L + 1)).Val; + end Get_Lit_Value; + + function Get_Lit_Chain (L : O_Cnode) return O_Cnode is + begin + return L + 2; + end Get_Lit_Chain; + + package Els is new GNAT.Table + (Table_Component_Type => O_Cnode, + Table_Index_Type => Int32, + Table_Low_Bound => 2, + Table_Initial => 128, + Table_Increment => 100); + + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Aggr, Target => Cnode_Common); + + function To_Cnode_Aggr is new Ada.Unchecked_Conversion + (Source => Cnode_Common, Target => Cnode_Aggr); + + + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; + Atype : O_Tnode) + is + Val : Int32; + Num : Uns32; + begin + Num := Get_Type_Record_Nbr_Fields (Atype); + Val := Els.Allocate (Integer (Num)); + + Cnodes.Append (Cnode_Common'(Kind => OC_Record, + Lit_Type => Atype)); + List := (Res => Cnodes.Last, + Rec_Field => Get_Type_Record_Fields (Atype), + El => Val); + Cnodes.Append (To_Cnode_Common (Cnode_Aggr'(Els => Val, + Nbr => Int32 (Num)))); + end Start_Record_Aggr; + + + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode) + is + begin + Els.Table (List.El) := Value; + List.El := List.El + 1; + end New_Record_Aggr_El; + + procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; + Res : out O_Cnode) is + begin + Res := List.Res; + end Finish_Record_Aggr; + + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode) + is + Val : Int32; + Num : Uns32; + begin + Num := Get_Type_Subarray_Length (Atype); + Val := Els.Allocate (Integer (Num)); + + Cnodes.Append (Cnode_Common'(Kind => OC_Array, + Lit_Type => Atype)); + List := (Res => Cnodes.Last, + El => Val); + Cnodes.Append (To_Cnode_Common (Cnode_Aggr'(Els => Val, + Nbr => Int32 (Num)))); + end Start_Array_Aggr; + + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode) + is + begin + Els.Table (List.El) := Value; + List.El := List.El + 1; + end New_Array_Aggr_El; + + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode) + is + begin + Res := List.Res; + end Finish_Array_Aggr; + + function Get_Const_Aggr_Length (Cst : O_Cnode) return Int32 is + begin + return To_Cnode_Aggr (Cnodes.Table (Cst + 1)).Nbr; + end Get_Const_Aggr_Length; + + function Get_Const_Aggr_Element (Cst : O_Cnode; N : Int32) return O_Cnode + is + El : Int32; + begin + El := To_Cnode_Aggr (Cnodes.Table (Cst + 1)).Els; + return Els.Table (El + N); + end Get_Const_Aggr_Element; + + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode + is + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Union, Target => Cnode_Common); + + Res : O_Cnode; + begin + if Debug.Flag_Debug_Hli then + Cnodes.Append (Cnode_Common'(Kind => OC_Union, + Lit_Type => Atype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Union'(El => Value, + Field => Field))); + return Res; + else + return Value; + end if; + end New_Union_Aggr; + + function To_Cnode_Union is new Ada.Unchecked_Conversion + (Source => Cnode_Common, Target => Cnode_Union); + + function Get_Const_Union_Field (Cst : O_Cnode) return O_Fnode is + begin + return To_Cnode_Union (Cnodes.Table (Cst + 1)).Field; + end Get_Const_Union_Field; + + function Get_Const_Union_Value (Cst : O_Cnode) return O_Cnode is + begin + return To_Cnode_Union (Cnodes.Table (Cst + 1)).El; + end Get_Const_Union_Value; + + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode + is + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Sizeof, Target => Cnode_Common); + + Res : O_Cnode; + begin + if Debug.Flag_Debug_Hli then + Cnodes.Append (Cnode_Common'(Kind => OC_Sizeof, + Lit_Type => Rtype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Sizeof'(Atype => Atype, + Pad => 0))); + return Res; + else + return New_Unsigned_Literal + (Rtype, Unsigned_64 (Get_Type_Size (Atype))); + end if; + end New_Sizeof; + + function Get_Sizeof_Type (Cst : O_Cnode) return O_Tnode + is + function To_Cnode_Sizeof is new Ada.Unchecked_Conversion + (Cnode_Common, Cnode_Sizeof); + begin + return To_Cnode_Sizeof (Cnodes.Table (Cst + 1)).Atype; + end Get_Sizeof_Type; + + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode + is + function To_Cnode_Common is new Ada.Unchecked_Conversion + (Source => Cnode_Sizeof, Target => Cnode_Common); + + Res : O_Cnode; + begin + if Debug.Flag_Debug_Hli then + Cnodes.Append (Cnode_Common'(Kind => OC_Alignof, + Lit_Type => Rtype)); + Res := Cnodes.Last; + Cnodes.Append (To_Cnode_Common (Cnode_Sizeof'(Atype => Atype, + Pad => 0))); + return Res; + else + return New_Unsigned_Literal + (Rtype, Unsigned_64 (Get_Type_Align_Bytes (Atype))); + end if; + end New_Alignof; + + function Get_Alignof_Type (Cst : O_Cnode) return O_Tnode + is + function To_Cnode_Sizeof is new Ada.Unchecked_Conversion + (Cnode_Common, Cnode_Sizeof); + begin + return To_Cnode_Sizeof (Cnodes.Table (Cst + 1)).Atype; + end Get_Alignof_Type; + + function New_Offsetof (Rec_Type : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode is + begin + if Get_Field_Parent (Field) /= Rec_Type then + raise Syntax_Error; + end if; + return New_Unsigned_Literal + (Rtype, Unsigned_64 (Get_Field_Offset (Field))); + end New_Offsetof; + + procedure Get_Const_Bytes (Cst : O_Cnode; H, L : out Uns32) is + begin + case Get_Const_Kind (Cst) is + when OC_Signed + | OC_Unsigned + | OC_Float => + H := Get_Const_High (Cst); + L := Get_Const_Low (Cst); + when OC_Null => + H := 0; + L := 0; + when OC_Lit => + H := 0; + L := To_Cnode_Enum (Cnodes.Table (Cst + 1)).Val; + when OC_Array + | OC_Record + | OC_Union + | OC_Sizeof + | OC_Alignof + | OC_Address + | OC_Subprg_Address => + raise Syntax_Error; + end case; + end Get_Const_Bytes; + + procedure Mark (M : out Mark_Type) is + begin + M.Cnode := Cnodes.Last; + M.Els := Els.Last; + end Mark; + + procedure Release (M : Mark_Type) is + begin + Cnodes.Set_Last (M.Cnode); + Els.Set_Last (M.Els); + end Release; + + procedure Disp_Stats + is + use Ada.Text_IO; + begin + Put_Line ("Number of Cnodes: " & O_Cnode'Image (Cnodes.Last)); + Put_Line ("Number of Cnodes-Els: " & Int32'Image (Els.Last)); + end Disp_Stats; + + procedure Finish is + begin + Cnodes.Free; + Els.Free; + end Finish; +end Ortho_Code.Consts; diff --git a/src/ortho/mcode/ortho_code-consts.ads b/src/ortho/mcode/ortho_code-consts.ads new file mode 100644 index 000000000..0076bc6eb --- /dev/null +++ b/src/ortho/mcode/ortho_code-consts.ads @@ -0,0 +1,158 @@ +-- Mcode back-end for ortho - Constants 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 Interfaces; use Interfaces; + +package Ortho_Code.Consts is + type OC_Kind is (OC_Signed, OC_Unsigned, OC_Float, OC_Lit, OC_Null, + OC_Array, OC_Record, OC_Union, + OC_Subprg_Address, OC_Address, + OC_Sizeof, OC_Alignof); + + function Get_Const_Kind (Cst : O_Cnode) return OC_Kind; + + function Get_Const_Type (Cst : O_Cnode) return O_Tnode; + + -- Get bytes for signed, unsigned, float, lit, null. + procedure Get_Const_Bytes (Cst : O_Cnode; H, L : out Uns32); + + -- Used to set the length of a constrained type. + -- FIXME: check for no overflow. + function Get_Const_U32 (Cst : O_Cnode) return Uns32; + + function Get_Const_U64 (Cst : O_Cnode) return Unsigned_64; + function Get_Const_I64 (Cst : O_Cnode) return Integer_64; + + function Get_Const_F64 (Cst : O_Cnode) return IEEE_Float_64; + + -- Get the low and high part of a constant. + function Get_Const_Low (Cst : O_Cnode) return Uns32; + function Get_Const_High (Cst : O_Cnode) return Uns32; + + function Get_Const_Low (Cst : O_Cnode) return Int32; + function Get_Const_High (Cst : O_Cnode) return Int32; + + function Get_Const_Aggr_Length (Cst : O_Cnode) return Int32; + function Get_Const_Aggr_Element (Cst : O_Cnode; N : Int32) return O_Cnode; + + -- Only available in HLI. + function Get_Const_Union_Field (Cst : O_Cnode) return O_Fnode; + function Get_Const_Union_Value (Cst : O_Cnode) return O_Cnode; + + -- Declaration for an address. + function Get_Const_Decl (Cst : O_Cnode) return O_Dnode; + + -- Get the type from an OC_Sizeof node. + function Get_Sizeof_Type (Cst : O_Cnode) return O_Tnode; + + -- Get the type from an OC_Alignof node. + function Get_Alignof_Type (Cst : O_Cnode) return O_Tnode; + + -- Get the value of a named literal. + --function Get_Const_Literal (Cst : O_Cnode) return Uns32; + + -- Create a literal from an integer. + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode; + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode; + + -- Create a null access literal. + function New_Null_Access (Ltype : O_Tnode) return O_Cnode; + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + function New_Named_Literal + (Atype : O_Tnode; Id : O_Ident; Val : Uns32; Prev : O_Cnode) + return O_Cnode; + + -- For boolean/enum literals. + function Get_Lit_Ident (L : O_Cnode) return O_Ident; + function Get_Lit_Chain (L : O_Cnode) return O_Cnode; + function Get_Lit_Value (L : O_Cnode) return Uns32; + + type O_Record_Aggr_List is limited private; + type O_Array_Aggr_List is limited private; + + -- Build a record/array aggregate. + -- The aggregate is constant, and therefore can be only used to initialize + -- constant declaration. + -- ATYPE must be either a record type or an array subtype. + -- Elements must be added in the order, and must be literals or aggregates. + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; + Atype : O_Tnode); + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode); + procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; + Res : out O_Cnode); + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode); + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode); + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode); + + -- Build an union aggregate. + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode; + + -- Returns the size in bytes of ATYPE. The result is a literal of + -- unsigned type RTYPE + -- ATYPE cannot be an unconstrained array type. + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the alignment in bytes for ATYPE. The result is a literal of + -- unsgined type RTYPE. + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the offset of FIELD in its record REC_TYPE. The result is a + -- literal of unsigned type or access type RTYPE. + function New_Offsetof (Rec_Type : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode; + + procedure Disp_Stats; + + type Mark_Type is limited private; + procedure Mark (M : out Mark_Type); + procedure Release (M : Mark_Type); + + procedure Finish; +private + type O_Array_Aggr_List is record + Res : O_Cnode; + El : Int32; + end record; + + type O_Record_Aggr_List is record + Res : O_Cnode; + Rec_Field : O_Fnode; + El : Int32; + end record; + + type Mark_Type is record + Cnode : O_Cnode; + Els : Int32; + end record; + +end Ortho_Code.Consts; diff --git a/src/ortho/mcode/ortho_code-debug.adb b/src/ortho/mcode/ortho_code-debug.adb new file mode 100644 index 000000000..0f3e01ab9 --- /dev/null +++ b/src/ortho/mcode/ortho_code-debug.adb @@ -0,0 +1,143 @@ +-- Mcode back-end for ortho - Internal debugging. +-- 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 Ortho_Code.Flags; + +package body Ortho_Code.Debug is + procedure Disp_Mode (M : Mode_Type) + is + use Ada.Text_IO; + begin + case M is + when Mode_U8 => + Put ("U8 "); + when Mode_U16 => + Put ("U16"); + when Mode_U32 => + Put ("U32"); + when Mode_U64 => + Put ("U64"); + when Mode_I8 => + Put ("I8 "); + when Mode_I16 => + Put ("I16"); + when Mode_I32 => + Put ("I32"); + when Mode_I64 => + Put ("I64"); + when Mode_X1 => + Put ("xxx"); + when Mode_Nil => + Put ("Nil"); + when Mode_F32 => + Put ("F32"); + when Mode_F64 => + Put ("F64"); + when Mode_B2 => + Put ("B2 "); + when Mode_Blk => + Put ("Blk"); + when Mode_P32 => + Put ("P32"); + when Mode_P64 => + Put ("P64"); + end case; + end Disp_Mode; + + procedure Set_Debug_Be_Flag (C : Character) + is + use Ada.Text_IO; + begin + case C is + when 'a' => + Flag_Debug_Asm := True; + when 'b' => + Flag_Debug_Body := True; + when 'B' => + Flag_Debug_Body2 := True; + when 'c' => + Flag_Debug_Code := True; + when 'C' => + Flag_Debug_Code2 := True; + when 'd' => + Flag_Debug_Dump := True; + when 'h' => + Flag_Debug_Hex := True; + when 'H' => + Flag_Debug_Hli := True; + when 'i' => + Flag_Debug_Insn := True; + when 's' => + Flag_Debug_Stat := True; + when 'k' => + Flag_Debug_Keep := True; + when 't' => + Flags.Flag_Type_Name := True; + when others => + Put_Line (Standard_Error, "unknown debug be flag '" & C & "'"); + end case; + end Set_Debug_Be_Flag; + + procedure Set_Be_Flag (Str : String) + is + use Ada.Text_IO; + + subtype Str_Type is String (1 .. Str'Length); + S : Str_Type renames Str; + begin + if S'Length > 11 and then S (1 .. 11) = "--be-debug=" then + for I in 12 .. S'Last loop + Set_Debug_Be_Flag (S (I)); + end loop; + elsif S'Length > 10 and then S (1 .. 10) = "--be-dump=" then + for I in 11 .. S'Last loop + case S (I) is + when 'c' => + Flag_Dump_Code := True; + when others => + Put_Line (Standard_Error, + "unknown back-end dump flag '" & S (I) & "'"); + end case; + end loop; + elsif S'Length > 10 and then S (1 .. 10) = "--be-disp=" then + for I in 11 .. S'Last loop + case S (I) is + when 'c' => + Flag_Disp_Code := True; + Flags.Flag_Type_Name := True; + when others => + Put_Line (Standard_Error, + "unknown back-end disp flag '" & S (I) & "'"); + end case; + end loop; + elsif S'Length > 9 and then S (1 .. 9) = "--be-opt=" then + for I in 10 .. S'Last loop + case S (I) is + when 'O' => + Flags.Flag_Optimize := True; + when 'b' => + Flags.Flag_Opt_BB := True; + when others => + Put_Line (Standard_Error, + "unknown back-end opt flag '" & S (I) & "'"); + end case; + end loop; + else + Put_Line (Standard_Error, "unknown back-end option " & Str); + end if; + end Set_Be_Flag; +end Ortho_Code.Debug; diff --git a/src/ortho/mcode/ortho_code-debug.ads b/src/ortho/mcode/ortho_code-debug.ads new file mode 100644 index 000000000..03f550ac9 --- /dev/null +++ b/src/ortho/mcode/ortho_code-debug.ads @@ -0,0 +1,70 @@ +-- Mcode back-end for ortho - Internal debugging. +-- 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; + +package Ortho_Code.Debug is + package Int32_IO is new Ada.Text_IO.Integer_IO (Ortho_Code.Int32); + + procedure Disp_Mode (M : Mode_Type); + + -- Set a debug flag. + procedure Set_Debug_Be_Flag (C : Character); + + -- any '--be-XXX=YY' option. + procedure Set_Be_Flag (Str : String); + + -- c: tree created, before any back-end. + Flag_Disp_Code : Boolean := False; + Flag_Dump_Code : Boolean := False; + + -- a: disp assembly code. + Flag_Debug_Asm : Boolean := False; + + -- A: do internal checks (assertions). + Flag_Debug_Assert : Boolean := True; + + -- b: disp top-level subprogram body before code generation. + Flag_Debug_Body : Boolean := False; + + -- B: disp top-level subprogram body after code generation. + Flag_Debug_Body2 : Boolean := False; + + -- c: display generated code. + Flag_Debug_Code : Boolean := False; + + -- C: display generated code just before asm. + Flag_Debug_Code2 : Boolean := False; + + -- h: disp bytes generated (in hexa). + Flag_Debug_Hex : Boolean := False; + + -- H: generate high-level instructions. + Flag_Debug_Hli : Boolean := False; + + -- r: raw dump, do not generate code. + Flag_Debug_Dump : Boolean := False; + + -- i: disp insns, when generated. + Flag_Debug_Insn : Boolean := False; + + -- s: disp stats (number of nodes). + Flag_Debug_Stat : Boolean := False; + + -- k: keep all nodes in memory (do not free). + Flag_Debug_Keep: Boolean := False; +end Ortho_Code.Debug; diff --git a/src/ortho/mcode/ortho_code-decls.adb b/src/ortho/mcode/ortho_code-decls.adb new file mode 100644 index 000000000..fcbf0b0de --- /dev/null +++ b/src/ortho/mcode/ortho_code-decls.adb @@ -0,0 +1,783 @@ +-- Mcode back-end for ortho - Declarations 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 GNAT.Table; +with Ada.Text_IO; +with Ortho_Ident; +with Ortho_Code.Debug; use Ortho_Code.Debug; +with Ortho_Code.Exprs; +with Ortho_Code.Abi; use Ortho_Code.Abi; +with Ortho_Code.Flags; + +package body Ortho_Code.Decls is + -- Common fields: + -- kind: 4 bits + -- storage: 2 bits + -- reg : 8 bits + -- depth : 16 bits + -- flags: addr + 9 + -- Additionnal fields: + -- OD_Type: Id, dtype + -- OD_Var: Id, Dtype, symbol + -- OD_Local: Id, Dtype, offset/reg + -- OD_Const: Id, Dtype, Val, Symbol? + -- OD_Function: Id, Dtype [interfaces follows], Symbol + -- OD_Procedure: Id [interfaces follows], Symbol + -- OD_Interface: Id, Dtype, offset/reg + -- OD_Begin: Last + -- OD_Body: Decl, Stmt, Parent + type Dnode_Common (Kind : OD_Kind := OD_Type) is record + Storage : O_Storage; + + -- True if the address of the declaration is taken. + Flag_Addr : Boolean; + + Flag2 : Boolean; + + Reg : O_Reg; + + -- Depth of the declaration. + Depth : O_Depth; + + case Kind is + when OD_Type + | OD_Const + | OD_Var + | OD_Local + | OD_Function + | OD_Procedure + | OD_Interface => + -- Identifier of this declaration. + Id : O_Ident; + -- Type of this declaration. + Dtype : O_Tnode; + -- Symbol or offset. + Ref : Int32; + -- For const: the value. + -- For subprg: size of pushed arguments. + Info2 : Int32; + when OD_Subprg_Ext => + -- Chain of interfaces. + Subprg_Inter : O_Dnode; + + when OD_Block => + -- Last declaration of this block. + Last : O_Dnode; + -- Max stack offset. + Block_Max_Stack : Uns32; + -- Infos: may be used to store symbols. + Block_Info1 : Int32; + Block_Info2 : Int32; + when OD_Body => + -- Corresponding declaration (function/procedure). + Body_Decl : O_Dnode; + -- Entry statement for this body. + Body_Stmt : O_Enode; + -- Parent (as a body) of this body or null if at top level. + Body_Parent : O_Dnode; + Body_Info : Int32; + when OD_Const_Val => + -- Corresponding declaration. + Val_Decl : O_Dnode; + -- Value. + Val_Val : O_Cnode; + end case; + end record; + + Use_Subprg_Ext : constant Boolean := False; + + pragma Pack (Dnode_Common); + + package Dnodes is new GNAT.Table + (Table_Component_Type => Dnode_Common, + Table_Index_Type => O_Dnode, + Table_Low_Bound => O_Dnode_First, + Table_Initial => 128, + Table_Increment => 100); + + package TDnodes is new GNAT.Table + (Table_Component_Type => O_Dnode, + Table_Index_Type => O_Tnode, + Table_Low_Bound => O_Tnode_First, + Table_Initial => 1, + Table_Increment => 100); + + Context : O_Dnode := O_Dnode_Null; + + function Get_Decl_Type (Decl : O_Dnode) return O_Tnode is + begin + return Dnodes.Table (Decl).Dtype; + end Get_Decl_Type; + + function Get_Decl_Kind (Decl : O_Dnode) return OD_Kind is + begin + return Dnodes.Table (Decl).Kind; + end Get_Decl_Kind; + + function Get_Decl_Storage (Decl : O_Dnode) return O_Storage is + begin + return Dnodes.Table (Decl).Storage; + end Get_Decl_Storage; + + procedure Set_Decl_Storage (Decl : O_Dnode; Storage : O_Storage) is + begin + Dnodes.Table (Decl).Storage := Storage; + end Set_Decl_Storage; + + function Get_Decl_Reg (Decl : O_Dnode) return O_Reg is + begin + return Dnodes.Table (Decl).Reg; + end Get_Decl_Reg; + + procedure Set_Decl_Reg (Decl : O_Dnode; Reg : O_Reg) is + begin + Dnodes.Table (Decl).Reg := Reg; + end Set_Decl_Reg; + + function Get_Decl_Depth (Decl : O_Dnode) return O_Depth is + begin + return Dnodes.Table (Decl).Depth; + end Get_Decl_Depth; + + function Get_Decl_Chain (Decl : O_Dnode) return O_Dnode is + begin + case Get_Decl_Kind (Decl) is + when OD_Block => + return Get_Block_Last (Decl) + 1; + when OD_Body => + return Get_Block_Last (Decl + 1) + 1; + when OD_Function + | OD_Procedure => + if Use_Subprg_Ext then + return Decl + 2; + else + return Decl + 1; + end if; + when others => + return Decl + 1; + end case; + end Get_Decl_Chain; + + function Get_Body_Stmt (Bod : O_Dnode) return O_Enode is + begin + return Dnodes.Table (Bod).Body_Stmt; + end Get_Body_Stmt; + + function Get_Body_Decl (Bod : O_Dnode) return O_Dnode is + begin + return Dnodes.Table (Bod).Body_Decl; + end Get_Body_Decl; + + function Get_Body_Parent (Bod : O_Dnode) return O_Dnode is + begin + return Dnodes.Table (Bod).Body_Parent; + end Get_Body_Parent; + + function Get_Body_Info (Bod : O_Dnode) return Int32 is + begin + return Dnodes.Table (Bod).Body_Info; + end Get_Body_Info; + + procedure Set_Body_Info (Bod : O_Dnode; Info : Int32) is + begin + Dnodes.Table (Bod).Body_Info := Info; + end Set_Body_Info; + + function Get_Decl_Ident (Decl : O_Dnode) return O_Ident is + begin + return Dnodes.Table (Decl).Id; + end Get_Decl_Ident; + + function Get_Decl_Last return O_Dnode is + begin + return Dnodes.Last; + end Get_Decl_Last; + + function Get_Block_Last (Blk : O_Dnode) return O_Dnode is + begin + return Dnodes.Table (Blk).Last; + end Get_Block_Last; + + function Get_Block_Max_Stack (Blk : O_Dnode) return Uns32 is + begin + return Dnodes.Table (Blk).Block_Max_Stack; + end Get_Block_Max_Stack; + + procedure Set_Block_Max_Stack (Blk : O_Dnode; Max : Uns32) is + begin + Dnodes.Table (Blk).Block_Max_Stack := Max; + end Set_Block_Max_Stack; + + function Get_Block_Info1 (Blk : O_Dnode) return Int32 is + begin + return Dnodes.Table (Blk).Block_Info1; + end Get_Block_Info1; + + procedure Set_Block_Info1 (Blk : O_Dnode; Info : Int32) is + begin + Dnodes.Table (Blk).Block_Info1 := Info; + end Set_Block_Info1; + + function Get_Block_Info2 (Blk : O_Dnode) return Int32 is + begin + return Dnodes.Table (Blk).Block_Info2; + end Get_Block_Info2; + + procedure Set_Block_Info2 (Blk : O_Dnode; Info : Int32) is + begin + Dnodes.Table (Blk).Block_Info2 := Info; + end Set_Block_Info2; + + function Get_Subprg_Interfaces (Decl : O_Dnode) return O_Dnode + is + Res : O_Dnode; + begin + if Use_Subprg_Ext then + Res := Decl + 2; + else + Res := Decl + 1; + end if; + + if Get_Decl_Kind (Res) = OD_Interface then + return Res; + else + return O_Dnode_Null; + end if; + end Get_Subprg_Interfaces; + + function Get_Interface_Chain (Decl : O_Dnode) return O_Dnode + is + Res : constant O_Dnode := Decl + 1; + begin + if Get_Decl_Kind (Res) = OD_Interface then + return Res; + else + return O_Dnode_Null; + end if; + end Get_Interface_Chain; + + function Get_Val_Decl (Decl : O_Dnode) return O_Dnode is + begin + return Dnodes.Table (Decl).Val_Decl; + end Get_Val_Decl; + + function Get_Val_Val (Decl : O_Dnode) return O_Cnode is + begin + return Dnodes.Table (Decl).Val_Val; + end Get_Val_Val; + + Cur_Depth : O_Depth := O_Toplevel; + + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode) is + begin + Dnodes.Append (Dnode_Common'(Kind => OD_Type, + Storage => O_Storage_Private, + Depth => Cur_Depth, + Reg => R_Nil, + Id => Ident, + Dtype => Atype, + Ref => 0, + Info2 => 0, + others => False)); + if Flags.Flag_Type_Name then + declare + L : O_Tnode; + begin + L := TDnodes.Last; + if Atype > L then + TDnodes.Set_Last (Atype); + TDnodes.Table (L + 1 .. Atype) := (others => O_Dnode_Null); + end if; + end; + TDnodes.Table (Atype) := Dnodes.Last; + end if; + end New_Type_Decl; + + function Get_Type_Decl (Atype : O_Tnode) return O_Dnode is + begin + if Atype <= TDnodes.Last then + return TDnodes.Table (Atype); + else + return O_Dnode_Null; + end if; + end Get_Type_Decl; + + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode) + is + begin + Dnodes.Append (Dnode_Common'(Kind => OD_Const, + Storage => Storage, + Depth => Cur_Depth, + Reg => R_Nil, + Id => Ident, + Dtype => Atype, + Ref => 0, + Info2 => 0, + others => False)); + Res := Dnodes.Last; + if not Flag_Debug_Hli then + Expand_Const_Decl (Res); + end if; + end New_Const_Decl; + + procedure New_Const_Value (Cst : O_Dnode; Val : O_Cnode) is + begin + if Dnodes.Table (Cst).Info2 /= 0 then + -- Value was already set. + raise Syntax_Error; + end if; + Dnodes.Table (Cst).Info2 := Int32 (Val); + if Flag_Debug_Hli then + Dnodes.Append (Dnode_Common'(Kind => OD_Const_Val, + Storage => O_Storage_Private, + Depth => Cur_Depth, + Reg => R_Nil, + Val_Decl => Cst, + Val_Val => Val, + others => False)); + else + Expand_Const_Value (Cst, Val); + end if; + end New_Const_Value; + + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode) + is + begin + if Storage = O_Storage_Local then + Dnodes.Append (Dnode_Common'(Kind => OD_Local, + Storage => Storage, + Depth => Cur_Depth, + Reg => R_Nil, + Id => Ident, + Dtype => Atype, + Ref => 0, + Info2 => 0, + others => False)); + Res := Dnodes.Last; + else + Dnodes.Append (Dnode_Common'(Kind => OD_Var, + Storage => Storage, + Depth => Cur_Depth, + Reg => R_Nil, + Id => Ident, + Dtype => Atype, + Ref => 0, + Info2 => 0, + others => False)); + Res := Dnodes.Last; + if not Flag_Debug_Hli then + Expand_Var_Decl (Res); + end if; + end if; + end New_Var_Decl; + + Static_Chain_Id : O_Ident := O_Ident_Nul; + + procedure Add_Static_Chain (Interfaces : in out O_Inter_List) + is + Res : O_Dnode; + begin + if Static_Chain_Id = O_Ident_Nul then + Static_Chain_Id := Ortho_Ident.Get_Identifier ("STATIC_CHAIN"); + end if; + + New_Interface_Decl (Interfaces, Res, Static_Chain_Id, O_Tnode_Ptr); + end Add_Static_Chain; + + procedure Start_Subprogram_Decl (Interfaces : out O_Inter_List) + is + Storage : O_Storage; + Decl : constant O_Dnode := Dnodes.Last; + begin + Storage := Get_Decl_Storage (Decl); + if Cur_Depth /= O_Toplevel then + case Storage is + when O_Storage_External + | O_Storage_Local => + null; + when O_Storage_Public => + raise Syntax_Error; + when O_Storage_Private => + Storage := O_Storage_Local; + Set_Decl_Storage (Decl, Storage); + end case; + end if; + if Use_Subprg_Ext then + Dnodes.Append (Dnode_Common'(Kind => OD_Subprg_Ext, + Storage => Storage, + Depth => Cur_Depth, + Reg => R_Nil, + Subprg_Inter => O_Dnode_Null, + others => False)); + end if; + + Start_Subprogram (Decl, Interfaces.Abi); + Interfaces.Decl := Decl; + if Storage = O_Storage_Local then + Add_Static_Chain (Interfaces); + end if; + end Start_Subprogram_Decl; + + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode) + is + begin + Dnodes.Append (Dnode_Common'(Kind => OD_Function, + Storage => Storage, + Depth => Cur_Depth, + Reg => R_Nil, + Id => Ident, + Dtype => Rtype, + Ref => 0, + Info2 => 0, + others => False)); + Start_Subprogram_Decl (Interfaces); + end Start_Function_Decl; + + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage) + is + begin + Dnodes.Append (Dnode_Common'(Kind => OD_Procedure, + Storage => Storage, + Depth => Cur_Depth, + Reg => R_Nil, + Id => Ident, + Dtype => O_Tnode_Null, + Ref => 0, + Info2 => 0, + others => False)); + Start_Subprogram_Decl (Interfaces); + end Start_Procedure_Decl; + + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode) + is + begin + Dnodes.Append (Dnode_Common'(Kind => OD_Interface, + Storage => O_Storage_Local, + Depth => Cur_Depth + 1, + Reg => R_Nil, + Id => Ident, + Dtype => Atype, + Ref => 0, + Info2 => 0, + others => False)); + Res := Dnodes.Last; + New_Interface (Res, Interfaces.Abi); + end New_Interface_Decl; + + procedure Set_Local_Offset (Decl : O_Dnode; Off : Int32) is + begin + Dnodes.Table (Decl).Ref := Off; + end Set_Local_Offset; + + function Get_Local_Offset (Decl : O_Dnode) return Int32 is + begin + return Dnodes.Table (Decl).Ref; + end Get_Local_Offset; + + function Get_Inter_Offset (Inter : O_Dnode) return Int32 is + begin + return Dnodes.Table (Inter).Ref; + end Get_Inter_Offset; + + procedure Set_Decl_Info (Decl : O_Dnode; Ref : Int32) is + begin + Dnodes.Table (Decl).Ref := Ref; + end Set_Decl_Info; + + function Get_Decl_Info (Decl : O_Dnode) return Int32 is + begin + return Dnodes.Table (Decl).Ref; + end Get_Decl_Info; + + procedure Set_Subprg_Stack (Decl : O_Dnode; Val : Int32) is + begin + Dnodes.Table (Decl).Info2 := Val; + end Set_Subprg_Stack; + + function Get_Subprg_Stack (Decl : O_Dnode) return Int32 is + begin + return Dnodes.Table (Decl).Info2; + end Get_Subprg_Stack; + + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode) is + begin + Res := Interfaces.Decl; + Finish_Subprogram (Res, Interfaces.Abi); + end Finish_Subprogram_Decl; + + Cur_Block : O_Dnode := O_Dnode_Null; + + function Start_Declare_Stmt return O_Dnode is + begin + Dnodes.Append (Dnode_Common'(Kind => OD_Block, + Storage => O_Storage_Local, + Depth => Cur_Depth, + Reg => R_Nil, + Last => O_Dnode_Null, + Block_Max_Stack => 0, + Block_Info1 => 0, + Block_Info2 => 0, + others => False)); + Cur_Block := Dnodes.Last; + return Cur_Block; + end Start_Declare_Stmt; + + procedure Finish_Declare_Stmt (Parent : O_Dnode) is + begin + Dnodes.Table (Cur_Block).Last := Dnodes.Last; + Cur_Block := Parent; + end Finish_Declare_Stmt; + + function Start_Subprogram_Body (Decl : O_Dnode; Stmt : O_Enode) + return O_Dnode + is + Res : O_Dnode; + begin + Dnodes.Append (Dnode_Common'(Kind => OD_Body, + Storage => O_Storage_Local, + Depth => Cur_Depth, + Reg => R_Nil, + Body_Parent => Context, + Body_Decl => Decl, + Body_Stmt => Stmt, + Body_Info => 0, + others => False)); + Res := Dnodes.Last; + Context := Res; + Cur_Depth := Cur_Depth + 1; + return Res; + end Start_Subprogram_Body; + + procedure Finish_Subprogram_Body is + begin + Cur_Depth := Cur_Depth - 1; + Context := Get_Body_Parent (Context); + end Finish_Subprogram_Body; + + +-- function Image (Decl : O_Dnode) return String is +-- begin +-- return O_Dnode'Image (Decl); +-- end Image; + + procedure Disp_Decl_Name (Decl : O_Dnode) + is + use Ada.Text_IO; + use Ortho_Ident; + Id : O_Ident; + begin + Id := Get_Decl_Ident (Decl); + if Is_Equal (Id, O_Ident_Nul) then + declare + Res : String := O_Dnode'Image (Decl); + begin + Res (1) := '?'; + Put (Res); + end; + else + Put (Get_String (Id)); + end if; + end Disp_Decl_Name; + + procedure Disp_Decl_Storage (Decl : O_Dnode) + is + use Ada.Text_IO; + begin + case Get_Decl_Storage (Decl) is + when O_Storage_Local => + Put ("local"); + when O_Storage_External => + Put ("external"); + when O_Storage_Public => + Put ("public"); + when O_Storage_Private => + Put ("private"); + end case; + end Disp_Decl_Storage; + + procedure Disp_Decl (Indent : Natural; Decl : O_Dnode) + is + use Ada.Text_IO; + use Ortho_Ident; + use Ortho_Code.Debug.Int32_IO; + begin + Set_Col (Count (Indent)); + Put (Int32 (Decl), 0); + Set_Col (Count (7 + Indent)); + case Get_Decl_Kind (Decl) is + when OD_Type => + Put ("type "); + Disp_Decl_Name (Decl); + Put (" is "); + Put (Int32 (Get_Decl_Type (Decl)), 0); + when OD_Function => + Disp_Decl_Storage (Decl); + Put (" function "); + Disp_Decl_Name (Decl); + Put (" return "); + Put (Int32 (Get_Decl_Type (Decl)), 0); + when OD_Procedure => + Disp_Decl_Storage (Decl); + Put (" procedure "); + Disp_Decl_Name (Decl); + when OD_Interface => + Put (" interface "); + Disp_Decl_Name (Decl); + Put (": "); + Put (Int32 (Get_Decl_Type (Decl)), 0); + Put (", offset="); + Put (Get_Inter_Offset (Decl), 0); + when OD_Const => + Disp_Decl_Storage (Decl); + Put (" const "); + Disp_Decl_Name (Decl); + Put (": "); + Put (Int32 (Get_Decl_Type (Decl)), 0); + when OD_Const_Val => + Put ("constant "); + Disp_Decl_Name (Get_Val_Decl (Decl)); + Put (": "); + Put (Int32 (Get_Val_Val (Decl)), 0); + when OD_Local => + Put ("local "); + Disp_Decl_Name (Decl); + Put (": "); + Put (Int32 (Get_Decl_Type (Decl)), 0); + Put (", offset="); + Put (Get_Inter_Offset (Decl), 0); + when OD_Var => + Disp_Decl_Storage (Decl); + Put (" var "); + Disp_Decl_Name (Decl); + Put (": "); + Put (Int32 (Get_Decl_Type (Decl)), 0); + when OD_Body => + Put ("body of "); + Put (Int32 (Get_Body_Decl (Decl)), 0); + Put (", stmt at "); + Put (Int32 (Get_Body_Stmt (Decl)), 0); + when OD_Block => + Put ("block until "); + Put (Int32 (Get_Block_Last (Decl)), 0); + when OD_Subprg_Ext => + Put ("Subprg_Ext"); +-- when others => +-- Put (OD_Kind'Image (Get_Decl_Kind (Decl))); + end case; + New_Line; + end Disp_Decl; + + procedure Disp_Decls (Indent : Natural; First, Last : O_Dnode) + is + N : O_Dnode; + begin + N := First; + while N <= Last loop + case Get_Decl_Kind (N) is + when OD_Body => + Disp_Decl (Indent, N); + Ortho_Code.Exprs.Disp_Subprg_Body + (Indent + 2, Get_Body_Stmt (N)); + N := N + 1; + when OD_Block => + -- Skip inner bindings. + N := Get_Block_Last (N) + 1; + when others => + Disp_Decl (Indent, N); + N := N + 1; + end case; + end loop; + end Disp_Decls; + + procedure Disp_Block (Indent : Natural; Start : O_Dnode) + is + Last : O_Dnode; + begin + if Get_Decl_Kind (Start) /= OD_Block then + Disp_Decl (Indent, Start); + raise Program_Error; + end if; + Last := Get_Block_Last (Start); + Disp_Decl (Indent, Start); + Disp_Decls (Indent, Start + 1, Last); + end Disp_Block; + + procedure Disp_All_Decls + is + begin + if False then + for I in Dnodes.First .. Dnodes.Last loop + Disp_Decl (1, I); + end loop; + end if; + + Disp_Decls (1, Dnodes.First, Dnodes.Last); + end Disp_All_Decls; + + procedure Debug_Decl (Decl : O_Dnode) is + begin + Disp_Decl (1, Decl); + end Debug_Decl; + + pragma Unreferenced (Debug_Decl); + + procedure Disp_Stats + is + use Ada.Text_IO; + begin + Put_Line ("Number of Dnodes: " & O_Dnode'Image (Dnodes.Last)); + Put_Line ("Number of TDnodes: " & O_Tnode'Image (TDnodes.Last)); + end Disp_Stats; + + procedure Mark (M : out Mark_Type) is + begin + M.Dnode := Dnodes.Last; + M.TDnode := TDnodes.Last; + end Mark; + + procedure Release (M : Mark_Type) is + begin + Dnodes.Set_Last (M.Dnode); + TDnodes.Set_Last (M.TDnode); + end Release; + + procedure Finish is + begin + Dnodes.Free; + TDnodes.Free; + end Finish; +end Ortho_Code.Decls; diff --git a/src/ortho/mcode/ortho_code-decls.ads b/src/ortho/mcode/ortho_code-decls.ads new file mode 100644 index 000000000..ad18892fe --- /dev/null +++ b/src/ortho/mcode/ortho_code-decls.ads @@ -0,0 +1,209 @@ +-- Mcode back-end for ortho - Declarations 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 Ortho_Code.Abi; + +package Ortho_Code.Decls is + -- Kind of a declaration. + type OD_Kind is (OD_Type, + OD_Const, OD_Const_Val, + + -- Global and local variables. + OD_Var, OD_Local, + + -- Subprograms. + OD_Function, OD_Procedure, + + -- Additional node for a subprogram. Internal use only. + OD_Subprg_Ext, + + OD_Interface, + OD_Body, + OD_Block); + + -- Return the kind of declaration DECL. + function Get_Decl_Kind (Decl : O_Dnode) return OD_Kind; + + -- Return the type of a declaration. + function Get_Decl_Type (Decl : O_Dnode) return O_Tnode; + + -- Return the identifier of a declaration. + function Get_Decl_Ident (Decl : O_Dnode) return O_Ident; + + -- Return the storage of a declaration. + function Get_Decl_Storage (Decl : O_Dnode) return O_Storage; + + -- Return the depth of a declaration. + function Get_Decl_Depth (Decl : O_Dnode) return O_Depth; + + -- Register for the declaration. + function Get_Decl_Reg (Decl : O_Dnode) return O_Reg; + procedure Set_Decl_Reg (Decl : O_Dnode; Reg : O_Reg); + + -- Return the next decl (in the same scope) after DECL. + -- This skips declarations in an inner block. + function Get_Decl_Chain (Decl : O_Dnode) return O_Dnode; + + -- Get the last declaration. + function Get_Decl_Last return O_Dnode; + + -- Return the subprogram declaration correspondig to body BOD. + function Get_Body_Decl (Bod : O_Dnode) return O_Dnode; + + -- Return the parent of a body. + function Get_Body_Parent (Bod : O_Dnode) return O_Dnode; + + -- Get the entry statement of body DECL. + function Get_Body_Stmt (Bod : O_Dnode) return O_Enode; + + -- Get/Set the info field of a body. + function Get_Body_Info (Bod : O_Dnode) return Int32; + procedure Set_Body_Info (Bod : O_Dnode; Info : Int32); + + -- Get the last declaration of block BLK. + function Get_Block_Last (Blk : O_Dnode) return O_Dnode; + + -- Get/Set the block max stack offset. + function Get_Block_Max_Stack (Blk : O_Dnode) return Uns32; + procedure Set_Block_Max_Stack (Blk : O_Dnode; Max : Uns32); + + -- Info on blocks. + function Get_Block_Info1 (Blk : O_Dnode) return Int32; + procedure Set_Block_Info1 (Blk : O_Dnode; Info : Int32); + function Get_Block_Info2 (Blk : O_Dnode) return Int32; + procedure Set_Block_Info2 (Blk : O_Dnode; Info : Int32); + + -- Get the declaration and the value associated with a constant value. + function Get_Val_Decl (Decl : O_Dnode) return O_Dnode; + function Get_Val_Val (Decl : O_Dnode) return O_Cnode; + + -- Declare a type. + -- This simply gives a name to a type. + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode); + + -- If Flag_Type_Name is set, a map from type to name is maintained. + function Get_Type_Decl (Atype : O_Tnode) return O_Dnode; + + -- Set/Get the offset (or register) of interface or local DECL. + -- To be used by ABI. + procedure Set_Local_Offset (Decl : O_Dnode; Off : Int32); + function Get_Local_Offset (Decl : O_Dnode) return Int32; + + -- Get/Set user info on subprogram, variable, constant declaration. + procedure Set_Decl_Info (Decl : O_Dnode; Ref : Int32); + function Get_Decl_Info (Decl : O_Dnode) return Int32; + + -- Get/Set the stack size of subprogram arguments. + procedure Set_Subprg_Stack (Decl : O_Dnode; Val : Int32); + function Get_Subprg_Stack (Decl : O_Dnode) return Int32; + + -- Get the first interface of a subprogram declaration. + function Get_Subprg_Interfaces (Decl : O_Dnode) return O_Dnode; + + -- Get the next interface. + -- End of interface chain when result is O_Dnode_Null. + function Get_Interface_Chain (Decl : O_Dnode) return O_Dnode; + + -- Declare a constant. + -- This simply gives a name to a constant value or aggregate. + -- A constant cannot be modified and its storage cannot be local. + -- ATYPE must be constrained. + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Set the value to CST. + procedure New_Const_Value (Cst : O_Dnode; Val : O_Cnode); + + -- Create a variable declaration. + -- A variable can be local only inside a function. + -- ATYPE must be constrained. + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + type O_Inter_List is limited private; + + -- Start a subprogram declaration. + -- Note: nested subprograms are allowed, ie o_storage_local subprograms can + -- be declared inside a subprograms. It is not allowed to declare + -- o_storage_external subprograms inside a subprograms. + -- Return type and interfaces cannot be a composite type. + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode); + -- For a subprogram without return value. + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage); + + -- Add an interface declaration to INTERFACES. + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode); + -- Finish the function declaration, get the node and a statement list. + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode); + + -- Start subprogram body of DECL. STMT is the corresponding statement. + -- Return the declaration for the body. + function Start_Subprogram_Body (Decl : O_Dnode; Stmt : O_Enode) + return O_Dnode; + procedure Finish_Subprogram_Body; + + -- Start a declarative region. + function Start_Declare_Stmt return O_Dnode; + procedure Finish_Declare_Stmt (Parent : O_Dnode); + + procedure Disp_All_Decls; + procedure Disp_Block (Indent : Natural; Start : O_Dnode); + procedure Disp_Decl_Name (Decl : O_Dnode); + procedure Disp_Decl (Indent : Natural; Decl : O_Dnode); + procedure Disp_Stats; + + type Mark_Type is limited private; + procedure Mark (M : out Mark_Type); + procedure Release (M : Mark_Type); + + procedure Finish; +private + type O_Inter_List is record + -- The declaration of the subprogram. + Decl : O_Dnode; + + -- Last declared parameter. + Last_Param : O_Dnode; + + -- Data for ABI. + Abi : Ortho_Code.Abi.O_Abi_Subprg; + end record; + + type Mark_Type is record + Dnode : O_Dnode; + TDnode : O_Tnode; + end record; + +end Ortho_Code.Decls; diff --git a/src/ortho/mcode/ortho_code-disps.adb b/src/ortho/mcode/ortho_code-disps.adb new file mode 100644 index 000000000..9e8ac1272 --- /dev/null +++ b/src/ortho/mcode/ortho_code-disps.adb @@ -0,0 +1,790 @@ +-- Mcode back-end for ortho - Internal tree dumper. +-- 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; use Ada.Text_IO; +with Ortho_Code.Debug; +with Ortho_Code.Consts; +with Ortho_Code.Decls; +with Ortho_Code.Types; +with Ortho_Code.Flags; +with Ortho_Ident; +with Interfaces; + +package body Ortho_Code.Disps is + procedure Disp_Subprg (Ident : Natural; S_Entry : O_Enode); + procedure Disp_Expr (Expr : O_Enode); + + procedure Disp_Indent (Indent : Natural) + is + begin + Put ((1 .. 2 * Indent => ' ')); + end Disp_Indent; + + procedure Disp_Ident (Id : O_Ident) + is + use Ortho_Ident; + begin + Put (Get_String (Id)); + end Disp_Ident; + + procedure Disp_Storage (Storage : O_Storage) is + begin + case Storage is + when O_Storage_External => + Put ("external"); + when O_Storage_Public => + Put ("public"); + when O_Storage_Private => + Put ("private"); + when O_Storage_Local => + Put ("local"); + end case; + end Disp_Storage; + + procedure Disp_Label (Label : O_Enode) + is + N : Int32; + begin + case Get_Expr_Kind (Label) is + when OE_Label => + Put ("label"); + N := Int32 (Label); + when OE_Loop => + Put ("loop"); + N := Int32 (Label); + when OE_BB => + Put ("BB"); + N := Get_BB_Number (Label); + when others => + raise Program_Error; + end case; + Put (Int32'Image (N)); + Put (":"); + end Disp_Label; + + procedure Disp_Call (Call : O_Enode) + is + Arg : O_Enode; + begin + Decls.Disp_Decl_Name (Get_Call_Subprg (Call)); + + Arg := Get_Arg_Link (Call); + if Arg /= O_Enode_Null then + Put (" ("); + loop + Disp_Expr (Get_Expr_Operand (Arg)); + Arg := Get_Arg_Link (Arg); + exit when Arg = O_Enode_Null; + Put (", "); + end loop; + Put (")"); + end if; + end Disp_Call; + + procedure Put_Trim (Str : String) is + begin + if Str (Str'First) = ' ' then + Put (Str (Str'First + 1 .. Str'Last)); + else + Put (Str); + end if; + end Put_Trim; + + procedure Disp_Typed_Lit (Lit : O_Cnode; Val : String) + is + use Ortho_Code.Consts; + begin + Disp_Type (Get_Const_Type (Lit)); + Put ("'["); + Put_Trim (Val); + Put (']'); + end Disp_Typed_Lit; + + procedure Disp_Lit (Lit : O_Cnode) + is + use Interfaces; + use Ortho_Code.Consts; + begin + case Get_Const_Kind (Lit) is + when OC_Unsigned => + Disp_Typed_Lit (Lit, Unsigned_64'Image (Get_Const_U64 (Lit))); + when OC_Signed => + Disp_Typed_Lit (Lit, Integer_64'Image (Get_Const_I64 (Lit))); + when OC_Subprg_Address => + Disp_Type (Get_Const_Type (Lit)); + Put ("'subprg_addr ("); + Decls.Disp_Decl_Name (Get_Const_Decl (Lit)); + Put (")"); + when OC_Address => + Disp_Type (Get_Const_Type (Lit)); + Put ("'address ("); + Decls.Disp_Decl_Name (Get_Const_Decl (Lit)); + Put (")"); + when OC_Sizeof => + Disp_Type (Get_Const_Type (Lit)); + Put ("'sizeof ("); + Disp_Type (Get_Sizeof_Type (Lit)); + Put (")"); + when OC_Null => + Disp_Type (Get_Const_Type (Lit)); + Put ("'[null]"); + when OC_Lit => + declare + L : O_Cnode; + begin + L := Types.Get_Type_Enum_Lit + (Get_Const_Type (Lit), Get_Lit_Value (Lit)); + Disp_Typed_Lit + (Lit, Ortho_Ident.Get_String (Get_Lit_Ident (L))); + end; + when OC_Array => + Put ('{'); + for I in 1 .. Get_Const_Aggr_Length (Lit) loop + if I /= 1 then + Put (", "); + end if; + Disp_Lit (Get_Const_Aggr_Element (Lit, I - 1)); + end loop; + Put ('}'); + when OC_Record => + declare + use Ortho_Code.Types; + F : O_Fnode; + begin + F := Get_Type_Record_Fields (Get_Const_Type (Lit)); + Put ('{'); + for I in 1 .. Get_Const_Aggr_Length (Lit) loop + if I /= 1 then + Put (", "); + end if; + Put ('.'); + Disp_Ident (Get_Field_Ident (F)); + Put (" = "); + Disp_Lit (Get_Const_Aggr_Element (Lit, I - 1)); + F := Get_Field_Chain (F); + end loop; + Put ('}'); + end; + when OC_Union => + Put ('{'); + Put ('.'); + Disp_Ident (Types.Get_Field_Ident (Get_Const_Union_Field (Lit))); + Put ('='); + Disp_Lit (Get_Const_Union_Value (Lit)); + Put ('}'); + when others => + Put ("*lit " & OC_Kind'Image (Get_Const_Kind (Lit)) & '*'); + end case; + end Disp_Lit; + + procedure Disp_Expr (Expr : O_Enode) + is + Kind : OE_Kind; + begin + Kind := Get_Expr_Kind (Expr); + case Kind is + when OE_Const => + case Get_Expr_Mode (Expr) is + when Mode_I8 + | Mode_I16 + | Mode_I32 => + Put_Trim (Int32'Image (To_Int32 (Get_Expr_Low (Expr)))); + when Mode_U8 + | Mode_U16 + | Mode_U32 => + Put_Trim (Uns32'Image (Get_Expr_Low (Expr))); + when others => + Put ("const:"); + Debug.Disp_Mode (Get_Expr_Mode (Expr)); + end case; + when OE_Lit => + Disp_Lit (Get_Expr_Lit (Expr)); + when OE_Case_Expr => + Put ("{case}"); + when OE_Kind_Dyadic + | OE_Kind_Cmp + | OE_Add + | OE_Mul + | OE_Shl => + Put ("("); + Disp_Expr (Get_Expr_Left (Expr)); + Put (' '); + case Kind is + when OE_Eq => + Put ('='); + when OE_Neq => + Put ("/="); + when OE_Lt => + Put ("<"); + when OE_Gt => + Put (">"); + when OE_Ge => + Put (">="); + when OE_Le => + Put ("<="); + when OE_Add => + Put ('+'); + when OE_Mul => + Put ('*'); + when OE_Add_Ov => + Put ("+#"); + when OE_Sub_Ov => + Put ("-#"); + when OE_Mul_Ov => + Put ("*#"); + when OE_Shl => + Put ("<<"); + when OE_And => + Put ("and"); + when OE_Or => + Put ("or"); + when others => + Put (OE_Kind'Image (Kind)); + end case; + Put (' '); + Disp_Expr (Get_Expr_Right (Expr)); + Put (")"); + when OE_Not => + Put ("not "); + Disp_Expr (Get_Expr_Operand (Expr)); + when OE_Neg_Ov => + Put ("neg "); + Disp_Expr (Get_Expr_Operand (Expr)); + when OE_Abs_Ov => + Put ("abs "); + Disp_Expr (Get_Expr_Operand (Expr)); + when OE_Indir => + declare + Op : O_Enode; + begin + Op := Get_Expr_Operand (Expr); + case Get_Expr_Kind (Op) is + when OE_Addrg + | OE_Addrl => + Decls.Disp_Decl_Name (Get_Addr_Object (Op)); + when others => + --Put ("*"); + Disp_Expr (Op); + end case; + end; + when OE_Addrl + | OE_Addrg => + -- Put ('@'); + Decls.Disp_Decl_Name (Get_Addr_Object (Expr)); + when OE_Call => + Disp_Call (Expr); + when OE_Alloca => + Put ("alloca ("); + Disp_Expr (Get_Expr_Operand (Expr)); + Put (")"); + when OE_Conv => + Disp_Type (Get_Conv_Type (Expr)); + Put ("'conv ("); + Disp_Expr (Get_Expr_Operand (Expr)); + Put (")"); + when OE_Conv_Ptr => + Disp_Type (Get_Conv_Type (Expr)); + Put ("'address ("); + Disp_Expr (Get_Expr_Operand (Expr)); + Put (")"); + when OE_Typed => + Disp_Type (Get_Conv_Type (Expr)); + Put ("'"); + -- Note: there is always parenthesis around comparison. + Disp_Expr (Get_Expr_Operand (Expr)); + when OE_Record_Ref => + Disp_Expr (Get_Expr_Operand (Expr)); + Put ("."); + Disp_Ident (Types.Get_Field_Ident (Get_Ref_Field (Expr))); + when OE_Access_Ref => + Disp_Expr (Get_Expr_Operand (Expr)); + Put (".all"); + when OE_Index_Ref => + Disp_Expr (Get_Expr_Operand (Expr)); + Put ('['); + Disp_Expr (Get_Ref_Index (Expr)); + Put (']'); + when OE_Slice_Ref => + Disp_Expr (Get_Expr_Operand (Expr)); + Put ('['); + Disp_Expr (Get_Ref_Index (Expr)); + Put ("...]"); + when OE_Get_Stack => + Put ("%sp"); + when OE_Get_Frame => + Put ("%fp"); + when others => + Put_Line (Standard_Error, "disps.disp_expr: unknown expr " + & OE_Kind'Image (Kind)); + end case; + end Disp_Expr; + + procedure Disp_Fields (Indent : Natural; Atype : O_Tnode) + is + use Types; + Nbr : Uns32; + F : O_Fnode; + begin + Nbr := Get_Type_Record_Nbr_Fields (Atype); + F := Get_Type_Record_Fields (Atype); + for I in 1 .. Nbr loop + Disp_Indent (Indent); + Disp_Ident (Get_Field_Ident (F)); + Put (": "); + Disp_Type (Get_Field_Type (F)); + Put (";"); + New_Line; + F := Get_Field_Chain (F); + end loop; + end Disp_Fields; + + procedure Disp_Type (Atype : O_Tnode; Force : Boolean := False) + is + use Types; + Kind : OT_Kind; + Decl : O_Dnode; + begin + if not Force then + Decl := Decls.Get_Type_Decl (Atype); + if Decl /= O_Dnode_Null then + Decls.Disp_Decl_Name (Decl); + return; + end if; + end if; + + Kind := Get_Type_Kind (Atype); + case Kind is + when OT_Signed => + Put ("signed ("); + Put_Trim (Uns32'Image (8 * Get_Type_Size (Atype))); + Put (")"); + when OT_Unsigned => + Put ("unsigned ("); + Put_Trim (Uns32'Image (8 * Get_Type_Size (Atype))); + Put (")"); + when OT_Float => + Put ("float"); + when OT_Access => + Put ("access"); + declare + Acc_Type : O_Tnode; + begin + Acc_Type := Get_Type_Access_Type (Atype); + if Acc_Type /= O_Tnode_Null then + Put (' '); + Disp_Type (Acc_Type); + end if; + end; + when OT_Ucarray => + Put ("array ["); + Disp_Type (Get_Type_Ucarray_Index (Atype)); + Put ("] of "); + Disp_Type (Get_Type_Ucarray_Element (Atype)); + when OT_Subarray => + Put ("subarray "); + Disp_Type (Get_Type_Subarray_Base (Atype)); + Put ("["); + Put_Trim (Uns32'Image (Get_Type_Subarray_Length (Atype))); + Put ("]"); + when OT_Record => + Put_Line ("record"); + Disp_Fields (1, Atype); + Put ("end record"); + when OT_Union => + Put_Line ("union"); + Disp_Fields (1, Atype); + Put ("end union"); + when OT_Boolean => + declare + Lit : O_Cnode; + begin + Put ("boolean {"); + Lit := Get_Type_Bool_False (Atype); + Disp_Ident (Consts.Get_Lit_Ident (Lit)); + Put (", "); + Lit := Get_Type_Bool_True (Atype); + Disp_Ident (Consts.Get_Lit_Ident (Lit)); + Put ("}"); + end; + when OT_Enum => + declare + use Consts; + Lit : O_Cnode; + begin + Put ("enum {"); + Lit := Get_Type_Enum_Lits (Atype); + for I in 1 .. Get_Type_Enum_Nbr_Lits (Atype) loop + if I /= 1 then + Put (", "); + end if; + Disp_Ident (Get_Lit_Ident (Lit)); + Put (" ="); + Put (Uns32'Image (I - 1)); + Lit := Get_Lit_Chain (Lit); + end loop; + Put ('}'); + end; + when OT_Complete => + Put ("-- complete: "); + Disp_Type (Get_Type_Complete_Type (Atype)); + end case; + end Disp_Type; + + procedure Disp_Decl_Storage (Decl : O_Dnode) is + begin + Disp_Storage (Decls.Get_Decl_Storage (Decl)); + Put (' '); + end Disp_Decl_Storage; + + procedure Disp_Subprg_Decl (Indent : Natural; Decl : O_Dnode) + is + use Decls; + Kind : OD_Kind; + Inter : O_Dnode; + begin + Disp_Decl_Storage (Decl); + Kind := Get_Decl_Kind (Decl); + case Kind is + when OD_Function => + Put ("function "); + when OD_Procedure => + Put ("procedure "); + when others => + raise Program_Error; + end case; + + Disp_Decl_Name (Decl); + Inter := Get_Subprg_Interfaces (Decl); + Put (" ("); + New_Line; + if Inter /= O_Dnode_Null then + loop + Disp_Indent (Indent + 1); + Disp_Decl_Name (Inter); + Put (": "); + Disp_Type (Get_Decl_Type (Inter)); + Inter := Get_Interface_Chain (Inter); + exit when Inter = O_Dnode_Null; + Put (";"); + New_Line; + end loop; + else + Disp_Indent (Indent + 1); + end if; + Put (")"); + if Kind = OD_Function then + New_Line; + Disp_Indent (Indent + 1); + Put ("return "); + Disp_Type (Get_Decl_Type (Decl)); + end if; + end Disp_Subprg_Decl; + + procedure Disp_Decl (Indent : Natural; + Decl : O_Dnode; + Nl : Boolean := False) + is + use Decls; + Kind : OD_Kind; + Dtype : O_Tnode; + begin + Kind := Get_Decl_Kind (Decl); + if Kind = OD_Interface then + return; + end if; + Disp_Indent (Indent); + case Kind is + when OD_Type => + Dtype := Get_Decl_Type (Decl); + Put ("type "); + Disp_Decl_Name (Decl); + Put (" is "); + Disp_Type (Dtype, True); + Put_Line (";"); + when OD_Local + | OD_Var => + Disp_Decl_Storage (Decl); + Put ("var "); + Disp_Decl_Name (Decl); + Put (" : "); + Dtype := Get_Decl_Type (Decl); + Disp_Type (Dtype); + if True then + Put (" {size=" + & Uns32'Image (Types.Get_Type_Size (Dtype)) & "}"); + end if; + Put_Line (";"); + when OD_Const => + Disp_Decl_Storage (Decl); + Put ("constant "); + Disp_Decl_Name (Decl); + Put (" : "); + Disp_Type (Get_Decl_Type (Decl)); + Put_Line (";"); + when OD_Const_Val => + Put ("constant "); + Disp_Decl_Name (Get_Val_Decl (Decl)); + Put (" := "); + Disp_Lit (Get_Val_Val (Decl)); + Put_Line (";"); + when OD_Function + | OD_Procedure => + Disp_Subprg_Decl (Indent, Decl); + Put_Line (";"); + when OD_Interface => + null; + when OD_Body => + -- Put ("body "); + Disp_Subprg_Decl (Indent, Get_Body_Decl (Decl)); + -- Disp_Decl_Name (Get_Body_Decl (Decl)); + New_Line; + Disp_Subprg (Indent, Get_Body_Stmt (Decl)); + when OD_Block | OD_Subprg_Ext => + null; + end case; + if Nl then + New_Line; + end if; + end Disp_Decl; + + procedure Disp_Stmt (Indent : in out Natural; Stmt : O_Enode) + is + use Decls; + Expr : O_Enode; + begin + case Get_Expr_Kind (Stmt) is + when OE_Beg => + Disp_Indent (Indent); + Put_Line ("declare"); + declare + Last : O_Dnode; + Decl : O_Dnode; + begin + Decl := Get_Block_Decls (Stmt); + Last := Get_Block_Last (Decl); + Decl := Decl + 1; + while Decl <= Last loop + case Get_Decl_Kind (Decl) is + when OD_Block => + Decl := Get_Block_Last (Decl) + 1; + when others => + Disp_Decl (Indent + 1, Decl, False); + Decl := Decl + 1; + end case; + end loop; + end; + Disp_Indent (Indent); + Put_Line ("begin"); + Indent := Indent + 1; + when OE_End => + Indent := Indent - 1; + Disp_Indent (Indent); + Put_Line ("end;"); + when OE_Line => + Disp_Indent (Indent); + Put_Line ("--#" & Int32'Image (Get_Expr_Line_Number (Stmt))); + when OE_BB => + Disp_Indent (Indent); + Put_Line ("# BB" & Int32'Image (Get_BB_Number (Stmt))); + when OE_Asgn => + Disp_Indent (Indent); + Disp_Expr (Get_Assign_Target (Stmt)); + Put (" := "); + Disp_Expr (Get_Expr_Operand (Stmt)); + Put_Line (";"); + when OE_Call => + Disp_Indent (Indent); + Disp_Call (Stmt); + Put_Line (";"); + when OE_Jump_F => + Disp_Indent (Indent); + Put ("jump "); + Disp_Label (Get_Jump_Label (Stmt)); + Put (" if not "); + Disp_Expr (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Jump_T => + Disp_Indent (Indent); + Put ("jump "); + Disp_Label (Get_Jump_Label (Stmt)); + Put (" if "); + Disp_Expr (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Jump => + Disp_Indent (Indent); + Put ("jump "); + Disp_Label (Get_Jump_Label (Stmt)); + New_Line; + when OE_Label => + Disp_Indent (Indent); + Disp_Label (Stmt); + New_Line; + when OE_Ret => + Disp_Indent (Indent); + Put ("return"); + Expr := Get_Expr_Operand (Stmt); + if Expr /= O_Enode_Null then + Put (" "); + Disp_Expr (Expr); + end if; + Put_Line (";"); + when OE_Set_Stack => + Disp_Indent (Indent); + Put ("%sp := "); + Disp_Expr (Get_Expr_Operand (Stmt)); + Put_Line (";"); + when OE_Leave => + Disp_Indent (Indent); + Put_Line ("# leave"); + when OE_If => + Disp_Indent (Indent); + Put ("if "); + Disp_Expr (Get_Expr_Operand (Stmt)); + Put (" then"); + New_Line; + Indent := Indent + 1; + when OE_Else => + Disp_Indent (Indent - 1); + Put ("else"); + New_Line; + when OE_Endif => + Indent := Indent - 1; + Disp_Indent (Indent); + Put_Line ("end if;"); + when OE_Loop => + Disp_Indent (Indent); + Disp_Label (Stmt); + New_Line; + Indent := Indent + 1; + when OE_Exit => + Disp_Indent (Indent); + Put ("exit "); + Disp_Label (Get_Jump_Label (Stmt)); + Put (";"); + New_Line; + when OE_Next => + Disp_Indent (Indent); + Put ("next "); + Disp_Label (Get_Jump_Label (Stmt)); + Put (";"); + New_Line; + when OE_Eloop => + Indent := Indent - 1; + Disp_Indent (Indent); + Put_Line ("end loop;"); + when OE_Case => + Disp_Indent (Indent); + Put ("case "); + Disp_Expr (Get_Expr_Operand (Stmt)); + Put (" is"); + New_Line; + if Debug.Flag_Debug_Hli then + Indent := Indent + 2; + end if; + when OE_Case_Branch => + Disp_Indent (Indent - 1); + Put ("when "); + declare + C : O_Enode; + L, H : O_Enode; + begin + C := Get_Case_Branch_Choice (Stmt); + loop + L := Get_Expr_Left (C); + H := Get_Expr_Right (C); + if L = O_Enode_Null then + Put ("others"); + else + Disp_Expr (L); + if H /= O_Enode_Null then + Put (" ... "); + Disp_Expr (H); + end if; + end if; + C := Get_Case_Choice_Link (C); + exit when C = O_Enode_Null; + New_Line; + Disp_Indent (Indent - 1); + Put (" | "); + end loop; + Put (" =>"); + New_Line; + end; + when OE_Case_End => + Indent := Indent - 2; + Disp_Indent (Indent); + Put ("end case;"); + New_Line; + when others => + Put_Line (Standard_Error, "debug.disp_stmt: unknown statement " & + OE_Kind'Image (Get_Expr_Kind (Stmt))); + end case; + end Disp_Stmt; + + procedure Disp_Subprg (Ident : Natural; S_Entry : O_Enode) + is + Stmt : O_Enode; + N_Ident : Natural := Ident; + begin + Stmt := S_Entry; + loop + Stmt := Get_Stmt_Link (Stmt); + Disp_Stmt (N_Ident, Stmt); + exit when Get_Expr_Kind (Stmt) = OE_Leave; + end loop; + end Disp_Subprg; + + Last_Decl : O_Dnode := O_Dnode_First; + + procedure Disp_Decls_Until (Last : O_Dnode; Nl : Boolean := False) is + begin + while Last_Decl <= Last loop + Disp_Decl (0, Last_Decl, Nl); + Last_Decl := Last_Decl + 1; + end loop; + end Disp_Decls_Until; + + procedure Disp_Subprg (Subprg : Subprogram_Data_Acc) + is + use Decls; + begin + Disp_Decls_Until (Subprg.D_Body, True); + if Get_Decl_Kind (Last_Decl) /= OD_Block then + raise Program_Error; + end if; + if Debug.Flag_Debug_Keep then + -- If nodes are kept, the next declaration to be displayed (at top + -- level) is the one that follow the subprogram block. + Last_Decl := Get_Block_Last (Last_Decl) + 1; + else + -- If nodes are not kept, this subprogram block will be freed, and + -- the next declaration is the block itself. + Last_Decl := Subprg.D_Body; + end if; + end Disp_Subprg; + + procedure Init is + begin + Flags.Flag_Type_Name := True; + end Init; + + procedure Finish is + begin + Disp_Decls_Until (Decls.Get_Decl_Last, True); + end Finish; + +end Ortho_Code.Disps; diff --git a/src/ortho/mcode/ortho_code-disps.ads b/src/ortho/mcode/ortho_code-disps.ads new file mode 100644 index 000000000..5ae4d8697 --- /dev/null +++ b/src/ortho/mcode/ortho_code-disps.ads @@ -0,0 +1,25 @@ +-- Mcode back-end for ortho - Internal tree dumper. +-- 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 Ortho_Code.Exprs; use Ortho_Code.Exprs; + +package Ortho_Code.Disps is + procedure Disp_Subprg (Subprg : Subprogram_Data_Acc); + procedure Disp_Type (Atype : O_Tnode; Force : Boolean := False); + procedure Init; + procedure Finish; +end Ortho_Code.Disps; diff --git a/src/ortho/mcode/ortho_code-dwarf.adb b/src/ortho/mcode/ortho_code-dwarf.adb new file mode 100644 index 000000000..ad67d1ff6 --- /dev/null +++ b/src/ortho/mcode/ortho_code-dwarf.adb @@ -0,0 +1,1351 @@ +-- Mcode back-end for ortho - Dwarf generator. +-- 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 GNAT.Directory_Operations; +with GNAT.Table; +with Interfaces; use Interfaces; +with Binary_File; use Binary_File; +with Dwarf; use Dwarf; +with Ada.Text_IO; +with Ortho_Code.Decls; +with Ortho_Code.Types; +with Ortho_Code.Consts; +with Ortho_Code.Flags; +with Ortho_Ident; +with Ortho_Code.Binary; + +package body Ortho_Code.Dwarf is + -- Dwarf debugging format. + -- Debugging. + Line1_Sect : Section_Acc := null; + Line_Last : Int32 := 0; + Line_Pc : Pc_Type := 0; + + -- Constant. + Min_Insn_Len : constant := 1; + Line_Base : constant := 1; + Line_Range : constant := 4; + Line_Opcode_Base : constant := 13; + Line_Max_Addr : constant := (255 - Line_Opcode_Base) / Line_Range; + -- + Line_Base; + + Cur_File : Natural := 0; + Last_File : Natural := 0; + + Orig_Sym : Symbol; + End_Sym : Symbol; + Abbrev_Sym : Symbol; + Info_Sym : Symbol; + Line_Sym : Symbol; + + Line_Sect : Section_Acc; + Abbrev_Sect : Section_Acc; + Info_Sect : Section_Acc; + Aranges_Sect : Section_Acc; + + Abbrev_Last : Unsigned_32; + +-- procedure Gen_String (Str : String) +-- is +-- begin +-- for I in Str'Range loop +-- Gen_B8 (Character'Pos (Str (I))); +-- end loop; +-- end Gen_String; + + procedure Gen_String_Nul (Str : String) + is + begin + Prealloc (Str'Length + 1); + for I in Str'Range loop + Gen_B8 (Character'Pos (Str (I))); + end loop; + Gen_B8 (0); + end Gen_String_Nul; + + procedure Gen_Sleb128 (V : Int32) + is + V1 : Uns32 := To_Uns32 (V); + V2 : Uns32; + B : Byte; + function Shift_Right_Arithmetic (Value : Uns32; Amount : Natural) + return Uns32; + pragma Import (Intrinsic, Shift_Right_Arithmetic); + begin + loop + B := Byte (V1 and 16#7F#); + V2 := Shift_Right_Arithmetic (V1, 7); + if (V2 = 0 and (B and 16#40#) = 0) + or (V2 = -1 and (B and 16#40#) /= 0) + then + Gen_B8 (B); + exit; + else + Gen_B8 (B or 16#80#); + V1 := V2; + end if; + end loop; + end Gen_Sleb128; + + procedure Gen_Uleb128 (V : Unsigned_32) + is + V1 : Unsigned_32 := V; + B : Byte; + begin + loop + B := Byte (V1 and 16#7f#); + V1 := Shift_Right (V1, 7); + if V1 /= 0 then + Gen_B8 (B or 16#80#); + else + Gen_B8 (B); + exit; + end if; + end loop; + end Gen_Uleb128; + +-- procedure New_Debug_Line_Decl (Line : Int32) +-- is +-- begin +-- Line_Last := Line; +-- end New_Debug_Line_Decl; + + procedure Set_Line_Stmt (Line : Int32) + is + Pc : Pc_Type; + D_Pc : Pc_Type; + D_Ln : Int32; + begin + if Line = Line_Last then + return; + end if; + Pc := Get_Current_Pc; + + D_Pc := (Pc - Line_Pc) / Min_Insn_Len; + D_Ln := Line - Line_Last; + + -- Always emit line information, since missing info can distrub the + -- user. + -- As an optimization, we could try to emit the highest line for the + -- same PC, since GDB seems to handle this way. + if False and D_Pc = 0 then + return; + end if; + + Set_Current_Section (Line1_Sect); + Prealloc (32); + + if Cur_File /= Last_File then + Gen_B8 (Byte (DW_LNS_Set_File)); + Gen_Uleb128 (Unsigned_32 (Cur_File)); + Last_File := Cur_File; + elsif Cur_File = 0 then + return; + end if; + + if D_Ln < Line_Base or D_Ln >= (Line_Base + Line_Range) then + -- Emit an advance line. + Gen_B8 (Byte (DW_LNS_Advance_Line)); + Gen_Sleb128 (Int32 (D_Ln - Line_Base)); + D_Ln := Line_Base; + end if; + if D_Pc >= Line_Max_Addr then + -- Emit an advance addr. + Gen_B8 (Byte (DW_LNS_Advance_Pc)); + Gen_Uleb128 (Unsigned_32 (D_Pc)); + D_Pc := 0; + end if; + Gen_B8 (Line_Opcode_Base + + Byte (D_Pc) * Line_Range + + Byte (D_Ln - Line_Base)); + + --Set_Current_Section (Text_Sect); + Line_Pc := Pc; + Line_Last := Line; + end Set_Line_Stmt; + + + type String_Acc is access constant String; + + type Dir_Chain; + type Dir_Chain_Acc is access Dir_Chain; + type Dir_Chain is record + Name : String_Acc; + Next : Dir_Chain_Acc; + end record; + + type File_Chain; + type File_Chain_Acc is access File_Chain; + type File_Chain is record + Name : String_Acc; + Dir : Natural; + Next : File_Chain_Acc; + end record; + + Dirs : Dir_Chain_Acc := null; + Files : File_Chain_Acc := null; + + procedure Set_Filename (Dir : String; File : String) + is + D : Natural; + F : Natural; + D_C : Dir_Chain_Acc; + F_C : File_Chain_Acc; + begin + -- Find directory. + if Dir = "" then + -- Current directory. + D := 0; + elsif Dirs = null then + -- First directory. + Dirs := new Dir_Chain'(Name => new String'(Dir), + Next => null); + D := 1; + else + -- Find a directory. + D_C := Dirs; + D := 1; + loop + exit when D_C.Name.all = Dir; + D := D + 1; + if D_C.Next = null then + D_C.Next := new Dir_Chain'(Name => new String'(Dir), + Next => null); + exit; + else + D_C := D_C.Next; + end if; + end loop; + end if; + + -- Find file. + F := 1; + if Files = null then + -- first file. + Files := new File_Chain'(Name => new String'(File), + Dir => D, + Next => null); + else + F_C := Files; + loop + exit when F_C.Name.all = File and F_C.Dir = D; + F := F + 1; + if F_C.Next = null then + F_C.Next := new File_Chain'(Name => new String'(File), + Dir => D, + Next => null); + exit; + else + F_C := F_C.Next; + end if; + end loop; + end if; + Cur_File := F; + end Set_Filename; + + procedure Gen_Abbrev_Header (Tag : Unsigned_32; Child : Byte) is + begin + Gen_Uleb128 (Tag); + Gen_B8 (Child); + end Gen_Abbrev_Header; + + procedure Gen_Abbrev_Tuple (Attr : Unsigned_32; Form : Unsigned_32) is + begin + Gen_Uleb128 (Attr); + Gen_Uleb128 (Form); + end Gen_Abbrev_Tuple; + + procedure Init + is + begin + -- Generate type names. + Flags.Flag_Type_Name := True; + + + Orig_Sym := Create_Local_Symbol; + Set_Symbol_Pc (Orig_Sym, False); + End_Sym := Create_Local_Symbol; + + Create_Section (Line1_Sect, ".debug_line-1", Section_Debug); + Set_Current_Section (Line1_Sect); + + -- Write Address. + Gen_B8 (0); -- extended opcode + Gen_B8 (5); -- length: 1 + 4 + Gen_B8 (Byte (DW_LNE_Set_Address)); + Gen_Ua_32 (Orig_Sym, 0); + + Line_Last := 1; + + Create_Section (Line_Sect, ".debug_line", Section_Debug); + Set_Section_Info (Line_Sect, null, 0, 0); + Set_Current_Section (Line_Sect); + Line_Sym := Create_Local_Symbol; + Set_Symbol_Pc (Line_Sym, False); + + -- Abbrevs. + Create_Section (Abbrev_Sect, ".debug_abbrev", Section_Debug); + Set_Section_Info (Abbrev_Sect, null, 0, 0); + Set_Current_Section (Abbrev_Sect); + + Abbrev_Sym := Create_Local_Symbol; + Set_Symbol_Pc (Abbrev_Sym, False); + + Gen_Uleb128 (1); + Gen_Abbrev_Header (DW_TAG_Compile_Unit, DW_CHILDREN_Yes); + + Gen_Abbrev_Tuple (DW_AT_Stmt_List, DW_FORM_Data4); + Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (DW_AT_Producer, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Comp_Dir, DW_FORM_String); + Gen_Abbrev_Tuple (0, 0); + + Abbrev_Last := 1; + + -- Info. + Create_Section (Info_Sect, ".debug_info", Section_Debug); + Set_Section_Info (Info_Sect, null, 0, 0); + Set_Current_Section (Info_Sect); + Info_Sym := Create_Local_Symbol; + Set_Symbol_Pc (Info_Sym, False); + + Gen_32 (7); -- Length: to be patched. + Gen_16 (2); -- version + Gen_Ua_32 (Abbrev_Sym, 0); -- Abbrev offset + Gen_B8 (4); -- Ptr size. + + -- Compile_unit. + Gen_Uleb128 (1); + Gen_Ua_32 (Line_Sym, 0); + Gen_Ua_32 (Orig_Sym, 0); + Gen_Ua_32 (End_Sym, 0); + Gen_String_Nul ("T.Gingold ortho_mcode (2004)"); + Gen_String_Nul (GNAT.Directory_Operations.Get_Current_Dir); + end Init; + + procedure Emit_Decl (Decl : O_Dnode); + + -- Next node to be emitted. + Last_Decl : O_Dnode := O_Dnode_First; + + procedure Emit_Decls_Until (Last : O_Dnode) + is + use Ortho_Code.Decls; + begin + while Last_Decl < Last loop + Emit_Decl (Last_Decl); + Last_Decl := Get_Decl_Chain (Last_Decl); + end loop; + end Emit_Decls_Until; + + procedure Finish + is + Length : Pc_Type; + Last : O_Dnode; + begin + Set_Symbol_Pc (End_Sym, False); + Length := Get_Current_Pc; + + Last := Decls.Get_Decl_Last; + Emit_Decls_Until (Last); + if Last_Decl <= Last then + Emit_Decl (Last); + end if; + + -- Finish abbrevs. + Set_Current_Section (Abbrev_Sect); + Gen_Uleb128 (0); + + -- Emit header. + Set_Current_Section (Line_Sect); + + -- Unit_Length (to be patched). + Gen_32 (0); + -- version + Gen_16 (2); + -- header_length (to be patched). + Gen_32 (5 + 12 + 1); + -- minimum_instruction_length. + Gen_B8 (Min_Insn_Len); + -- default_is_stmt + Gen_B8 (1); + -- line base + Gen_B8 (Line_Base); + -- line range + Gen_B8 (Line_Range); + -- opcode base + Gen_B8 (Line_Opcode_Base); + -- standard_opcode_length. + Gen_B8 (0); -- copy + Gen_B8 (1); -- advance pc + Gen_B8 (1); -- advance line + Gen_B8 (1); -- set file + Gen_B8 (1); -- set column + Gen_B8 (0); -- negate stmt + Gen_B8 (0); -- set basic block + Gen_B8 (0); -- const add pc + Gen_B8 (1); -- fixed advance pc + Gen_B8 (0); -- set prologue end + Gen_B8 (0); -- set epilogue begin + Gen_B8 (1); -- set isa + --if Line_Opcode_Base /= 13 then + -- raise Program_Error; + --end if; + + -- include directories + declare + D : Dir_Chain_Acc; + begin + D := Dirs; + while D /= null loop + Gen_String_Nul (D.Name.all); + D := D.Next; + end loop; + Gen_B8 (0); -- last entry. + end; + + -- file_names. + declare + F : File_Chain_Acc; + begin + F := Files; + while F /= null loop + Gen_String_Nul (F.Name.all); + Gen_Uleb128 (Unsigned_32 (F.Dir)); + Gen_B8 (0); -- time + Gen_B8 (0); -- length + F := F.Next; + end loop; + Gen_B8 (0); -- last entry. + end; + + -- Set prolog length + Patch_32 (6, Unsigned_32 (Get_Current_Pc - 6)); + + Merge_Section (Line_Sect, Line1_Sect); + + -- Emit end of sequence. + Gen_B8 (0); -- extended opcode + Gen_B8 (1); -- length: 1 + Gen_B8 (Byte (DW_LNE_End_Sequence)); + + -- Set total length. + Patch_32 (0, Unsigned_32 (Get_Current_Pc - 4)); + + -- Info. + Set_Current_Section (Info_Sect); + -- Finish child. + Gen_Uleb128 (0); + -- Set total length. + Patch_32 (0, Unsigned_32 (Get_Current_Pc - 4)); + + -- Aranges + Create_Section (Aranges_Sect, ".debug_aranges", Section_Debug); + Set_Section_Info (Aranges_Sect, null, 0, 0); + Set_Current_Section (Aranges_Sect); + + Gen_32 (28); -- Length. + Gen_16 (2); -- version + Gen_Ua_32 (Info_Sym, 0); -- info offset + Gen_B8 (4); -- Ptr size. + Gen_B8 (0); -- seg desc size. + Gen_32 (0); -- pad + Gen_Ua_32 (Orig_Sym, 0); -- text offset + Gen_32 (Unsigned_32 (Length)); + Gen_32 (0); -- End + Gen_32 (0); + end Finish; + + procedure Generate_Abbrev (Abbrev : out Unsigned_32) is + begin + Abbrev_Last := Abbrev_Last + 1; + Abbrev := Abbrev_Last; + + Set_Current_Section (Abbrev_Sect); + -- FIXME: should be enough ? + Prealloc (128); + Gen_Uleb128 (Abbrev); + end Generate_Abbrev; + + procedure Gen_Info_Header (Abbrev : Unsigned_32) is + begin + Set_Current_Section (Info_Sect); + Gen_Uleb128 (Abbrev); + end Gen_Info_Header; + + function Gen_Info_Sibling return Pc_Type + is + Pc : Pc_Type; + begin + Pc := Get_Current_Pc; + Gen_32 (0); + return Pc; + end Gen_Info_Sibling; + + procedure Patch_Info_Sibling (Pc : Pc_Type) is + begin + Patch_32 (Pc, Unsigned_32 (Get_Current_Pc)); + end Patch_Info_Sibling; + + Abbrev_Base_Type : Unsigned_32 := 0; + Abbrev_Base_Type_Name : Unsigned_32 := 0; + Abbrev_Pointer : Unsigned_32 := 0; + Abbrev_Pointer_Name : Unsigned_32 := 0; + Abbrev_Uncomplete_Pointer : Unsigned_32 := 0; + Abbrev_Uncomplete_Pointer_Name : Unsigned_32 := 0; + Abbrev_Ucarray : Unsigned_32 := 0; + Abbrev_Ucarray_Name : Unsigned_32 := 0; + Abbrev_Uc_Subrange : Unsigned_32 := 0; + Abbrev_Subarray : Unsigned_32 := 0; + Abbrev_Subarray_Name : Unsigned_32 := 0; + Abbrev_Subrange : Unsigned_32 := 0; + Abbrev_Struct : Unsigned_32 := 0; + Abbrev_Struct_Name : Unsigned_32 := 0; + Abbrev_Union : Unsigned_32 := 0; + Abbrev_Union_Name : Unsigned_32 := 0; + Abbrev_Member : Unsigned_32 := 0; + Abbrev_Enum : Unsigned_32 := 0; + Abbrev_Enum_Name : Unsigned_32 := 0; + Abbrev_Enumerator : Unsigned_32 := 0; + + package TOnodes is new GNAT.Table + (Table_Component_Type => Pc_Type, + Table_Index_Type => O_Tnode, + Table_Low_Bound => O_Tnode_First, + Table_Initial => 16, + Table_Increment => 100); + + procedure Emit_Type_Ref (Atype : O_Tnode) + is + Off : Pc_Type; + begin + Off := TOnodes.Table (Atype); + if Off = Null_Pc then + raise Program_Error; + end if; + Gen_32 (Unsigned_32 (Off)); + end Emit_Type_Ref; + + procedure Emit_Ident (Id : O_Ident) + is + use Ortho_Ident; + L : Natural; + begin + L := Get_String_Length (Id); + Prealloc (Pc_Type (L) + 128); + Gen_String_Nul (Get_String (Id)); + end Emit_Ident; + + procedure Add_Type_Ref (Atype : O_Tnode; Pc : Pc_Type) + is + Prev : O_Tnode; + begin + if Atype > TOnodes.Last then + -- Expand. + Prev := TOnodes.Last; + TOnodes.Set_Last (Atype); + TOnodes.Table (Prev + 1 .. Atype - 1) := (others => Null_Pc); + end if; + TOnodes.Table (Atype) := Pc; + end Add_Type_Ref; + + procedure Emit_Decl_Ident (Decl : O_Dnode) + is + use Ortho_Code.Decls; + begin + Emit_Ident (Get_Decl_Ident (Decl)); + end Emit_Decl_Ident; + + procedure Emit_Decl_Ident_If_Set (Decl : O_Dnode) + is + use Ortho_Code.Decls; + begin + if Decl /= O_Dnode_Null then + Emit_Ident (Get_Decl_Ident (Decl)); + end if; + end Emit_Decl_Ident_If_Set; + + procedure Emit_Type (Atype : O_Tnode); + + procedure Emit_Base_Type (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + procedure Finish_Gen_Abbrev is + begin + Gen_Abbrev_Tuple (DW_AT_Encoding, DW_FORM_Data1); + Gen_Abbrev_Tuple (DW_AT_Byte_Size, DW_FORM_Data1); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev; + begin + if Decl = O_Dnode_Null then + if Abbrev_Base_Type = 0 then + Generate_Abbrev (Abbrev_Base_Type); + Gen_Abbrev_Header (DW_TAG_Base_Type, DW_CHILDREN_No); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Base_Type); + else + if Abbrev_Base_Type_Name = 0 then + Generate_Abbrev (Abbrev_Base_Type_Name); + Gen_Abbrev_Header (DW_TAG_Base_Type, DW_CHILDREN_No); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Base_Type_Name); + Emit_Decl_Ident (Decl); + end if; + + case Get_Type_Kind (Atype) is + when OT_Signed => + Gen_B8 (DW_ATE_Signed); + when OT_Unsigned => + Gen_B8 (DW_ATE_Unsigned); + when OT_Float => + Gen_B8 (DW_ATE_Float); + when others => + raise Program_Error; + end case; + Gen_B8 (Byte (Get_Type_Size (Atype))); + end Emit_Base_Type; + + procedure Emit_Access_Type (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + procedure Finish_Gen_Abbrev is + begin + Gen_Abbrev_Tuple (DW_AT_Byte_Size, DW_FORM_Data1); + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev; + + procedure Finish_Gen_Abbrev_Uncomplete is + begin + Gen_Abbrev_Tuple (DW_AT_Byte_Size, DW_FORM_Data1); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev_Uncomplete; + + Dtype : O_Tnode; + D_Pc : Pc_Type; + begin + Dtype := Get_Type_Access_Type (Atype); + + if Dtype = O_Tnode_Null then + if Decl = O_Dnode_Null then + if Abbrev_Uncomplete_Pointer = 0 then + Generate_Abbrev (Abbrev_Uncomplete_Pointer); + Gen_Abbrev_Header (DW_TAG_Pointer_Type, DW_CHILDREN_No); + Finish_Gen_Abbrev_Uncomplete; + end if; + Gen_Info_Header (Abbrev_Uncomplete_Pointer); + else + if Abbrev_Uncomplete_Pointer_Name = 0 then + Generate_Abbrev (Abbrev_Uncomplete_Pointer_Name); + Gen_Abbrev_Header (DW_TAG_Pointer_Type, DW_CHILDREN_No); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev_Uncomplete; + end if; + Gen_Info_Header (Abbrev_Uncomplete_Pointer_Name); + Emit_Decl_Ident (Decl); + end if; + Gen_B8 (Byte (Get_Type_Size (Atype))); + else + if Decl = O_Dnode_Null then + if Abbrev_Pointer = 0 then + Generate_Abbrev (Abbrev_Pointer); + Gen_Abbrev_Header (DW_TAG_Pointer_Type, DW_CHILDREN_No); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Pointer); + else + if Abbrev_Pointer_Name = 0 then + Generate_Abbrev (Abbrev_Pointer_Name); + Gen_Abbrev_Header (DW_TAG_Pointer_Type, DW_CHILDREN_No); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Pointer_Name); + Emit_Decl_Ident (Decl); + end if; + Gen_B8 (Byte (Get_Type_Size (Atype))); + -- Break possible loops: generate the access entry... + D_Pc := Get_Current_Pc; + Gen_32 (0); + -- ... generate the designated type ... + Emit_Type (Dtype); + -- ... and write its reference. + Patch_32 (D_Pc, Unsigned_32 (TOnodes.Table (Dtype))); + end if; + end Emit_Access_Type; + + procedure Emit_Ucarray_Type (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + + procedure Finish_Gen_Abbrev is + begin + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev; + begin + if Decl = O_Dnode_Null then + if Abbrev_Ucarray = 0 then + Generate_Abbrev (Abbrev_Ucarray); + Gen_Abbrev_Header (DW_TAG_Array_Type, DW_CHILDREN_Yes); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Ucarray); + else + if Abbrev_Ucarray_Name = 0 then + Generate_Abbrev (Abbrev_Ucarray_Name); + Gen_Abbrev_Header (DW_TAG_Array_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Ucarray_Name); + Emit_Decl_Ident (Decl); + end if; + Emit_Type_Ref (Get_Type_Ucarray_Element (Atype)); + + if Abbrev_Uc_Subrange = 0 then + Generate_Abbrev (Abbrev_Uc_Subrange); + Gen_Abbrev_Header (DW_TAG_Subrange_Type, DW_CHILDREN_No); + + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (0, 0); + end if; + + Gen_Info_Header (Abbrev_Uc_Subrange); + Emit_Type_Ref (Get_Type_Ucarray_Index (Atype)); + + Gen_Uleb128 (0); + end Emit_Ucarray_Type; + + procedure Emit_Subarray_Type (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + procedure Finish_Gen_Abbrev is + begin + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Byte_Size, DW_FORM_Udata); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev; + + Base : O_Tnode; + begin + if Decl = O_Dnode_Null then + if Abbrev_Subarray = 0 then + Generate_Abbrev (Abbrev_Subarray); + Gen_Abbrev_Header (DW_TAG_Array_Type, DW_CHILDREN_Yes); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Subarray); + else + if Abbrev_Subarray_Name = 0 then + Generate_Abbrev (Abbrev_Subarray_Name); + Gen_Abbrev_Header (DW_TAG_Array_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Subarray_Name); + Emit_Decl_Ident (Decl); + end if; + + Base := Get_Type_Subarray_Base (Atype); + + Emit_Type_Ref (Get_Type_Ucarray_Element (Base)); + Gen_Uleb128 (Unsigned_32 (Get_Type_Size (Atype))); + + if Abbrev_Subrange = 0 then + Generate_Abbrev (Abbrev_Subrange); + Gen_Abbrev_Header (DW_TAG_Subrange_Type, DW_CHILDREN_No); + + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Lower_Bound, DW_FORM_Data1); + Gen_Abbrev_Tuple (DW_AT_Count, DW_FORM_Udata); + Gen_Abbrev_Tuple (0, 0); + end if; + + Gen_Info_Header (Abbrev_Subrange); + Emit_Type_Ref (Get_Type_Ucarray_Index (Base)); + Gen_B8 (0); + Gen_Uleb128 (Unsigned_32 (Get_Type_Subarray_Length (Atype))); + + Gen_Uleb128 (0); + end Emit_Subarray_Type; + + procedure Emit_Members (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + Nbr : Uns32; + F : O_Fnode; + Loc_Pc : Pc_Type; + Sibling_Pc : Pc_Type; + begin + if Abbrev_Member = 0 then + Generate_Abbrev (Abbrev_Member); + + Gen_Abbrev_Header (DW_TAG_Member, DW_CHILDREN_No); + + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Data_Member_Location, DW_FORM_Block1); + Gen_Abbrev_Tuple (0, 0); + end if; + + Set_Current_Section (Info_Sect); + Sibling_Pc := Gen_Info_Sibling; + Emit_Decl_Ident_If_Set (Decl); + Gen_Uleb128 (Unsigned_32 (Get_Type_Size (Atype))); + + Nbr := Get_Type_Record_Nbr_Fields (Atype); + F := Get_Type_Record_Fields (Atype); + while Nbr > 0 loop + Gen_Uleb128 (Abbrev_Member); + Emit_Ident (Get_Field_Ident (F)); + Emit_Type_Ref (Get_Field_Type (F)); + + -- Location. + Loc_Pc := Get_Current_Pc; + Gen_B8 (3); + Gen_B8 (DW_OP_Plus_Uconst); + Gen_Uleb128 (Unsigned_32 (Get_Field_Offset (F))); + Patch_B8 (Loc_Pc, Unsigned_8 (Get_Current_Pc - (Loc_Pc + 1))); + + F := Get_Field_Chain (F); + Nbr := Nbr - 1; + end loop; + + -- end of children. + Gen_Uleb128 (0); + Patch_Info_Sibling (Sibling_Pc); + end Emit_Members; + + procedure Emit_Record_Type (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + procedure Finish_Gen_Abbrev is + begin + Gen_Abbrev_Tuple (DW_AT_Byte_Size, DW_FORM_Udata); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev; + begin + if Decl = O_Dnode_Null then + if Abbrev_Struct = 0 then + Generate_Abbrev (Abbrev_Struct); + + Gen_Abbrev_Header (DW_TAG_Structure_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Struct); + else + if Abbrev_Struct_Name = 0 then + Generate_Abbrev (Abbrev_Struct_Name); + + Gen_Abbrev_Header (DW_TAG_Structure_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Struct_Name); + end if; + Emit_Members (Atype, Decl); + end Emit_Record_Type; + + procedure Emit_Union_Type (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + procedure Finish_Gen_Abbrev is + begin + Gen_Abbrev_Tuple (DW_AT_Byte_Size, DW_FORM_Udata); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev; + begin + if Decl = O_Dnode_Null then + if Abbrev_Union = 0 then + Generate_Abbrev (Abbrev_Union); + + Gen_Abbrev_Header (DW_TAG_Union_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Union); + else + if Abbrev_Union_Name = 0 then + Generate_Abbrev (Abbrev_Union_Name); + + Gen_Abbrev_Header (DW_TAG_Union_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Union_Name); + end if; + Emit_Members (Atype, Decl); + end Emit_Union_Type; + + procedure Emit_Enum_Type (Atype : O_Tnode; Decl : O_Dnode) + is + use Ortho_Code.Types; + use Ortho_Code.Consts; + procedure Finish_Gen_Abbrev is + begin + Gen_Abbrev_Tuple (DW_AT_Byte_Size, DW_FORM_Data1); + Gen_Abbrev_Tuple (0, 0); + end Finish_Gen_Abbrev; + + procedure Emit_Enumerator (L : O_Cnode) is + begin + Gen_Uleb128 (Abbrev_Enumerator); + Emit_Ident (Get_Lit_Ident (L)); + Gen_Uleb128 (Unsigned_32 (Get_Lit_Value (L))); + end Emit_Enumerator; + + Nbr : Uns32; + L : O_Cnode; + Sibling_Pc : Pc_Type; + begin + if Abbrev_Enumerator = 0 then + Generate_Abbrev (Abbrev_Enumerator); + + Gen_Abbrev_Header (DW_TAG_Enumerator, DW_CHILDREN_No); + + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Const_Value, DW_FORM_Udata); + Gen_Abbrev_Tuple (0, 0); + end if; + if Decl = O_Dnode_Null then + if Abbrev_Enum = 0 then + Generate_Abbrev (Abbrev_Enum); + Gen_Abbrev_Header (DW_TAG_Enumeration_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Enum); + else + if Abbrev_Enum_Name = 0 then + Generate_Abbrev (Abbrev_Enum_Name); + Gen_Abbrev_Header (DW_TAG_Enumeration_Type, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Finish_Gen_Abbrev; + end if; + Gen_Info_Header (Abbrev_Enum_Name); + end if; + + Sibling_Pc := Gen_Info_Sibling; + Emit_Decl_Ident_If_Set (Decl); + Gen_B8 (Byte (Get_Type_Size (Atype))); + case Get_Type_Kind (Atype) is + when OT_Enum => + Nbr := Get_Type_Enum_Nbr_Lits (Atype); + L := Get_Type_Enum_Lits (Atype); + while Nbr > 0 loop + Emit_Enumerator (L); + + L := Get_Lit_Chain (L); + Nbr := Nbr - 1; + end loop; + when OT_Boolean => + Emit_Enumerator (Get_Type_Bool_False (Atype)); + Emit_Enumerator (Get_Type_Bool_True (Atype)); + when others => + raise Program_Error; + end case; + + -- End of children. + Gen_Uleb128 (0); + Patch_Info_Sibling (Sibling_Pc); + end Emit_Enum_Type; + + procedure Emit_Type (Atype : O_Tnode) + is + use Ortho_Code.Types; + use Ada.Text_IO; + Kind : OT_Kind; + Decl : O_Dnode; + begin + -- If already emitted, then return. + if Atype <= TOnodes.Last + and then TOnodes.Table (Atype) /= Null_Pc + then + return; + end if; + + Kind := Get_Type_Kind (Atype); + + -- First step: emit inner types (if any). + case Kind is + when OT_Signed + | OT_Unsigned + | OT_Float + | OT_Boolean + | OT_Enum => + null; + when OT_Access => + null; + when OT_Ucarray => + Emit_Type (Get_Type_Ucarray_Index (Atype)); + Emit_Type (Get_Type_Ucarray_Element (Atype)); + when OT_Subarray => + Emit_Type (Get_Type_Subarray_Base (Atype)); + when OT_Record + | OT_Union => + declare + Nbr : Uns32; + F : O_Fnode; + begin + Nbr := Get_Type_Record_Nbr_Fields (Atype); + F := Get_Type_Record_Fields (Atype); + while Nbr > 0 loop + Emit_Type (Get_Field_Type (F)); + F := Get_Field_Chain (F); + Nbr := Nbr - 1; + end loop; + end; + when OT_Complete => + null; + end case; + + Set_Current_Section (Info_Sect); + Add_Type_Ref (Atype, Get_Current_Pc); + + Decl := Decls.Get_Type_Decl (Atype); + + -- Second step: emit info. + case Kind is + when OT_Signed + | OT_Unsigned + | OT_Float => + Emit_Base_Type (Atype, Decl); + -- base types. + when OT_Access => + Emit_Access_Type (Atype, Decl); + when OT_Ucarray => + Emit_Ucarray_Type (Atype, Decl); + when OT_Subarray => + Emit_Subarray_Type (Atype, Decl); + when OT_Record => + Emit_Record_Type (Atype, Decl); + when OT_Union => + Emit_Union_Type (Atype, Decl); + when OT_Enum + | OT_Boolean => + Emit_Enum_Type (Atype, Decl); + when OT_Complete => + null; + end case; + end Emit_Type; + + procedure Emit_Decl_Type (Decl : O_Dnode) + is + use Ortho_Code.Decls; + begin + Emit_Type_Ref (Get_Decl_Type (Decl)); + end Emit_Decl_Type; + + Abbrev_Variable : Unsigned_32 := 0; + Abbrev_Const : Unsigned_32 := 0; + + procedure Emit_Local_Location (Decl : O_Dnode) + is + use Ortho_Code.Decls; + Pc : Pc_Type; + begin + Pc := Get_Current_Pc; + Gen_B8 (2); + Gen_B8 (DW_OP_Fbreg); + Gen_Sleb128 (Get_Decl_Info (Decl)); + Patch_B8 (Pc, Unsigned_8 (Get_Current_Pc - (Pc + 1))); + end Emit_Local_Location; + + procedure Emit_Global_Location (Decl : O_Dnode) + is + use Ortho_Code.Binary; + begin + Gen_B8 (5); + Gen_B8 (DW_OP_Addr); + Gen_Ua_32 (Get_Decl_Symbol (Decl), 0); + end Emit_Global_Location; + + procedure Emit_Variable (Decl : O_Dnode) + is + use Ortho_Code.Decls; + Dtype : O_Tnode; + begin + if Get_Decl_Ident (Decl) = O_Ident_Nul then + return; + end if; + + if Abbrev_Variable = 0 then + Generate_Abbrev (Abbrev_Variable); + Gen_Abbrev_Header (DW_TAG_Variable, DW_CHILDREN_No); + + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Location, DW_FORM_Block1); + Gen_Abbrev_Tuple (0, 0); + end if; + + Dtype := Get_Decl_Type (Decl); + Emit_Type (Dtype); + + Gen_Info_Header (Abbrev_Variable); + Emit_Decl_Ident (Decl); + Emit_Type_Ref (Dtype); + case Get_Decl_Kind (Decl) is + when OD_Local => + Emit_Local_Location (Decl); + when OD_Var => + Emit_Global_Location (Decl); + when others => + raise Program_Error; + end case; + end Emit_Variable; + + procedure Emit_Const (Decl : O_Dnode) + is + use Ortho_Code.Decls; + Dtype : O_Tnode; + begin + if Abbrev_Const = 0 then + Generate_Abbrev (Abbrev_Const); + -- FIXME: should be a TAG_Constant, however, GDB does not support it. + -- work-around: could use a const_type. + Gen_Abbrev_Header (DW_TAG_Variable, DW_CHILDREN_No); + + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Location, DW_FORM_Block1); + Gen_Abbrev_Tuple (0, 0); + end if; + + Dtype := Get_Decl_Type (Decl); + Emit_Type (Dtype); + Gen_Info_Header (Abbrev_Const); + Emit_Decl_Ident (Decl); + Emit_Type_Ref (Dtype); + Emit_Global_Location (Decl); + end Emit_Const; + + procedure Emit_Type_Decl (Decl : O_Dnode) + is + use Ortho_Code.Decls; + begin + Emit_Type (Get_Decl_Type (Decl)); + end Emit_Type_Decl; + + Subprg_Sym : Symbol; + + Abbrev_Block : Unsigned_32 := 0; + + procedure Emit_Block_Decl (Decl : O_Dnode) + is + use Ortho_Code.Decls; + Last : O_Dnode; + Sdecl : O_Dnode; + Sibling_Pc : Pc_Type; + begin + if Abbrev_Block = 0 then + Generate_Abbrev (Abbrev_Block); + + Gen_Abbrev_Header (DW_TAG_Lexical_Block, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (0, 0); + end if; + + Gen_Info_Header (Abbrev_Block); + Sibling_Pc := Gen_Info_Sibling; + + Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Block_Info1 (Decl))); + Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Block_Info2 (Decl))); + + -- Emit decls for children. + Last := Get_Block_Last (Decl); + Sdecl := Decl + 1; + while Sdecl <= Last loop + Emit_Decl (Sdecl); + Sdecl := Get_Decl_Chain (Sdecl); + end loop; + + -- End of children. + Set_Current_Section (Info_Sect); + Gen_Uleb128 (0); + + Patch_Info_Sibling (Sibling_Pc); + end Emit_Block_Decl; + + Abbrev_Function : Unsigned_32 := 0; + Abbrev_Procedure : Unsigned_32 := 0; + Abbrev_Interface : Unsigned_32 := 0; + + procedure Emit_Subprg_Body (Bod : O_Dnode) + is + use Ortho_Code.Decls; + Kind : OD_Kind; + Decl : O_Dnode; + Idecl : O_Dnode; + Prev_Subprg_Sym : Symbol; + Sibling_Pc : Pc_Type; + begin + Decl := Get_Body_Decl (Bod); + Kind := Get_Decl_Kind (Decl); + + -- Emit interfaces type. + Idecl := Get_Subprg_Interfaces (Decl); + while Idecl /= O_Dnode_Null loop + Emit_Type (Get_Decl_Type (Idecl)); + Idecl := Get_Interface_Chain (Idecl); + end loop; + + if Kind = OD_Function then + Emit_Type (Get_Decl_Type (Decl)); + if Abbrev_Function = 0 then + Generate_Abbrev (Abbrev_Function); + + Gen_Abbrev_Header (DW_TAG_Subprogram, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (DW_AT_Frame_Base, DW_FORM_Block1); + --Gen_Abbrev_Tuple (DW_AT_Return_Addr, DW_FORM_Block1); + Gen_Abbrev_Tuple (0, 0); + end if; + Gen_Info_Header (Abbrev_Function); + else + if Abbrev_Procedure = 0 then + Generate_Abbrev (Abbrev_Procedure); + + Gen_Abbrev_Header (DW_TAG_Subprogram, DW_CHILDREN_Yes); + Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4); + + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr); + Gen_Abbrev_Tuple (DW_AT_Frame_Base, DW_FORM_Block1); + --Gen_Abbrev_Tuple (DW_AT_Return_Addr, DW_FORM_Block1); + Gen_Abbrev_Tuple (0, 0); + end if; + Gen_Info_Header (Abbrev_Procedure); + end if; + + Sibling_Pc := Gen_Info_Sibling; + + if Kind = OD_Function then + Emit_Decl_Type (Decl); + end if; + + Emit_Decl_Ident (Decl); + Prev_Subprg_Sym := Subprg_Sym; + Subprg_Sym := Binary.Get_Decl_Symbol (Decl); + Gen_Ua_32 (Subprg_Sym, 0); + Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Body_Info (Bod))); + + -- Frame base. + Gen_B8 (1); + Gen_B8 (DW_OP_Reg5); + + -- Interfaces. + Idecl := Get_Subprg_Interfaces (Decl); + if Idecl /= O_Dnode_Null then + if Abbrev_Interface = 0 then + Generate_Abbrev (Abbrev_Interface); + + Gen_Abbrev_Header (DW_TAG_Formal_Parameter, DW_CHILDREN_No); + Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4); + Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String); + Gen_Abbrev_Tuple (DW_AT_Location, DW_FORM_Block1); + Gen_Abbrev_Tuple (0, 0); + end if; + + loop + Gen_Info_Header (Abbrev_Interface); + Emit_Decl_Type (Idecl); + Emit_Decl_Ident (Idecl); + + Emit_Local_Location (Idecl); + + Idecl := Get_Interface_Chain (Idecl); + exit when Idecl = O_Dnode_Null; + end loop; + end if; + + -- Internal declarations. + Emit_Block_Decl (Bod + 1); + + -- End of children. + Gen_Uleb128 (0); + + Patch_Info_Sibling (Sibling_Pc); + + Subprg_Sym := Prev_Subprg_Sym; + end Emit_Subprg_Body; + + procedure Emit_Decl (Decl : O_Dnode) + is + use Ada.Text_IO; + use Ortho_Code.Decls; + begin + case Get_Decl_Kind (Decl) is + when OD_Type => + Emit_Type_Decl (Decl); + when OD_Local + | OD_Var => + Emit_Variable (Decl); + when OD_Const => + Emit_Const (Decl); + when OD_Function + | OD_Procedure + | OD_Interface => + null; + when OD_Body => + Emit_Subprg_Body (Decl); + when OD_Block => + Emit_Block_Decl (Decl); + when others => + Put_Line ("dwarf.emit_decl: emit " + & OD_Kind'Image (Get_Decl_Kind (Decl))); + end case; + end Emit_Decl; + + procedure Emit_Subprg (Bod : O_Dnode) is + begin + Emit_Decls_Until (Bod); + Emit_Decl (Bod); + Last_Decl := Decls.Get_Decl_Chain (Bod); + end Emit_Subprg; + + procedure Mark (M : out Mark_Type) is + begin + M.Last_Decl := Last_Decl; + M.Last_Tnode := TOnodes.Last; + end Mark; + + procedure Release (M : Mark_Type) is + begin + Last_Decl := M.Last_Decl; + TOnodes.Set_Last (M.Last_Tnode); + end Release; + +end Ortho_Code.Dwarf; + diff --git a/src/ortho/mcode/ortho_code-dwarf.ads b/src/ortho/mcode/ortho_code-dwarf.ads new file mode 100644 index 000000000..c120bcfe1 --- /dev/null +++ b/src/ortho/mcode/ortho_code-dwarf.ads @@ -0,0 +1,41 @@ +-- Mcode back-end for ortho - Dwarf generator. +-- 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. +package Ortho_Code.Dwarf is + procedure Init; + procedure Finish; + + -- For a body. + procedure Emit_Subprg (Bod : O_Dnode); + + -- Emit all debug info until but not including LAST. + procedure Emit_Decls_Until (Last : O_Dnode); + + -- For a line in a subprogram. + procedure Set_Line_Stmt (Line : Int32); + procedure Set_Filename (Dir : String; File : String); + + type Mark_Type is limited private; + procedure Mark (M : out Mark_Type); + procedure Release (M : Mark_Type); + +private + type Mark_Type is record + Last_Decl : O_Dnode; + Last_Tnode : O_Tnode; + end record; +end Ortho_Code.Dwarf; diff --git a/src/ortho/mcode/ortho_code-exprs.adb b/src/ortho/mcode/ortho_code-exprs.adb new file mode 100644 index 000000000..b2dfa1a67 --- /dev/null +++ b/src/ortho/mcode/ortho_code-exprs.adb @@ -0,0 +1,1663 @@ +-- 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; use 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_Stack_Adjust (Enode : O_Enode) return Int32 is + begin + return Int32 (Enodes.Table (Enode).Arg1); + end Get_Stack_Adjust; + + 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; + pragma Unreferenced (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; + + function Get_Loop_Level (Stmt : O_Enode) return Int32 is + begin + return Int32 (Enodes.Table (Stmt).Arg1); + end Get_Loop_Level; + + procedure Set_Loop_Level (Stmt : O_Enode; Level : Int32) is + begin + Enodes.Table (Stmt).Arg1 := O_Enode (Level); + end Set_Loop_Level; + + 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 : constant 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_Union + | OC_Sizeof + | OC_Alignof => + 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 + -- The static chain is the first interface of the subprogram. + Res := New_Enode (OE_Addrl, Abi.Mode_Ptr, O_Tnode_Ptr, + O_Enode (Get_Subprg_Interfaces (Subprg.D_Decl)), + 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; + if Get_Base_Type (Get_Enode_Type (O_Enode (Lvalue))) + /= Get_Base_Type (Get_Type_Access_Type (Atype)) + 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; + St_Type : O_Tnode; + 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); + if Stack_Ptr_Type /= O_Tnode_Null then + St_Type := Stack_Ptr_Type; + else + St_Type := Rtype; + end if; + -- Add a decl. + New_Var_Decl (Save_Var, O_Ident_Nul, O_Storage_Local, St_Type); + -- Add insn to save stack ptr. + Stmt := New_Enode (OE_Asgn, St_Type, + New_Stack (St_Type), + 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 not Flag_Lower_Stmt 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_Else_Stmt (Block : in out O_If_Block) is + begin + if not Flag_Lower_Stmt then + New_Enode_Stmt (OE_Else, 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 not Flag_Lower_Stmt 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 not Flag_Lower_Stmt 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 not Flag_Lower_Stmt 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 not Flag_Lower_Stmt 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 not Flag_Lower_Stmt 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 Debug_Expr (N : O_Enode) + is + use Ada.Text_IO; + use Ortho_Code.Debug.Int32_IO; + Indent : constant Count := Col; + begin + Put (Int32 (N), 0); + Set_Col (Indent + 7); + Disp_Mode (Get_Expr_Mode (N)); + Put (" "); + Put (OE_Kind'Image (Get_Expr_Kind (N))); + Set_Col (Indent + 28); +-- 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 Debug_Expr; + + procedure Disp_Subprg_Body (Indent : Natural; Subprg : O_Enode) + is + use Ada.Text_IO; + 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. + Set_Col (Count (Indent)); + Debug_Expr (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 => + Set_Col (Count (Indent)); + Debug_Expr (N); + exit; + when others => + Set_Col (Count (N_Indent)); + Debug_Expr (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 + Debug_Expr (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; diff --git a/src/ortho/mcode/ortho_code-exprs.ads b/src/ortho/mcode/ortho_code-exprs.ads new file mode 100644 index 000000000..9bd4596d7 --- /dev/null +++ b/src/ortho/mcode/ortho_code-exprs.ads @@ -0,0 +1,600 @@ +-- 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. +package Ortho_Code.Exprs is + type OE_Kind is + ( + OE_Nil, + + -- Dyadic operations. + -- ARG1 is left, ARG2 is right. + OE_Add_Ov, + OE_Sub_Ov, + OE_Mul_Ov, + OE_Div_Ov, + OE_Rem, + OE_Mod, + + OE_And, + OE_Or, + OE_Xor, + + -- Monadic operations. + -- ARG1 is expression. + OE_Not, + OE_Neg_Ov, + OE_Abs_Ov, + + -- Comparaison. + -- ARG1 is left, ARG2 is right. + OE_Eq, + OE_Neq, + OE_Le, + OE_Lt, + OE_Ge, + OE_Gt, + + -- Without checks, for addresses. + OE_Add, + OE_Mul, + OE_Shl, -- Left shift + + -- A literal. + -- ARG1 is low part, ARG2 is high part. + OE_Const, + + -- Address of a local variable/parameter. + -- ARG1 is object. + -- ARG2 is the frame pointer or O_Enode_Null for current frame pointer. + OE_Addrl, + -- Address of a global variable. + -- ARG1 is object. + OE_Addrg, + + -- Pointer dereference. + -- ARG1 is operand. + OE_Indir, + + -- Conversion. + -- ARG1 is expression. + -- ARG2: type + OE_Conv_Ptr, + OE_Conv, + + -- Typed expression. + OE_Typed, + + -- Local memory allocation. + -- ARG1 is size (in bytes). + OE_Alloca, + + -- Statements. + + -- Subrogram entry. + -- ARG1 is the corresponding Leave (used to skip inner subprograms). + -- ARG2 is unused. + OE_Entry, + -- Subprogram exit. + -- ARG1 and ARG2 are unused. + OE_Leave, + + -- Declaration blocks. + -- ARG1: parent + -- ARG2: corresponding declarations. + OE_Beg, + -- ARG1: corresponding beg + -- ARG2: unsused. + OE_End, + + -- Assignment. + -- ARG1 is value, ARG2 is target (address). + OE_Asgn, + + -- Subprogram calls. + -- ARG1 is value + -- ARG2 is link to the next argument. + OE_Arg, + -- ARG1 is subprogram + -- ARG2 is arguments. + OE_Call, + -- ARG1 is intrinsic operation. + OE_Intrinsic, + + -- Modify the stack pointer value, to align the stack before pushing + -- arguments, or to free the stack. + -- ARG1 is the signed offset. + OE_Stack_Adjust, + + -- Return ARG1 (if not mode_nil) from current subprogram. + -- ARG1: expression. + OE_Ret, + + -- Line number (for debugging). + -- ARG1: line number + OE_Line, + + -- High level instructions. + + -- Basic block. + -- ARG1: next BB + -- ARG2: number + OE_BB, + + -- ARG1 is the literal. + OE_Lit, + -- ARG1: value + -- ARG2: first branch (HLI only). + OE_Case, + -- ARG1: the corresponding OE_Case + OE_Case_Expr, + -- ARG1: left bound + -- ARG2: right bound + -- LINK: choice link + OE_Case_Choice, + -- ARG1: choice link + -- ARG2: next branch + OE_Case_Branch, + -- End of case. + OE_Case_End, + + -- ARG1: the condition + -- ARG2: the else/endif + OE_If, + OE_Else, + OE_Endif, + + -- ARG1: loop level. + OE_Loop, + -- ARG1: loop. + OE_Eloop, + -- ARG2: loop. + OE_Next, + OE_Exit, + + -- ARG1: the record + -- ARG2: the field + OE_Record_Ref, + + -- ARG1: the expression. + OE_Access_Ref, + + -- ARG1: the array + -- ARG2: the index + OE_Index_Ref, + OE_Slice_Ref, + + -- Low level instructions. + + -- Label. + -- ARG1: current block (used for alloca), only during tree building. + -- ARG2: user info (generally used to store symbol). + OE_Label, + + -- Jump to ARG2. + OE_Jump, + + -- Jump to ARG2 if ARG1 is true/false. + OE_Jump_T, + OE_Jump_F, + + -- Used internally only. + -- ARG2 is info/target, ARG1 is expression (if any). + OE_Spill, + OE_Reload, + OE_Move, + + -- Alloca/allocb handling. + OE_Get_Stack, + OE_Set_Stack, + + -- Get current frame pointer. + OE_Get_Frame, + + -- Additionnal reg + OE_Reg + ); + for OE_Kind'Size use 8; + + subtype OE_Kind_Dyadic is OE_Kind range OE_Add_Ov .. OE_Xor; + subtype OE_Kind_Cmp is OE_Kind range OE_Eq .. OE_Gt; + + + -- BE representation of an instruction. + type O_Insn is mod 256; + + type Subprogram_Data; + type Subprogram_Data_Acc is access Subprogram_Data; + + type Subprogram_Data is record + -- Parent or null if top-level subprogram. + Parent : Subprogram_Data_Acc; + + -- Block in which this subprogram is declared, or o_dnode_null if + -- top-level subprogram. + --Parent_Block : O_Dnode; + + -- First and last child, or null if no children. + First_Child : Subprogram_Data_Acc; + Last_Child : Subprogram_Data_Acc; + + -- Next subprogram at the same depth level. + Brother : Subprogram_Data_Acc; + + -- Depth of the subprogram. + Depth : O_Depth; + + -- Dnode for the declaration. + D_Decl : O_Dnode; + + -- Enode for the Entry. + E_Entry : O_Enode; + + -- Dnode for the Body. + D_Body : O_Dnode; + + -- Label just before leave. + Exit_Label : O_Enode; + + -- Last statement of this subprogram. + Last_Stmt : O_Enode; + + -- Static maximum stack use. + Stack_Max : Uns32; + end record; + + -- Data for the current subprogram. + Cur_Subprg : Subprogram_Data_Acc := null; + + -- First and last (top-level) subprogram. + First_Subprg : Subprogram_Data_Acc := null; + Last_Subprg : Subprogram_Data_Acc := null; + + -- Type of the stack pointer - for OE_Get_Stack and OE_Set_Stack. + -- Can be set by back-ends. + Stack_Ptr_Type : O_Tnode := O_Tnode_Null; + + -- Create a new node. + -- Should be used only by back-end to add internal nodes. + function New_Enode (Kind : OE_Kind; + Mode : Mode_Type; + Rtype : O_Tnode; + Arg1 : O_Enode; + Arg2 : O_Enode) return O_Enode; + + -- Get the kind of ENODE. + function Get_Expr_Kind (Enode : O_Enode) return OE_Kind; + pragma Inline (Get_Expr_Kind); + + -- Get the mode of ENODE. + function Get_Expr_Mode (Enode : O_Enode) return Mode_Type; + pragma Inline (Get_Expr_Mode); + + -- Get/Set the register of ENODE. + function Get_Expr_Reg (Enode : O_Enode) return O_Reg; + procedure Set_Expr_Reg (Enode : O_Enode; Reg : O_Reg); + pragma Inline (Get_Expr_Reg); + pragma Inline (Set_Expr_Reg); + + -- Get the operand of an unary expression. + function Get_Expr_Operand (Enode : O_Enode) return O_Enode; + procedure Set_Expr_Operand (Enode : O_Enode; Val : O_Enode); + + -- Get left/right operand of a binary expression. + function Get_Expr_Left (Enode : O_Enode) return O_Enode; + function Get_Expr_Right (Enode : O_Enode) return O_Enode; + procedure Set_Expr_Left (Enode : O_Enode; Val : O_Enode); + procedure Set_Expr_Right (Enode : O_Enode; Val : O_Enode); + + -- Get the low and high part of an OE_CONST node. + function Get_Expr_Low (Cst : O_Enode) return Uns32; + function Get_Expr_High (Cst : O_Enode) return Uns32; + + -- Get target of the assignment. + function Get_Assign_Target (Enode : O_Enode) return O_Enode; + procedure Set_Assign_Target (Enode : O_Enode; Targ : O_Enode); + + -- For OE_Lit: get the literal. + function Get_Expr_Lit (Lit : O_Enode) return O_Cnode; + + -- Type of a OE_Conv/OE_Nop/OE_Typed/OE_Alloca + -- Used only for display/debugging purposes. + function Get_Conv_Type (Enode : O_Enode) return O_Tnode; + + -- Leave node corresponding to the entry. + function Get_Entry_Leave (Enode : O_Enode) return O_Enode; + + -- Get the label of a jump/ret + function Get_Jump_Label (Enode : O_Enode) return O_Enode; + procedure Set_Jump_Label (Enode : O_Enode; Label : O_Enode); + + -- Get the object of addrl,addrp,addrg + function Get_Addr_Object (Enode : O_Enode) return O_Dnode; + + -- Get the computed frame for the object. + -- If O_Enode_Null, then use current frame. + function Get_Addrl_Frame (Enode : O_Enode) return O_Enode; + procedure Set_Addrl_Frame (Enode : O_Enode; Frame : O_Enode); + + -- Return the stack adjustment. For positive values, this is the amount of + -- bytes to allocate on the stack before pushing arguments, so that the + -- stack pointer stays aligned. For negtive values, this is the amount of + -- bytes to release on the stack. + function Get_Stack_Adjust (Enode : O_Enode) return Int32; + + -- Get the subprogram called by ENODE. + function Get_Call_Subprg (Enode : O_Enode) return O_Dnode; + + -- Get the first argument of a call, or the next argument of an arg. + function Get_Arg_Link (Enode : O_Enode) return O_Enode; + + -- Get the declaration chain of a Beg statement. + function Get_Block_Decls (Blk : O_Enode) return O_Dnode; + + -- Get the parent of the block. + function Get_Block_Parent (Blk : O_Enode) return O_Enode; + + -- Get the corresponding beg. + function Get_End_Beg (Blk : O_Enode) return O_Enode; + + -- True if the block contains an alloca insn. + function Get_Block_Has_Alloca (Blk : O_Enode) return Boolean; + + -- Set the next branch of a case/case_branch. + procedure Set_Case_Branch (C : O_Enode; Branch : O_Enode); + + -- Set the first choice of a case branch. + procedure Set_Case_Branch_Choice (Branch : O_Enode; Choice : O_Enode); + function Get_Case_Branch_Choice (Branch : O_Enode) return O_Enode; + + -- Set the choice link of a case choice. + procedure Set_Case_Choice_Link (Choice : O_Enode; N_Choice : O_Enode); + function Get_Case_Choice_Link (Choice : O_Enode) return O_Enode; + + -- Get/Set the max stack size for the end block BLKE. + --function Get_Block_Max_Stack (Blke : O_Enode) return Int32; + --procedure Set_Block_Max_Stack (Blke : O_Enode; Max : Int32); + + -- Get the field of an o_record_ref node. + function Get_Ref_Field (Ref : O_Enode) return O_Fnode; + + -- Get the index of an OE_Index_Ref or OE_Slice_Ref node. + function Get_Ref_Index (Ref : O_Enode) return O_Enode; + + -- Get/Set the info field of a label. + function Get_Label_Info (Label : O_Enode) return Int32; + procedure Set_Label_Info (Label : O_Enode; Info : Int32); + + -- Get the info of a spill. + function Get_Spill_Info (Spill : O_Enode) return Int32; + procedure Set_Spill_Info (Spill : O_Enode; Info : Int32); + + -- Get the statement link. + function Get_Stmt_Link (Stmt : O_Enode) return O_Enode; + procedure Set_Stmt_Link (Stmt : O_Enode; Next : O_Enode); + + -- Get the line number of an OE_Line statement. + function Get_Expr_Line_Number (Stmt : O_Enode) return Int32; + + -- Get the operation of an intrinsic. + function Get_Intrinsic_Operation (Stmt : O_Enode) return Int32; + + -- Get the basic block label (uniq number). + function Get_BB_Number (Stmt : O_Enode) return Int32; + + -- For OE_Loop, set loop level (an integer). + -- Reserved for back-end in HLI mode only. + function Get_Loop_Level (Stmt : O_Enode) return Int32; + procedure Set_Loop_Level (Stmt : O_Enode; Level : Int32); + + -- Start a subprogram body. + -- Note: the declaration may have an external storage, in this case it + -- becomes public. + procedure Start_Subprogram_Body (Func : O_Dnode); + + -- Finish a subprogram body. + procedure Finish_Subprogram_Body; + + -- Translate a scalar literal into an expression. + function New_Lit (Lit : O_Cnode) return O_Enode; + + -- Translate an object (var, const or interface) into an lvalue. + function New_Obj (Obj : O_Dnode) return O_Lnode; + + -- Create a dyadic operation. + -- Left and right nodes must have the same type. + -- Binary operation is allowed only on boolean types. + -- The result is of the type of the operands. + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode; + + -- Create a monadic operation. + -- Result is of the type of operand. + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode; + + -- Create a comparaison operator. + -- NTYPE is the type of the result and must be a boolean type. + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) + return O_Enode; + + -- Returns the size in bytes of ATYPE. The result is a literal of + -- unsigned type RTYPE + -- ATYPE cannot be an unconstrained array type. + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Enode; + + -- Returns the offset of FIELD in its record. The result is a literal + -- of unsigned type RTYPE. + function New_Offsetof (Field : O_Fnode; Rtype : O_Tnode) return O_Enode; + + -- 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; + + -- 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; + + -- Get an element of a record. + -- Type of REC must be a record type. + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode; + + -- Reference an access. + -- Type of ACC must be an access type. + function New_Access_Element (Acc : O_Enode) return O_Lnode; + + -- Do a conversion. + -- Allowed conversions are: + -- FIXME: to write. + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode; + + -- Same as New_Address but without any restriction. + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode; + + -- Get the address of a subprogram. + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Enode; + + -- Get the value of an Lvalue. + function New_Value (Lvalue : O_Lnode) return O_Enode; + + -- Return a pointer of type RTPE to SIZE bytes allocated on the stack. + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode; + + type O_Assoc_List is limited private; + + -- Create a function call or a procedure call. + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode); + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode); + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode; + procedure New_Procedure_Call (Assocs : in out O_Assoc_List); + + -- Assign VALUE to TARGET, type must be the same or compatible. + -- FIXME: what about slice assignment? + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode); + + -- Exit from the subprogram and return VALUE. + procedure New_Return_Stmt (Value : O_Enode); + -- Exit from the subprogram, which doesn't return value. + procedure New_Return_Stmt; + + type O_If_Block is limited private; + + -- Build an IF statement. + procedure Start_If_Stmt (Block : out O_If_Block; Cond : O_Enode); + procedure New_Else_Stmt (Block : in out O_If_Block); + procedure Finish_If_Stmt (Block : in out O_If_Block); + + type O_Snode is private; + O_Snode_Null : constant O_Snode; + + -- Create a infinite loop statement. + procedure Start_Loop_Stmt (Label : out O_Snode); + procedure Finish_Loop_Stmt (Label : in out O_Snode); + + -- Exit from a loop stmt or from a for stmt. + procedure New_Exit_Stmt (L : O_Snode); + -- Go to the start of a loop stmt or of a for stmt. + -- Loops/Fors between L and the current points are exited. + procedure New_Next_Stmt (L : O_Snode); + + -- Case statement. + -- VALUE is the selector and must be a discrete type. + type O_Case_Block is limited private; + procedure Start_Case_Stmt (Block : out O_Case_Block; Value : O_Enode); + procedure Start_Choice (Block : in out O_Case_Block); + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode); + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode); + procedure New_Default_Choice (Block : in out O_Case_Block); + procedure Finish_Choice (Block : in out O_Case_Block); + procedure Finish_Case_Stmt (Block : in out O_Case_Block); + + procedure Start_Declare_Stmt; + procedure Finish_Declare_Stmt; + + procedure New_Debug_Line_Stmt (Line : Natural); + + procedure Disp_Subprg_Body (Indent : Natural; Subprg : O_Enode); + procedure Disp_All_Enode; + procedure Disp_Stats; + + type Mark_Type is limited private; + procedure Mark (M : out Mark_Type); + procedure Release (M : Mark_Type); + + procedure Finish; +private + type O_Assoc_List is record + -- Subprogram being called. + Subprg : O_Dnode; + -- First and last argument statement. + First_Arg : O_Enode; + Last_Arg : O_Enode; + -- Interface for the next association. + Next_Inter : O_Dnode; + end record; + + type O_Case_Block is record + -- Expression for the selection. + Expr : O_Enode; + + -- Type of expression. + -- Used to perform checks. + Expr_Type : O_Tnode; + + -- Choice code and branch code is not mixed (anymore). + -- Therefore, code to perform choices is inserted. + -- Last node of the choice code. + Last_Node : O_Enode; + + -- Label at the end of the case statement. + -- used to jump from the end of a branch to the end of the statement. + Label_End : O_Enode; + + -- Label of the branch code. + Label_Branch : O_Enode; + end record; + + type O_If_Block is record + Label_End : O_Enode; + Label_Next : O_Enode; + end record; + + type O_Snode is record + Label_Start : O_Enode; + Label_End : O_Enode; + end record; + O_Snode_Null : constant O_Snode := (Label_Start => O_Enode_Null, + Label_End => O_Enode_Null); + + type Mark_Type is record + Enode : O_Enode; + end record; +end Ortho_Code.Exprs; diff --git a/src/ortho/mcode/ortho_code-flags.ads b/src/ortho/mcode/ortho_code-flags.ads new file mode 100644 index 000000000..805f3779b --- /dev/null +++ b/src/ortho/mcode/ortho_code-flags.ads @@ -0,0 +1,35 @@ +-- Compile flags for mcode. +-- 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. +package Ortho_Code.Flags is + type Debug_Type is (Debug_None, Debug_Dwarf); + + -- Debugging information generated. + Flag_Debug : Debug_Type := Debug_None; + + -- If set, generate a map from type to type declaration. + Flag_Type_Name : Boolean := False; + + -- If set, enable optimiztions. + Flag_Optimize : Boolean := False; + + -- If set, create basic blocks during tree building. + Flag_Opt_BB : Boolean := False; + + -- If set, add profiling calls. + Flag_Profile : Boolean := False; +end Ortho_Code.Flags; diff --git a/src/ortho/mcode/ortho_code-opts.adb b/src/ortho/mcode/ortho_code-opts.adb new file mode 100644 index 000000000..0ea6b039b --- /dev/null +++ b/src/ortho/mcode/ortho_code-opts.adb @@ -0,0 +1,214 @@ +-- Mcode back-end for ortho - Optimization. +-- 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 Ortho_Code.Flags; + +package body Ortho_Code.Opts is + procedure Relabel_Jump (Jmp : O_Enode) + is + Label : O_Enode; + Bb : O_Enode; + begin + Label := Get_Jump_Label (Jmp); + if Get_Expr_Kind (Label) = OE_Label then + Bb := O_Enode (Get_Label_Info (Label)); + if Bb /= O_Enode_Null then + Set_Jump_Label (Jmp, Bb); + end if; + end if; + end Relabel_Jump; + + procedure Jmp_To_Bb (Subprg : Subprogram_Data_Acc) + is + First : O_Enode; + Stmt : O_Enode; + Prev : O_Enode; + Cur_Bb : O_Enode; + begin + -- Get first statement after entry. + First := Get_Stmt_Link (Subprg.E_Entry); + + -- First loop: + -- If a label belongs to a BB (ie, is at the beginning of a BB), + -- then link it to the BB. + Stmt := First; + Cur_Bb := O_Enode_Null; + loop + case Get_Expr_Kind (Stmt) is + when OE_Leave => + exit; + when OE_BB => + Cur_Bb := Stmt; + when OE_Label => + if Cur_Bb /= O_Enode_Null then + Set_Label_Info (Stmt, Int32 (Cur_Bb)); + end if; + when OE_Jump + | OE_Jump_T + | OE_Jump_F => + -- This handles backward jump. + Relabel_Jump (Stmt); + when others => + Cur_Bb := O_Enode_Null; + end case; + Stmt := Get_Stmt_Link (Stmt); + end loop; + + -- Second loop: + -- Transform jump to label to jump to BB. + Stmt := First; + Prev := O_Enode_Null; + loop + case Get_Expr_Kind (Stmt) is + when OE_Leave => + exit; + when OE_Jump + | OE_Jump_T + | OE_Jump_F => + -- This handles forward jump. + Relabel_Jump (Stmt); + -- Update PREV. + Prev := Stmt; + when OE_Label => + -- Remove the Label. + -- Do not update PREV. + if Get_Label_Info (Stmt) /= 0 then + Set_Stmt_Link (Prev, Get_Stmt_Link (Stmt)); + end if; + when others => + Prev := Stmt; + end case; + Stmt := Get_Stmt_Link (Stmt); + end loop; + end Jmp_To_Bb; + + type Oe_Kind_Bool_Array is array (OE_Kind) of Boolean; + Is_Passive_Stmt : constant Oe_Kind_Bool_Array := + (OE_Label | OE_BB | OE_End | OE_Beg => True, + others => False); + + -- Return the next statement after STMT which really execute instructions. + function Get_Fall_Stmt (Stmt : O_Enode) return O_Enode + is + Res : O_Enode; + begin + Res := Stmt; + loop + Res := Get_Stmt_Link (Res); + case Get_Expr_Kind (Res) is + when OE_Label + | OE_BB + | OE_End + | OE_Beg => + null; + when others => + return Res; + end case; + end loop; + end Get_Fall_Stmt; + pragma Unreferenced (Get_Fall_Stmt); + + procedure Thread_Jump (Subprg : Subprogram_Data_Acc) + is + First : O_Enode; + Stmt : O_Enode; + Prev, Next : O_Enode; + Kind : OE_Kind; + begin + -- Get first statement after entry. + First := Get_Stmt_Link (Subprg.E_Entry); + + -- First loop: + -- If a label belongs to a BB (ie, is at the beginning of a BB), + -- then link it to the BB. + Stmt := First; + Prev := O_Enode_Null; + loop + Next := Get_Stmt_Link (Stmt); + Kind := Get_Expr_Kind (Stmt); + case Kind is + when OE_Leave => + exit; + when OE_Jump => + -- Remove the jump if followed by the label. + -- * For _T/_F: should convert to a ignore value. + -- Discard unreachable statements after the jump. + declare + N_Stmt : O_Enode; + P_Stmt : O_Enode; + Label : O_Enode; + Flag_Discard : Boolean; + K_Stmt : OE_Kind; + begin + N_Stmt := Next; + P_Stmt := Stmt; + Label := Get_Jump_Label (Stmt); + Flag_Discard := True; + loop + if N_Stmt = Label then + -- Remove STMT. + Set_Stmt_Link (Prev, Next); + exit; + end if; + K_Stmt := Get_Expr_Kind (N_Stmt); + if K_Stmt = OE_Label then + -- Do not discard anymore statements, since they are + -- now reachable. + Flag_Discard := False; + end if; + if not Is_Passive_Stmt (K_Stmt) then + if not Flag_Discard then + -- We have found the next statement. + -- Keep the jump. + Prev := Stmt; + exit; + else + -- Delete insn. + N_Stmt := Get_Stmt_Link (N_Stmt); + Set_Stmt_Link (P_Stmt, N_Stmt); + end if; + else + -- Iterate. + P_Stmt := N_Stmt; + N_Stmt := Get_Stmt_Link (N_Stmt); + end if; + end loop; + end; + when others => + Prev := Stmt; + end case; + Stmt := Next; + end loop; + end Thread_Jump; + + procedure Optimize_Subprg (Subprg : Subprogram_Data_Acc) + is + begin + -- Jump optimisation: + -- * discard insns after a OE_JUMP. + -- * Remove jump if followed by label + -- (through label, BB, comments, end, line) + -- * Redirect jump to jump (infinite loop !) + -- * Revert jump_t/f if expr is not (XXX) + -- * Jmp_t/f L:; jmp L2; L1: -> jmp_f/t L2 + Thread_Jump (Subprg); + if Flags.Flag_Opt_BB then + Jmp_To_Bb (Subprg); + end if; + end Optimize_Subprg; +end Ortho_Code.Opts; + diff --git a/src/ortho/mcode/ortho_code-opts.ads b/src/ortho/mcode/ortho_code-opts.ads new file mode 100644 index 000000000..27a907c7b --- /dev/null +++ b/src/ortho/mcode/ortho_code-opts.ads @@ -0,0 +1,22 @@ +-- Mcode back-end for ortho - Optimization. +-- 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 Ortho_Code.Exprs; use Ortho_Code.Exprs; + +package Ortho_Code.Opts is + procedure Optimize_Subprg (Subprg : Subprogram_Data_Acc); +end Ortho_Code.Opts; diff --git a/src/ortho/mcode/ortho_code-types.adb b/src/ortho/mcode/ortho_code-types.adb new file mode 100644 index 000000000..e0c070c27 --- /dev/null +++ b/src/ortho/mcode/ortho_code-types.adb @@ -0,0 +1,820 @@ +-- Mcode back-end for ortho - type 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_Conversion; +with GNAT.Table; +with Ortho_Code.Consts; use Ortho_Code.Consts; +with Ortho_Code.Debug; +with Ortho_Code.Abi; use Ortho_Code.Abi; +with Ortho_Ident; + +package body Ortho_Code.Types is + type Bool_Array is array (Natural range <>) of Boolean; + pragma Pack (Bool_Array); + + type Tnode_Common is record + Kind : OT_Kind; -- 4 bits. + Mode : Mode_Type; -- 4 bits. + Align : Small_Natural; -- 2 bits. + Deferred : Boolean; -- 1 bit (True if the type was incomplete at first) + Flag1 : Boolean; + Pad0 : Bool_Array (0 .. 19); + Size : Uns32; + end record; + pragma Pack (Tnode_Common); + for Tnode_Common'Size use 64; + + type Tnode_Access is record + Dtype : O_Tnode; + Pad : Uns32; + end record; + + type Tnode_Array is record + Element_Type : O_Tnode; + Index_Type : O_Tnode; + end record; + + type Tnode_Subarray is record + Base_Type : O_Tnode; + Length : Uns32; + end record; + + type Tnode_Record is record + Fields : O_Fnode; + Nbr_Fields : Uns32; + end record; + + type Tnode_Enum is record + Lits : O_Cnode; + Nbr_Lits : Uns32; + end record; + + type Tnode_Bool is record + Lit_False : O_Cnode; + Lit_True : O_Cnode; + end record; + + package Tnodes is new GNAT.Table + (Table_Component_Type => Tnode_Common, + Table_Index_Type => O_Tnode, + Table_Low_Bound => O_Tnode_First, + Table_Initial => 128, + Table_Increment => 100); + + type Field_Type is record + Parent : O_Tnode; + Ident : O_Ident; + Ftype : O_Tnode; + Offset : Uns32; + Next : O_Fnode; + end record; + + package Fnodes is new GNAT.Table + (Table_Component_Type => Field_Type, + Table_Index_Type => O_Fnode, + Table_Low_Bound => 2, + Table_Initial => 64, + Table_Increment => 100); + + function Get_Type_Kind (Atype : O_Tnode) return OT_Kind is + begin + return Tnodes.Table (Atype).Kind; + end Get_Type_Kind; + + function Get_Type_Size (Atype : O_Tnode) return Uns32 is + begin + return Tnodes.Table (Atype).Size; + end Get_Type_Size; + + function Get_Type_Align (Atype : O_Tnode) return Small_Natural is + begin + return Tnodes.Table (Atype).Align; + end Get_Type_Align; + + function Get_Type_Align_Bytes (Atype : O_Tnode) return Uns32 is + begin + return 2 ** Get_Type_Align (Atype); + end Get_Type_Align_Bytes; + + function Get_Type_Mode (Atype : O_Tnode) return Mode_Type is + begin + return Tnodes.Table (Atype).Mode; + end Get_Type_Mode; + + function Get_Type_Deferred (Atype : O_Tnode) return Boolean is + begin + return Tnodes.Table (Atype).Deferred; + end Get_Type_Deferred; + + function Get_Type_Flag1 (Atype : O_Tnode) return Boolean is + begin + return Tnodes.Table (Atype).Flag1; + end Get_Type_Flag1; + + procedure Set_Type_Flag1 (Atype : O_Tnode; Flag : Boolean) is + begin + Tnodes.Table (Atype).Flag1 := Flag; + end Set_Type_Flag1; + + function To_Tnode_Access is new Ada.Unchecked_Conversion + (Source => Tnode_Common, Target => Tnode_Access); + + function Get_Type_Access_Type (Atype : O_Tnode) return O_Tnode + is + begin + return To_Tnode_Access (Tnodes.Table (Atype + 1)).Dtype; + end Get_Type_Access_Type; + + + function To_Tnode_Array is new Ada.Unchecked_Conversion + (Source => Tnode_Common, Target => Tnode_Array); + + function Get_Type_Ucarray_Index (Atype : O_Tnode) return O_Tnode is + begin + return To_Tnode_Array (Tnodes.Table (Atype + 1)).Index_Type; + end Get_Type_Ucarray_Index; + + function Get_Type_Ucarray_Element (Atype : O_Tnode) return O_Tnode is + begin + return To_Tnode_Array (Tnodes.Table (Atype + 1)).Element_Type; + end Get_Type_Ucarray_Element; + + + function To_Tnode_Subarray is new Ada.Unchecked_Conversion + (Source => Tnode_Common, Target => Tnode_Subarray); + + function Get_Type_Subarray_Base (Atype : O_Tnode) return O_Tnode is + begin + return To_Tnode_Subarray (Tnodes.Table (Atype + 1)).Base_Type; + end Get_Type_Subarray_Base; + + function Get_Type_Subarray_Length (Atype : O_Tnode) return Uns32 is + begin + return To_Tnode_Subarray (Tnodes.Table (Atype + 1)).Length; + end Get_Type_Subarray_Length; + + + function To_Tnode_Record is new Ada.Unchecked_Conversion + (Source => Tnode_Common, Target => Tnode_Record); + + function Get_Type_Record_Fields (Atype : O_Tnode) return O_Fnode is + begin + return To_Tnode_Record (Tnodes.Table (Atype + 1)).Fields; + end Get_Type_Record_Fields; + + function Get_Type_Record_Nbr_Fields (Atype : O_Tnode) return Uns32 is + begin + return To_Tnode_Record (Tnodes.Table (Atype + 1)).Nbr_Fields; + end Get_Type_Record_Nbr_Fields; + + function To_Tnode_Enum is new Ada.Unchecked_Conversion + (Source => Tnode_Common, Target => Tnode_Enum); + + function Get_Type_Enum_Lits (Atype : O_Tnode) return O_Cnode is + begin + return To_Tnode_Enum (Tnodes.Table (Atype + 1)).Lits; + end Get_Type_Enum_Lits; + + function Get_Type_Enum_Lit (Atype : O_Tnode; Pos : Uns32) return O_Cnode + is + F : O_Cnode; + begin + F := Get_Type_Enum_Lits (Atype); + return F + 2 * O_Cnode (Pos); + end Get_Type_Enum_Lit; + + function Get_Type_Enum_Nbr_Lits (Atype : O_Tnode) return Uns32 is + begin + return To_Tnode_Enum (Tnodes.Table (Atype + 1)).Nbr_Lits; + end Get_Type_Enum_Nbr_Lits; + + + function To_Tnode_Bool is new Ada.Unchecked_Conversion + (Source => Tnode_Common, Target => Tnode_Bool); + + function Get_Type_Bool_False (Atype : O_Tnode) return O_Cnode is + begin + return To_Tnode_Bool (Tnodes.Table (Atype + 1)).Lit_False; + end Get_Type_Bool_False; + + function Get_Type_Bool_True (Atype : O_Tnode) return O_Cnode is + begin + return To_Tnode_Bool (Tnodes.Table (Atype + 1)).Lit_True; + end Get_Type_Bool_True; + + function Get_Field_Offset (Field : O_Fnode) return Uns32 is + begin + return Fnodes.Table (Field).Offset; + end Get_Field_Offset; + + procedure Set_Field_Offset (Field : O_Fnode; Offset : Uns32) is + begin + Fnodes.Table (Field).Offset := Offset; + end Set_Field_Offset; + + function Get_Field_Parent (Field : O_Fnode) return O_Tnode is + begin + return Fnodes.Table (Field).Parent; + end Get_Field_Parent; + + function Get_Field_Type (Field : O_Fnode) return O_Tnode is + begin + return Fnodes.Table (Field).Ftype; + end Get_Field_Type; + + function Get_Field_Ident (Field : O_Fnode) return O_Ident is + begin + return Fnodes.Table (Field).Ident; + end Get_Field_Ident; + + function Get_Field_Chain (Field : O_Fnode) return O_Fnode is + begin + return Fnodes.Table (Field).Next; + end Get_Field_Chain; + + function New_Unsigned_Type (Size : Natural) return O_Tnode + is + Mode : Mode_Type; + Sz : Uns32; + begin + case Size is + when 8 => + Mode := Mode_U8; + Sz := 1; + when 16 => + Mode := Mode_U16; + Sz := 2; + when 32 => + Mode := Mode_U32; + Sz := 4; + when 64 => + Mode := Mode_U64; + Sz := 8; + when others => + raise Program_Error; + end case; + Tnodes.Append (Tnode_Common'(Kind => OT_Unsigned, + Mode => Mode, + Align => Mode_Align (Mode), + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => Sz)); + return Tnodes.Last; + end New_Unsigned_Type; + + function New_Signed_Type (Size : Natural) return O_Tnode + is + Mode : Mode_Type; + Sz : Uns32; + begin + case Size is + when 8 => + Mode := Mode_I8; + Sz := 1; + when 16 => + Mode := Mode_I16; + Sz := 2; + when 32 => + Mode := Mode_I32; + Sz := 4; + when 64 => + Mode := Mode_I64; + Sz := 8; + when others => + raise Program_Error; + end case; + Tnodes.Append (Tnode_Common'(Kind => OT_Signed, + Mode => Mode, + Align => Mode_Align (Mode), + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => Sz)); + return Tnodes.Last; + end New_Signed_Type; + + function New_Float_Type return O_Tnode is + begin + Tnodes.Append (Tnode_Common'(Kind => OT_Float, + Mode => Mode_F64, + Align => Mode_Align (Mode_F64), + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => 8)); + return Tnodes.Last; + end New_Float_Type; + + function To_Tnode_Common is new Ada.Unchecked_Conversion + (Source => Tnode_Enum, Target => Tnode_Common); + + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural) + is + Mode : Mode_Type; + Sz : Uns32; + begin + case Size is + when 8 => + Mode := Mode_U8; + Sz := 1; + when 16 => + Mode := Mode_U16; + Sz := 2; + when 32 => + Mode := Mode_U32; + Sz := 4; + when 64 => + Mode := Mode_U64; + Sz := 8; + when others => + raise Program_Error; + end case; + Tnodes.Append (Tnode_Common'(Kind => OT_Enum, + Mode => Mode, + Align => Mode_Align (Mode), + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => Sz)); + List := (Res => Tnodes.Last, + First => O_Cnode_Null, + Last => O_Cnode_Null, + Nbr => 0); + Tnodes.Increment_Last; + end Start_Enum_Type; + + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; Res : out O_Cnode) + is + begin + Res := New_Named_Literal (List.Res, Ident, List.Nbr, List.Last); + List.Nbr := List.Nbr + 1; + if List.Last = O_Cnode_Null then + List.First := Res; + end if; + List.Last := Res; + end New_Enum_Literal; + + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode) is + begin + Res := List.Res; + Tnodes.Table (List.Res + 1) := To_Tnode_Common + (Tnode_Enum'(Lits => List.First, + Nbr_Lits => List.Nbr)); + end Finish_Enum_Type; + + + function To_Tnode_Common is new Ada.Unchecked_Conversion + (Source => Tnode_Bool, Target => Tnode_Common); + + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode) + is + begin + Tnodes.Append (Tnode_Common'(Kind => OT_Boolean, + Mode => Mode_B2, + Align => 0, + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => 1)); + Res := Tnodes.Last; + False_E := New_Named_Literal (Res, False_Id, 0, O_Cnode_Null); + True_E := New_Named_Literal (Res, True_Id, 1, False_E); + Tnodes.Append (To_Tnode_Common (Tnode_Bool'(Lit_False => False_E, + Lit_True => True_E))); + end New_Boolean_Type; + + function To_Tnode_Common is new Ada.Unchecked_Conversion + (Source => Tnode_Array, Target => Tnode_Common); + + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode + is + Res : O_Tnode; + begin + Tnodes.Append (Tnode_Common'(Kind => OT_Ucarray, + Mode => Mode_Blk, + Align => Get_Type_Align (El_Type), + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => 0)); + Res := Tnodes.Last; + Tnodes.Append (To_Tnode_Common (Tnode_Array'(Element_Type => El_Type, + Index_Type => Index_Type))); + return Res; + end New_Array_Type; + + function To_Tnode_Common is new Ada.Unchecked_Conversion + (Source => Tnode_Subarray, Target => Tnode_Common); + + function New_Constrained_Array_Type (Atype : O_Tnode; Length : Uns32) + return O_Tnode + is + Res : O_Tnode; + Size : Uns32; + begin + Size := Get_Type_Size (Get_Type_Array_Element (Atype)); + Tnodes.Append (Tnode_Common'(Kind => OT_Subarray, + Mode => Mode_Blk, + Align => Get_Type_Align (Atype), + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => Size * Length)); + Res := Tnodes.Last; + Tnodes.Append (To_Tnode_Common (Tnode_Subarray'(Base_Type => Atype, + Length => Length))); + return Res; + end New_Constrained_Array_Type; + + procedure Create_Completer (Atype : O_Tnode) is + begin + Tnodes.Append (Tnode_Common'(Kind => OT_Complete, + Mode => Mode_Nil, + Align => 0, + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => To_Uns32 (Int32 (Atype)))); + end Create_Completer; + + function Get_Type_Complete_Type (Atype : O_Tnode) return O_Tnode is + begin + return O_Tnode (To_Int32 (Tnodes.Table (Atype).Size)); + end Get_Type_Complete_Type; + + function To_Tnode_Common is new Ada.Unchecked_Conversion + (Source => Tnode_Access, Target => Tnode_Common); + + function New_Access_Type (Dtype : O_Tnode) return O_Tnode + is + Res : O_Tnode; + begin + Tnodes.Append (Tnode_Common'(Kind => OT_Access, + Mode => Mode_P32, + Align => Mode_Align (Mode_P32), + Deferred => Dtype = O_Tnode_Null, + Flag1 => False, + Pad0 => (others => False), + Size => 4)); + Res := Tnodes.Last; + Tnodes.Append (To_Tnode_Common (Tnode_Access'(Dtype => Dtype, + Pad => 0))); + return Res; + end New_Access_Type; + + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode) is + begin + if Get_Type_Access_Type (Atype) /= O_Tnode_Null then + raise Program_Error; + end if; + Tnodes.Table (Atype + 1) := + To_Tnode_Common (Tnode_Access'(Dtype => Dtype, + Pad => 0)); + if Flag_Type_Completer then + Create_Completer (Atype); + end if; + end Finish_Access_Type; + + + function To_Tnode_Common is new Ada.Unchecked_Conversion + (Source => Tnode_Record, Target => Tnode_Common); + + function Create_Record_Type (Deferred : Boolean) return O_Tnode + is + Res : O_Tnode; + begin + Tnodes.Append (Tnode_Common'(Kind => OT_Record, + Mode => Mode_Blk, + Align => 0, + Deferred => Deferred, + Flag1 => False, + Pad0 => (others => False), + Size => 0)); + Res := Tnodes.Last; + Tnodes.Append (To_Tnode_Common (Tnode_Record'(Fields => O_Fnode_Null, + Nbr_Fields => 0))); + return Res; + end Create_Record_Type; + + procedure Start_Record_Type (Elements : out O_Element_List) + is + begin + Elements := (Res => Create_Record_Type (False), + First_Field => O_Fnode_Null, + Last_Field => O_Fnode_Null, + Off => 0, + Align => 0, + Nbr => 0); + end Start_Record_Type; + + procedure New_Uncomplete_Record_Type (Res : out O_Tnode) is + begin + Res := Create_Record_Type (True); + end New_Uncomplete_Record_Type; + + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List) + is + begin + Elements := (Res => Res, + First_Field => O_Fnode_Null, + Last_Field => O_Fnode_Null, + Off => 0, + Align => 0, + Nbr => 0); + end Start_Uncomplete_Record_Type; + + function Get_Mode_Size (Mode : Mode_Type) return Uns32 is + begin + case Mode is + when Mode_B2 + | Mode_U8 + | Mode_I8 => + return 1; + when Mode_I16 + | Mode_U16 => + return 2; + when Mode_I32 + | Mode_U32 + | Mode_P32 + | Mode_F32 => + return 4; + when Mode_I64 + | Mode_U64 + | Mode_P64 + | Mode_F64 => + return 8; + when Mode_X1 + | Mode_Nil + | Mode_Blk => + raise Program_Error; + end case; + end Get_Mode_Size; + + function Do_Align (Off : Uns32; Atype : O_Tnode) return Uns32 + is + Msk : constant Uns32 := Get_Type_Align_Bytes (Atype) - 1; + begin + -- Align. + return (Off + Msk) and (not Msk); + end Do_Align; + + function Do_Align (Off : Uns32; Mode : Mode_Type) return Uns32 + is + Msk : constant Uns32 := (2 ** Mode_Align (Mode)) - 1; + begin + -- Align. + return (Off + Msk) and (not Msk); + end Do_Align; + + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode) + is + begin + Elements.Off := Do_Align (Elements.Off, Etype); + + Fnodes.Append (Field_Type'(Parent => Elements.Res, + Ident => Ident, + Ftype => Etype, + Offset => Elements.Off, + Next => O_Fnode_Null)); + El := Fnodes.Last; + Elements.Off := Elements.Off + Get_Type_Size (Etype); + if Get_Type_Align (Etype) > Elements.Align then + Elements.Align := Get_Type_Align (Etype); + end if; + if Elements.Last_Field /= O_Fnode_Null then + Fnodes.Table (Elements.Last_Field).Next := Fnodes.Last; + else + Elements.First_Field := Fnodes.Last; + end if; + Elements.Last_Field := Fnodes.Last; + Elements.Nbr := Elements.Nbr + 1; + end New_Record_Field; + + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode) + is + begin + Tnodes.Table (Elements.Res).Size := Do_Align (Elements.Off, + Elements.Res); + Tnodes.Table (Elements.Res).Align := Elements.Align; + Tnodes.Table (Elements.Res + 1) := To_Tnode_Common + (Tnode_Record'(Fields => Elements.First_Field, + Nbr_Fields => Elements.Nbr)); + Res := Elements.Res; + if Flag_Type_Completer + and then Tnodes.Table (Elements.Res).Deferred + then + Create_Completer (Elements.Res); + end if; + end Finish_Record_Type; + + procedure Start_Union_Type (Elements : out O_Element_List) + is + begin + Tnodes.Append (Tnode_Common'(Kind => OT_Union, + Mode => Mode_Blk, + Align => 0, + Deferred => False, + Flag1 => False, + Pad0 => (others => False), + Size => 0)); + Elements := (Res => Tnodes.Last, + First_Field => O_Fnode_Null, + Last_Field => O_Fnode_Null, + Off => 0, + Align => 0, + Nbr => 0); + Tnodes.Append (To_Tnode_Common (Tnode_Record'(Fields => O_Fnode_Null, + Nbr_Fields => 0))); + end Start_Union_Type; + + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode) + is + Off : Uns32; + begin + Off := Elements.Off; + Elements.Off := 0; + New_Record_Field (Elements, El, Ident, Etype); + if Off > Elements.Off then + Elements.Off := Off; + end if; + end New_Union_Field; + + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode) + is + begin + Finish_Record_Type (Elements, Res); + end Finish_Union_Type; + + function Get_Type_Array_Element (Atype : O_Tnode) return O_Tnode + is + Base : O_Tnode; + begin + case Get_Type_Kind (Atype) is + when OT_Ucarray => + Base := Atype; + when OT_Subarray => + Base := Get_Type_Subarray_Base (Atype); + when others => + raise Program_Error; + end case; + return Get_Type_Ucarray_Element (Base); + end Get_Type_Array_Element; + + procedure Debug_Type (Atype : O_Tnode) + is + use Ortho_Code.Debug.Int32_IO; + use Ada.Text_IO; + Kind : OT_Kind; + begin + Put (Int32 (Atype), 3); + Put (" "); + Kind := Get_Type_Kind (Atype); + Put (OT_Kind'Image (Get_Type_Kind (Atype))); + Put (" "); + Put (Mode_Type'Image (Get_Type_Mode (Atype))); + Put (" D="); + Put (Boolean'Image (Get_Type_Deferred (Atype))); + Put (" F1="); + Put (Boolean'Image (Get_Type_Flag1 (Atype))); + New_Line; + case Kind is + when OT_Boolean => + Put (" false: "); + Put (Int32 (Get_Type_Bool_False (Atype))); + Put (", true: "); + Put (Int32 (Get_Type_Bool_True (Atype))); + New_Line; + when OT_Access => + Put (" acc_type: "); + Put (Int32 (Get_Type_Access_Type (Atype))); + New_Line; + when OT_Record => + Put (" fields: "); + Put (Int32 (Get_Type_Record_Fields (Atype))); + Put (", nbr_fields: "); + Put (To_Int32 (Get_Type_Record_Nbr_Fields (Atype))); + New_Line; + when OT_Subarray => + Put (" base type: "); + Put (Int32 (Get_Type_Subarray_Base (Atype))); + Put (", length: "); + Put (To_Int32 (Get_Type_Subarray_Length (Atype))); + New_Line; + when others => + null; + end case; + end Debug_Type; + + procedure Debug_Field (Field : O_Fnode) + is + use Ortho_Code.Debug.Int32_IO; + use Ada.Text_IO; + begin + Put (Int32 (Field), 3); + Put (" "); + Put (" Offset="); + Put (To_Int32 (Get_Field_Offset (Field)), 0); + Put (", Ident="); + Put (Ortho_Ident.Get_String (Get_Field_Ident (Field))); + Put (", Type="); + Put (Int32 (Get_Field_Type (Field)), 0); + Put (", Chain="); + Put (Int32 (Get_Field_Chain (Field)), 0); + New_Line; + end Debug_Field; + + function Get_Type_Limit return O_Tnode is + begin + return Tnodes.Last; + end Get_Type_Limit; + + function Get_Type_Next (Atype : O_Tnode) return O_Tnode is + begin + case Tnodes.Table (Atype).Kind is + when OT_Unsigned + | OT_Signed + | OT_Float => + return Atype + 1; + when OT_Boolean + | OT_Enum + | OT_Ucarray + | OT_Subarray + | OT_Access + | OT_Record + | OT_Union => + return Atype + 2; + when OT_Complete => + return Atype + 1; + end case; + end Get_Type_Next; + + function Get_Base_Type (Atype : O_Tnode) return O_Tnode + is + begin + case Get_Type_Kind (Atype) is + when OT_Subarray => + return Get_Type_Subarray_Base (Atype); + when others => + return Atype; + end case; + end Get_Base_Type; + + procedure Mark (M : out Mark_Type) is + begin + M.Tnode := Tnodes.Last; + M.Fnode := Fnodes.Last; + end Mark; + + procedure Release (M : Mark_Type) is + begin + Tnodes.Set_Last (M.Tnode); + Fnodes.Set_Last (M.Fnode); + end Release; + + procedure Disp_Stats + is + use Ada.Text_IO; + begin + Put_Line ("Number of Tnodes: " & O_Tnode'Image (Tnodes.Last)); + Put_Line ("Number of Fnodes: " & O_Fnode'Image (Fnodes.Last)); + end Disp_Stats; + + procedure Finish is + begin + Tnodes.Free; + Fnodes.Free; + end Finish; +end Ortho_Code.Types; diff --git a/src/ortho/mcode/ortho_code-types.ads b/src/ortho/mcode/ortho_code-types.ads new file mode 100644 index 000000000..da6549841 --- /dev/null +++ b/src/ortho/mcode/ortho_code-types.ads @@ -0,0 +1,240 @@ +-- Mcode back-end for ortho - type 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. +package Ortho_Code.Types is + type OT_Kind is (OT_Unsigned, OT_Signed, OT_Boolean, OT_Enum, OT_Float, + OT_Ucarray, OT_Subarray, OT_Access, + OT_Record, OT_Union, + + -- Type completion. Mark the completion of a type. + -- Optionnal. + OT_Complete); + + -- Kind of ATYPE. + function Get_Type_Kind (Atype : O_Tnode) return OT_Kind; + + -- Number of bytes of type ATYPE. + function Get_Type_Size (Atype : O_Tnode) return Uns32; + + -- Same as Get_Type_Size but for modes. + -- Returns 0 in case of error. + function Get_Mode_Size (Mode : Mode_Type) return Uns32; + + -- Alignment for ATYPE, in power of 2. + subtype Small_Natural is Natural range 0 .. 3; + type Mode_Align_Array is array (Mode_Type) of Small_Natural; + function Get_Type_Align (Atype : O_Tnode) return Small_Natural; + + -- Alignment for ATYPE in bytes. + function Get_Type_Align_Bytes (Atype : O_Tnode) return Uns32; + + -- Return true is the type was incomplete at creation. + -- (it may - or not - have been completed later). + function Get_Type_Deferred (Atype : O_Tnode) return Boolean; + + -- A back-end reserved flag. + -- Initialized to False. + function Get_Type_Flag1 (Atype : O_Tnode) return Boolean; + procedure Set_Type_Flag1 (Atype : O_Tnode; Flag : Boolean); + + -- Align OFF on ATYPE. + function Do_Align (Off : Uns32; Atype : O_Tnode) return Uns32; + function Do_Align (Off : Uns32; Mode : Mode_Type) return Uns32; + + -- Get the mode for ATYPE. + function Get_Type_Mode (Atype : O_Tnode) return Mode_Type; + + -- Get the type designated by access type ATYPE. + function Get_Type_Access_Type (Atype : O_Tnode) return O_Tnode; + + -- Get the index type of array type ATYPE. + function Get_Type_Ucarray_Index (Atype : O_Tnode) return O_Tnode; + + -- Get the element type of array type ATYPE. + function Get_Type_Ucarray_Element (Atype : O_Tnode) return O_Tnode; + + -- Get the base type of array type ATYPE. + function Get_Type_Subarray_Base (Atype : O_Tnode) return O_Tnode; + + -- Get number of element for array type ATYPE. + function Get_Type_Subarray_Length (Atype : O_Tnode) return Uns32; + + -- Get the first field of record/union ATYPE. + function Get_Type_Record_Fields (Atype : O_Tnode) return O_Fnode; + + -- Get the number of fields of record/union ATYPE. + function Get_Type_Record_Nbr_Fields (Atype : O_Tnode) return Uns32; + + -- Get the first literal of enum type ATYPE. + function Get_Type_Enum_Lits (Atype : O_Tnode) return O_Cnode; + + -- Get the POS th literal of enum type ATYPE. + -- The first is when POS = 0. + function Get_Type_Enum_Lit (Atype : O_Tnode; Pos : Uns32) return O_Cnode; + + -- Get the number of literals of enum type ATYPE. + function Get_Type_Enum_Nbr_Lits (Atype : O_Tnode) return Uns32; + + -- Get the false/true literal of boolean type ATYPE. + function Get_Type_Bool_False (Atype : O_Tnode) return O_Cnode; + function Get_Type_Bool_True (Atype : O_Tnode) return O_Cnode; + + -- Return the union/record type which contains FIELD. + function Get_Field_Parent (Field : O_Fnode) return O_Tnode; + + -- Get the offset of FIELD in its record/union. + function Get_Field_Offset (Field : O_Fnode) return Uns32; + procedure Set_Field_Offset (Field : O_Fnode; Offset : Uns32); + + -- Get the type of FIELD. + function Get_Field_Type (Field : O_Fnode) return O_Tnode; + + -- Get the name of FIELD. + function Get_Field_Ident (Field : O_Fnode) return O_Ident; + + -- Get the next field. + function Get_Field_Chain (Field : O_Fnode) return O_Fnode; + + -- Get the type that was completed. + function Get_Type_Complete_Type (Atype : O_Tnode) return O_Tnode; + + -- Build a scalar type; size may be 8, 16, 32 or 64. + function New_Unsigned_Type (Size : Natural) return O_Tnode; + function New_Signed_Type (Size : Natural) return O_Tnode; + + -- Build a float type. + function New_Float_Type return O_Tnode; + + -- Build a boolean type. + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode); + + -- Create an enumeration + type O_Enum_List is limited private; + + -- Elements are declared in order, the first is ordered from 0. + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural); + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; Res : out O_Cnode); + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode); + + + -- Build an access type. + -- DTYPE may be O_tnode_null in order to build an incomplete access type. + -- It is completed with finish_access_type. + function New_Access_Type (Dtype : O_Tnode) return O_Tnode; + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode); + + + -- Build an array type. + -- The array is not constrained and unidimensional. + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode; + + -- Build a constrained array type. + function New_Constrained_Array_Type (Atype : O_Tnode; Length : Uns32) + return O_Tnode; + + -- Return the base type of ATYPE: for a subarray this is the uc array, + -- otherwise this is the type. + function Get_Base_Type (Atype : O_Tnode) return O_Tnode; + + type O_Element_List is limited private; + + -- Build a record type. + procedure Start_Record_Type (Elements : out O_Element_List); + -- Add a field in the record; not constrained array are prohibited, since + -- its size is unlimited. + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode); + -- Finish the record type. + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an uncomplete record type: + -- First call NEW_UNCOMPLETE_RECORD_TYPE, which returns a record type. + -- This type can be declared or used to define access types on it. + -- Then, complete (if necessary) the record type, by calling + -- START_UNCOMPLETE_RECORD_TYPE, NEW_RECORD_FIELD and FINISH_RECORD_TYPE. + procedure New_Uncomplete_Record_Type (Res : out O_Tnode); + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List); + + -- Build an union type. + procedure Start_Union_Type (Elements : out O_Element_List); + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode); + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Non-primitives. + + -- Type of an element of a ucarray or constrained array. + function Get_Type_Array_Element (Atype : O_Tnode) return O_Tnode; + + -- Get a type number limit (an O_Tnode is a number). + -- There is no type whose number is beyond this limit. + -- Note: the limit may not be a type! + function Get_Type_Limit return O_Tnode; + + -- Get the type which follows ATYPE. + -- User has to check that the result is valid (ie not beyond limit). + function Get_Type_Next (Atype : O_Tnode) return O_Tnode; + + procedure Disp_Stats; + + -- Free all the memory used. + procedure Finish; + + type Mark_Type is limited private; + procedure Mark (M : out Mark_Type); + procedure Release (M : Mark_Type); + + procedure Debug_Type (Atype : O_Tnode); + procedure Debug_Field (Field : O_Fnode); +private + type O_Enum_List is record + Res : O_Tnode; + First : O_Cnode; + Last : O_Cnode; + Nbr : Uns32; + end record; + + type O_Element_List is record + Res : O_Tnode; + Nbr : Uns32; + Off : Uns32; + Align : Small_Natural; + First_Field : O_Fnode; + Last_Field : O_Fnode; + end record; + + type Mark_Type is record + Tnode : O_Tnode; + Fnode : O_Fnode; + end record; + +end Ortho_Code.Types; + diff --git a/src/ortho/mcode/ortho_code-x86-abi.adb b/src/ortho/mcode/ortho_code-x86-abi.adb new file mode 100644 index 000000000..bb06d51d4 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-abi.adb @@ -0,0 +1,762 @@ +-- X86 ABI definitions. +-- 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 Ortho_Code.Decls; use Ortho_Code.Decls; +with Ortho_Code.Exprs; use Ortho_Code.Exprs; +with Ortho_Code.Consts; +with Ortho_Code.Debug; +with Ortho_Code.Disps; +with Ortho_Code.Flags; +with Ortho_Code.Dwarf; +with Ortho_Code.X86; use Ortho_Code.X86; +with Ortho_Code.X86.Insns; +with Ortho_Code.X86.Emits; +with Ortho_Code.X86.Flags; +with Binary_File; +with Binary_File.Memory; +with Ada.Text_IO; + +package body Ortho_Code.X86.Abi is + procedure Start_Subprogram (Subprg : O_Dnode; Abi : out O_Abi_Subprg) + is + pragma Unreferenced (Subprg); + begin + -- First argument is at %ebp + 8 + Abi.Offset := 8; + end Start_Subprogram; + + procedure New_Interface (Inter : O_Dnode; Abi : in out O_Abi_Subprg) + is + Itype : O_Tnode; + Size : Uns32; + begin + Itype := Get_Decl_Type (Inter); + Size := Get_Type_Size (Itype); + Size := (Size + 3) and not 3; + Set_Local_Offset (Inter, Abi.Offset); + Abi.Offset := Abi.Offset + Int32 (Size); + end New_Interface; + + procedure Finish_Subprogram (Subprg : O_Dnode; Abi : in out O_Abi_Subprg) + is + use Binary_File; + function To_Int32 is new Ada.Unchecked_Conversion + (Source => Symbol, Target => Int32); + begin + Set_Decl_Info (Subprg, + To_Int32 (Create_Symbol (Get_Decl_Ident (Subprg)))); + -- Offset is 8 biased. + Set_Subprg_Stack (Subprg, Abi.Offset - 8); + end Finish_Subprogram; + + procedure Link_Stmt (Stmt : O_Enode) is + begin + Set_Stmt_Link (Last_Link, Stmt); + Last_Link := Stmt; + end Link_Stmt; + + procedure Disp_Subprg (Subprg : O_Dnode); + + + Exprs_Mark : Exprs.Mark_Type; + Decls_Mark : Decls.Mark_Type; + Consts_Mark : Consts.Mark_Type; + Types_Mark : Types.Mark_Type; + Dwarf_Mark : Dwarf.Mark_Type; + + procedure Start_Body (Subprg : O_Dnode) + is + pragma Unreferenced (Subprg); + begin + if not Debug.Flag_Debug_Keep then + Mark (Exprs_Mark); + Mark (Decls_Mark); + Consts.Mark (Consts_Mark); + Mark (Types_Mark); + end if; + end Start_Body; + + procedure Finish_Body (Subprg : Subprogram_Data_Acc) + is + use Ortho_Code.Flags; + + Child : Subprogram_Data_Acc; + begin + if Debug.Flag_Debug_Hli then + Disps.Disp_Subprg (Subprg); + return; + end if; + + Insns.Gen_Subprg_Insns (Subprg); + + if Ortho_Code.Debug.Flag_Debug_Body2 then + Disp_Subprg_Body (1, Subprg.E_Entry); + end if; + + if Ortho_Code.Debug.Flag_Debug_Code then + Disp_Subprg (Subprg.D_Body); + end if; + + Emits.Emit_Subprg (Subprg); + + if Get_Decl_Depth (Subprg.D_Decl) = O_Toplevel + and then Flag_Debug = Debug_Dwarf + then + Dwarf.Emit_Decls_Until (Subprg.D_Body); + if not Debug.Flag_Debug_Keep then + Dwarf.Mark (Dwarf_Mark); + end if; + end if; + + -- Recurse on nested subprograms. + Child := Subprg.First_Child; + while Child /= null loop + Finish_Body (Child); + Child := Child.Brother; + end loop; + + if Get_Decl_Depth (Subprg.D_Decl) = O_Toplevel then + if Flag_Debug = Debug_Dwarf then + Dwarf.Emit_Subprg (Subprg.D_Body); + end if; + + if not Debug.Flag_Debug_Keep then + Release (Exprs_Mark); + Release (Decls_Mark); + Consts.Release (Consts_Mark); + Release (Types_Mark); + Dwarf.Release (Dwarf_Mark); + end if; + end if; + end Finish_Body; + + procedure Expand_Const_Decl (Decl : O_Dnode) is + begin + Emits.Emit_Const_Decl (Decl); + end Expand_Const_Decl; + + procedure Expand_Var_Decl (Decl : O_Dnode) is + begin + Emits.Emit_Var_Decl (Decl); + end Expand_Var_Decl; + + procedure Expand_Const_Value (Decl : O_Dnode; Val : O_Cnode) is + begin + Emits.Emit_Const_Value (Decl, Val); + end Expand_Const_Value; + + procedure Disp_Label (Label : O_Enode) + is + use Ada.Text_IO; + use Ortho_Code.Debug.Int32_IO; + begin + Put ("L"); + Put (Int32 (Label), 0); + end Disp_Label; + + procedure Disp_Reg (Reg : O_Enode) + is + use Ada.Text_IO; + use Ortho_Code.Debug.Int32_IO; + begin + Put ("reg_"); + Put (Int32 (Reg), 0); + Put ("{"); + Put (Image_Reg (Get_Expr_Reg (Reg))); + Put ("}"); + end Disp_Reg; + + procedure Disp_Local (Stmt : O_Enode) + is + use Ada.Text_IO; + use Ortho_Code.Debug.Int32_IO; + Obj : constant O_Dnode := Get_Addr_Object (Stmt); + Frame : constant O_Enode := Get_Addrl_Frame (Stmt); + begin + if Frame = O_Enode_Null then + Put ("fp"); + else + Disp_Reg (Frame); + end if; + Put (","); + Put (Get_Local_Offset (Obj), 0); + Put (" {"); + Disp_Decl_Name (Obj); + Put ("}"); + end Disp_Local; + + procedure Disp_Uns32 (Val : Uns32) + is + use Ada.Text_IO; + U2c : constant array (Uns32 range 0 .. 15) of Character + := "0123456789abcdef"; + V : Uns32 := Val; + begin + for I in 0 .. 7 loop + Put (U2c (Shift_Right (V, 28))); + V := Shift_Left (V, 4); + end loop; + end Disp_Uns32; + + procedure Disp_Const (Stmt : O_Enode) + is + use Ada.Text_IO; + begin + Put ("["); + case Get_Expr_Mode (Stmt) is + when Mode_U64 + | Mode_I64 + | Mode_F64 => + Disp_Uns32 (Get_Expr_High (Stmt)); + Put (","); + when others => + null; + end case; + Disp_Uns32 (Get_Expr_Low (Stmt)); + Put ("]"); + end Disp_Const; + + procedure Disp_Irm_Code (Stmt : O_Enode) + is + use Ortho_Code.Debug.Int32_IO; + use Ada.Text_IO; + Reg : O_Reg; + Kind : OE_Kind; + begin + Reg := Get_Expr_Reg (Stmt); + Kind := Get_Expr_Kind (Stmt); + case Reg is + when R_Mem => + case Kind is + when OE_Indir => + Put ('('); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + Put (')'); +-- when OE_Lit => +-- Put ("(&n)"); + when others => + raise Program_Error; + end case; + when R_Imm => + case Kind is + when OE_Const => + Disp_Const (Stmt); + when OE_Addrg => + Put ("&"); + Disp_Decl_Name (Get_Addr_Object (Stmt)); + when OE_Add => + Disp_Irm_Code (Get_Expr_Left (Stmt)); + Put ("+"); + Disp_Irm_Code (Get_Expr_Right (Stmt)); + when others => + raise Program_Error; + end case; + when Regs_R32 + | R_Any32 + | R_Any8 + | Regs_R64 + | R_Any64 + | Regs_Cc + | Regs_Fp + | Regs_Xmm => + Disp_Reg (Stmt); + when R_Spill => + Disp_Reg (Stmt); + --Disp_Irm_Code (Get_Stmt_Link (Stmt)); + when R_B_Off + | R_I_Off + | R_B_I + | R_Sib => + case Kind is + when OE_Addrl => + Disp_Local (Stmt); + when OE_Add => + Disp_Irm_Code (Get_Expr_Left (Stmt)); + Put (" + "); + Disp_Irm_Code (Get_Expr_Right (Stmt)); + when others => + raise Program_Error; + end case; + when R_I => + Disp_Irm_Code (Get_Expr_Left (Stmt)); + Put (" * "); + case Get_Expr_Low (Get_Expr_Right (Stmt)) is + when 0 => + Put ('1'); + when 1 => + Put ('2'); + when 2 => + Put ('4'); + when 3 => + Put ('8'); + when others => + Put ('?'); + end case; + when others => + Ada.Text_IO.Put_Line + ("abi.disp_irm_code: unhandled reg=" & Image_Reg (Reg) + & ", stmt=" & O_Enode'Image (Stmt)); + raise Program_Error; + end case; + end Disp_Irm_Code; + + procedure Disp_Decls (Block : O_Dnode) + is + Decl : O_Dnode; + Last : O_Dnode; + begin + Last := Get_Block_Last (Block); + Disp_Decl (2, Block); + Decl := Block + 1; + while Decl <= Last loop + case Get_Decl_Kind (Decl) is + when OD_Local => + Disp_Decl (2, Decl); + when OD_Block => + -- Skip internal blocks. + Decl := Get_Block_Last (Decl); + when others => + Disp_Decl (2, Decl); + null; + end case; + Decl := Decl + 1; + end loop; + end Disp_Decls; + + procedure Disp_Stmt (Stmt : O_Enode) + is + use Ada.Text_IO; + use Debug.Int32_IO; + Kind : OE_Kind; + Mode : Mode_Type; + + procedure Disp_Op_Name (Name : String) is + begin + Put (Name); + Put (":"); + Debug.Disp_Mode (Mode); + Put (" "); + end Disp_Op_Name; + + procedure Disp_Reg_Op_Name (Name : String) is + begin + Put (" "); + Disp_Reg (Stmt); + Put (" = "); + Disp_Op_Name (Name); + end Disp_Reg_Op_Name; + + begin + Kind := Get_Expr_Kind (Stmt); + Mode := Get_Expr_Mode (Stmt); + + case Kind is + when OE_Beg => + Put (" # block start"); + if Get_Block_Has_Alloca (Stmt) then + Put (" [alloca]"); + end if; + New_Line; + Disp_Decls (Get_Block_Decls (Stmt)); + when OE_End => + Put_Line (" # block end"); + when OE_Indir => + Disp_Reg_Op_Name ("indir"); + Put ("("); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + Put_Line (")"); + when OE_Alloca => + Disp_Reg_Op_Name ("alloca"); + Put ("("); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + Put_Line (")"); + when OE_Kind_Cmp + | OE_Kind_Dyadic => + Disp_Reg_Op_Name ("op"); + Put ("{"); + Put (OE_Kind'Image (Kind)); + Put ("} "); + Disp_Irm_Code (Get_Expr_Left (Stmt)); + Put (", "); + Disp_Irm_Code (Get_Expr_Right (Stmt)); + New_Line; + when OE_Abs_Ov + | OE_Neg_Ov + | OE_Not => + Disp_Reg_Op_Name ("op"); + Put ("{"); + Put (OE_Kind'Image (Kind)); + Put ("} "); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Const => + Disp_Reg_Op_Name ("const"); + Disp_Const (Stmt); + New_Line; + when OE_Jump_F => + Put (" jump_f "); + Disp_Reg (Get_Expr_Operand (Stmt)); + Put (" "); + Disp_Label (Get_Jump_Label (Stmt)); + New_Line; + when OE_Jump_T => + Put (" jump_t "); + Disp_Reg (Get_Expr_Operand (Stmt)); + Put (" "); + Disp_Label (Get_Jump_Label (Stmt)); + New_Line; + when OE_Jump => + Put (" jump "); + Disp_Label (Get_Jump_Label (Stmt)); + New_Line; + when OE_Label => + Disp_Label (Stmt); + Put_Line (":"); + when OE_Asgn => + Put (" assign:"); + Debug.Disp_Mode (Mode); + Put (" ("); + Disp_Irm_Code (Get_Assign_Target (Stmt)); + Put (") <- "); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Set_Stack => + Put (" set_stack"); + Put (" <- "); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Spill => + Disp_Reg_Op_Name ("spill"); + Disp_Reg (Get_Expr_Operand (Stmt)); + Put (", offset="); + Put (Int32'Image (Get_Spill_Info (Stmt))); + New_Line; + when OE_Reload => + Disp_Reg_Op_Name ("reload"); + Disp_Reg (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Arg => + Put (" push "); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Call => + if Get_Expr_Mode (Stmt) /= Mode_Nil then + Disp_Reg_Op_Name ("call"); + else + Put (" "); + Disp_Op_Name ("call"); + Put (" "); + end if; + Disp_Decl_Name (Get_Call_Subprg (Stmt)); + New_Line; + when OE_Stack_Adjust => + Put (" stack_adjust: "); + Put (Int32'Image (Get_Stack_Adjust (Stmt))); + New_Line; + when OE_Intrinsic => + Disp_Reg_Op_Name ("intrinsic"); + --Disp_Decl_Name (Get_Call_Subprg (Stmt)); + New_Line; + when OE_Conv => + Disp_Reg_Op_Name ("conv"); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Move => + Disp_Reg_Op_Name ("move"); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Ret => + Put (" ret"); + if Get_Expr_Mode (Stmt) /= Mode_Nil then + Put (" "); + Disp_Reg (Get_Expr_Operand (Stmt)); + end if; + New_Line; + when OE_Case => + Disp_Reg_Op_Name ("case"); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Case_Expr => + Disp_Reg_Op_Name ("case_expr"); + Disp_Irm_Code (Get_Expr_Operand (Stmt)); + New_Line; + when OE_Leave => + Put_Line ("leave"); + when OE_Entry => + Put_Line ("entry"); + when OE_Line => + Put (" # line #"); + Put (Get_Expr_Line_Number (Stmt), 0); + New_Line; + when OE_Addrl => + Disp_Reg_Op_Name ("lea{addrl}"); + Put ("("); + Disp_Local (Stmt); + Put (")"); + New_Line; + when OE_Addrg => + Disp_Reg_Op_Name ("lea{addrg}"); + Put ("&"); + Disp_Decl_Name (Get_Addr_Object (Stmt)); + New_Line; + when OE_Add => + Disp_Reg_Op_Name ("lea{add}"); + Put ("("); + Disp_Irm_Code (Get_Expr_Left (Stmt)); + Put (" + "); + Disp_Irm_Code (Get_Expr_Right (Stmt)); + Put (")"); + New_Line; + when OE_Mul => + Disp_Reg_Op_Name ("mul"); + Disp_Irm_Code (Get_Expr_Left (Stmt)); + Put (", "); + Disp_Irm_Code (Get_Expr_Right (Stmt)); + New_Line; + when OE_Shl => + Disp_Reg_Op_Name ("shl"); + Disp_Irm_Code (Get_Expr_Left (Stmt)); + Put (", "); + Disp_Irm_Code (Get_Expr_Right (Stmt)); + New_Line; + when OE_Reg => + Disp_Reg_Op_Name ("reg"); + New_Line; + when others => + Ada.Text_IO.Put_Line + ("abi.disp_stmt: unhandled enode " & OE_Kind'Image (Kind)); + raise Program_Error; + end case; + end Disp_Stmt; + + procedure Disp_Subprg_Decl (Decl : O_Dnode) + is + use Ada.Text_IO; + Arg : O_Dnode; + begin + Put ("subprogram "); + Disp_Decl_Name (Decl); + Put_Line (":"); + Arg := Decl + 1; + while Get_Decl_Kind (Arg) = OD_Interface loop + Disp_Decl (2, Arg); + Arg := Arg + 1; + end loop; + end Disp_Subprg_Decl; + + procedure Disp_Subprg (Subprg : O_Dnode) + is + use Ada.Text_IO; + + Stmt : O_Enode; + begin + Disp_Subprg_Decl (Get_Body_Decl (Subprg)); + + Stmt := Get_Body_Stmt (Subprg); + loop + exit when Stmt = O_Enode_Null; + Disp_Stmt (Stmt); + exit when Get_Expr_Kind (Stmt) = OE_Leave; + Stmt := Get_Stmt_Link (Stmt); + end loop; + end Disp_Subprg; + + procedure New_Debug_Filename_Decl (Filename : String) + is + use Ortho_Code.Flags; + begin + if Flag_Debug = Debug_Dwarf then + Dwarf.Set_Filename ("", Filename); + end if; + end New_Debug_Filename_Decl; + + procedure Init + is + use Ortho_Code.Debug; + begin + -- Alignment of doubles is platform dependent. + Mode_Align (Mode_F64) := X86.Flags.Mode_F64_Align; + + if Flag_Debug_Hli then + Disps.Init; + else + Emits.Init; + end if; + end Init; + + procedure Finish + is + use Ortho_Code.Debug; + begin + if Flag_Debug_Hli then + Disps.Finish; + else + Emits.Finish; + end if; + end Finish; + +-- function Image_Insn (Insn : O_Insn) return String is +-- begin +-- case Insn is +-- when Insn_Nil => +-- return "nil"; +-- when Insn_Imm => +-- return "imm"; +-- when Insn_Base_Off => +-- return "B+O"; +-- when Insn_Loadm => +-- return "ldm"; +-- when Insn_Loadi => +-- return "ldi"; +-- when Insn_Mem => +-- return "mem"; +-- when Insn_Cmp => +-- return "cmp"; +-- when Insn_Op => +-- return "op "; +-- when Insn_Rop => +-- return "rop"; +-- when Insn_Call => +-- return "cal"; +-- when others => +-- return "???"; +-- end case; +-- end Image_Insn; + + function Image_Reg (Reg : O_Reg) return String is + begin + case Reg is + when R_Nil => + return "nil "; + when R_None => + return " -- "; + when R_Spill => + return "spil"; + when R_Mem => + return "mem "; + when R_Imm => + return "imm "; + when R_Irm => + return "irm "; + when R_Rm => + return "rm "; + when R_Sib => + return "sib "; + when R_B_Off => + return "b+o "; + when R_B_I => + return "b+i "; + when R_I => + return "s*i "; + when R_Ir => + return " ir "; + when R_I_Off => + return "i+o "; + when R_Any32 => + return "r32 "; + when R_Any_Cc => + return "cc "; + when R_Any8 => + return "r8 "; + when R_Any64 => + return "r64 "; + + when R_St0 => + return "st0 "; + when R_Ax => + return "ax "; + when R_Dx => + return "dx "; + when R_Cx => + return "cx "; + when R_Bx => + return "bx "; + when R_Si => + return "si "; + when R_Di => + return "di "; + when R_Sp => + return "sp "; + when R_Bp => + return "bp "; + when R_Edx_Eax => + return "dxax"; + when R_Ebx_Ecx => + return "bxcx"; + when R_Esi_Edi => + return "sidi"; + when R_Eq => + return "eq? "; + when R_Ne => + return "ne? "; + when R_Uge => + return "uge?"; + when R_Sge => + return "sge?"; + when R_Ugt => + return "ugt?"; + when R_Sgt => + return "sgt?"; + when R_Ule => + return "ule?"; + when R_Sle => + return "sle?"; + when R_Ult => + return "ult?"; + when R_Slt => + return "slt?"; + when R_Xmm0 => + return "xmm0"; + when R_Xmm1 => + return "xmm1"; + when R_Xmm2 => + return "xmm2"; + when R_Xmm3 => + return "xmm3"; + when others => + return "????"; + end case; + end Image_Reg; + + -- From GCC. + -- FIXME: these don't handle overflow! + function Divdi3 (A, B : Long_Integer) return Long_Integer; + pragma Import (C, Divdi3, "__divdi3"); + + function Muldi3 (A, B : Long_Integer) return Long_Integer; + pragma Import (C, Muldi3, "__muldi3"); + + procedure Chkstk (Sz : Integer); + pragma Import (C, Chkstk, "__chkstk"); + + procedure Link_Intrinsics + is + begin + Binary_File.Memory.Set_Symbol_Address + (Ortho_Code.X86.Emits.Intrinsics_Symbol + (Ortho_Code.X86.Intrinsic_Mul_Ov_I64), + Muldi3'Address); + Binary_File.Memory.Set_Symbol_Address + (Ortho_Code.X86.Emits.Intrinsics_Symbol + (Ortho_Code.X86.Intrinsic_Div_Ov_I64), + Divdi3'Address); + if X86.Flags.Flag_Alloca_Call then + Binary_File.Memory.Set_Symbol_Address + (Ortho_Code.X86.Emits.Chkstk_Symbol, Chkstk'Address); + end if; + end Link_Intrinsics; +end Ortho_Code.X86.Abi; diff --git a/src/ortho/mcode/ortho_code-x86-abi.ads b/src/ortho/mcode/ortho_code-x86-abi.ads new file mode 100644 index 000000000..7b166dad8 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-abi.ads @@ -0,0 +1,76 @@ +-- X86 ABI definitions. +-- 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 Ortho_Code.Types; use Ortho_Code.Types; + +package Ortho_Code.X86.Abi is + type O_Abi_Subprg is private; + + procedure Init; + procedure Finish; + + Mode_Align : Mode_Align_Array := + (Mode_U8 | Mode_I8 => 0, + Mode_U16 | Mode_I16 => 1, + Mode_U32 | Mode_I32 | Mode_F32 | Mode_P32 => 2, + Mode_U64 | Mode_I64 => 2, + Mode_F64 => 2, -- 2 for SVR4-ABI and Darwin, 3 for Windows. + Mode_Blk | Mode_X1 | Mode_Nil | Mode_P64 => 0, + Mode_B2 => 0); + + Mode_Ptr : constant Mode_Type := Mode_P32; + + Flag_Type_Completer : constant Boolean := False; + Flag_Lower_Stmt : constant Boolean := True; + + Flag_Sse2 : Boolean := False; + + -- Procedures to layout a subprogram declaration. + procedure Start_Subprogram (Subprg : O_Dnode; Abi : out O_Abi_Subprg); + procedure New_Interface (Inter : O_Dnode; Abi : in out O_Abi_Subprg); + procedure Finish_Subprogram (Subprg : O_Dnode; Abi : in out O_Abi_Subprg); + + -- Only called for top-level subprograms. + procedure Start_Body (Subprg : O_Dnode); + -- Finish compilation of a body. + procedure Finish_Body (Subprg : Subprogram_Data_Acc); + + procedure Expand_Const_Decl (Decl : O_Dnode); + procedure Expand_Var_Decl (Decl : O_Dnode); + procedure Expand_Const_Value (Decl : O_Dnode; Val : O_Cnode); + + procedure New_Debug_Filename_Decl (Filename : String); + + Last_Link : O_Enode; + procedure Link_Stmt (Stmt : O_Enode); + + -- Disp SUBPRG (subprg declaration) as a declaration (name and interfaces). + procedure Disp_Subprg_Decl (Decl : O_Dnode); + + procedure Disp_Stmt (Stmt : O_Enode); + + --function Image_Insn (Insn : O_Insn) return String; + function Image_Reg (Reg : O_Reg) return String; + + -- Link in memory intrinsics symbols. + procedure Link_Intrinsics; +private + type O_Abi_Subprg is record + -- For x86: offset of the next argument. + Offset : Int32 := 0; + end record; +end Ortho_Code.X86.Abi; diff --git a/src/ortho/mcode/ortho_code-x86-emits.adb b/src/ortho/mcode/ortho_code-x86-emits.adb new file mode 100644 index 000000000..ad1ef559b --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-emits.adb @@ -0,0 +1,2322 @@ +-- Mcode back-end for ortho - Binary X86 instructions generator. +-- 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 Ortho_Code.Abi; +with Ortho_Code.Decls; +with Ortho_Code.Types; +with Ortho_Code.Consts; +with Ortho_Code.Debug; +with Ortho_Code.X86.Insns; +with Ortho_Code.X86.Flags; +with Ortho_Code.Flags; +with Ortho_Code.Dwarf; +with Ortho_Code.Binary; use Ortho_Code.Binary; +with Ortho_Ident; +with Ada.Text_IO; +with Interfaces; use Interfaces; + +package body Ortho_Code.X86.Emits is + type Insn_Size is (Sz_8, Sz_16, Sz_32l, Sz_32h); + + type Fp_Size is (Fp_32, Fp_64); + + Sect_Text : Binary_File.Section_Acc; + Sect_Rodata : Binary_File.Section_Acc; + Sect_Bss : Binary_File.Section_Acc; + + Reg_Helper : O_Reg; + + Subprg_Pc : Pc_Type; + + procedure Error_Emit (Msg : String; Insn : O_Enode) + is + use Ada.Text_IO; + begin + Put ("error_emit: "); + Put (Msg); + Put (", insn="); + Put (O_Enode'Image (Insn)); + Put (" ("); + Put (OE_Kind'Image (Get_Expr_Kind (Insn))); + Put (")"); + New_Line; + raise Program_Error; + end Error_Emit; + + + procedure Gen_Insn_Sz (B : Byte; Sz : Insn_Size) is + begin + case Sz is + when Sz_8 => + Gen_B8 (B); + when Sz_16 => + Gen_B8 (16#66#); + Gen_B8 (B + 1); + when Sz_32l + | Sz_32h => + Gen_B8 (B + 1); + end case; + end Gen_Insn_Sz; + + procedure Gen_Insn_Sz_S8 (B : Byte; Sz : Insn_Size) is + begin + case Sz is + when Sz_8 => + Gen_B8 (B); + when Sz_16 => + Gen_B8 (16#66#); + Gen_B8 (B + 3); + when Sz_32l + | Sz_32h => + Gen_B8 (B + 3); + end case; + end Gen_Insn_Sz_S8; + + function Get_Const_Val (C : O_Enode; Sz : Insn_Size) return Uns32 is + begin + case Sz is + when Sz_8 + | Sz_16 + | Sz_32l => + return Get_Expr_Low (C); + when Sz_32h => + return Get_Expr_High (C); + end case; + end Get_Const_Val; + + function Is_Imm8 (N : O_Enode; Sz : Insn_Size) return Boolean is + begin + if Get_Expr_Kind (N) /= OE_Const then + return False; + end if; + return Get_Const_Val (N, Sz) <= 127; + end Is_Imm8; + + procedure Gen_Imm8 (N : O_Enode; Sz : Insn_Size) is + begin + Gen_B8 (Byte (Get_Const_Val (N, Sz))); + end Gen_Imm8; + +-- procedure Gen_Imm32 (N : O_Enode; Sz : Insn_Size) +-- is +-- use Interfaces; +-- begin +-- case Get_Expr_Kind (N) is +-- when OE_Const => +-- Gen_Le32 (Unsigned_32 (Get_Const_Val (N, Sz))); +-- when OE_Addrg => +-- Gen_X86_32 (Get_Decl_Symbol (Get_Addr_Object (N)), 0); +-- when others => +-- raise Program_Error; +-- end case; +-- end Gen_Imm32; + + procedure Gen_Imm (N : O_Enode; Sz : Insn_Size) is + begin + case Get_Expr_Kind (N) is + when OE_Const => + case Sz is + when Sz_8 => + Gen_B8 (Byte (Get_Expr_Low (N) and 16#FF#)); + when Sz_16 => + Gen_Le16 (Unsigned_32 (Get_Expr_Low (N) and 16#FF_FF#)); + when Sz_32l => + Gen_Le32 (Unsigned_32 (Get_Expr_Low (N))); + when Sz_32h => + Gen_Le32 (Unsigned_32 (Get_Expr_High (N))); + end case; + when OE_Addrg => + if Sz /= Sz_32l then + raise Program_Error; + end if; + Gen_X86_32 (Get_Decl_Symbol (Get_Addr_Object (N)), 0); + when OE_Add => + declare + P : O_Enode; + L, R : O_Enode; + S, C : O_Enode; + Off : Int32; + begin + Off := 0; + P := N; + if Sz /= Sz_32l then + raise Program_Error; + end if; + loop + L := Get_Expr_Left (P); + R := Get_Expr_Right (P); + + -- Extract the const node. + if Get_Expr_Kind (R) = OE_Const then + S := L; + C := R; + elsif Get_Expr_Kind (L) = OE_Const then + S := R; + C := L; + else + raise Program_Error; + end if; + if Get_Expr_Mode (C) /= Mode_U32 then + raise Program_Error; + end if; + Off := Off + To_Int32 (Get_Expr_Low (C)); + + exit when Get_Expr_Kind (S) = OE_Addrg; + P := S; + if Get_Expr_Kind (P) /= OE_Add then + raise Program_Error; + end if; + end loop; + Gen_X86_32 (Get_Decl_Symbol (Get_Addr_Object (S)), + Integer_32 (Off)); + end; + when others => + raise Program_Error; + end case; + end Gen_Imm; + + Rm_Base : O_Reg; + Rm_Index : O_Reg; + Rm_Offset : Int32; + Rm_Sym : Symbol; + Rm_Scale : Byte; + + procedure Fill_Sib (N : O_Enode) + is + use Ortho_Code.Decls; + Reg : O_Reg; + begin + Reg := Get_Expr_Reg (N); + if Reg in Regs_R32 then + if Rm_Base = R_Nil then + Rm_Base := Reg; + elsif Rm_Index = R_Nil then + Rm_Index := Reg; + else + raise Program_Error; + end if; + return; + end if; + case Get_Expr_Kind (N) is + when OE_Indir => + Fill_Sib (Get_Expr_Operand (N)); + when OE_Addrl => + declare + Frame : O_Enode; + begin + Frame := Get_Addrl_Frame (N); + if Frame = O_Enode_Null then + Rm_Base := R_Bp; + else + Rm_Base := Get_Expr_Reg (Frame); + end if; + end; + Rm_Offset := Rm_Offset + Get_Local_Offset (Get_Addr_Object (N)); + when OE_Addrg => + if Rm_Sym /= Null_Symbol then + raise Program_Error; + end if; + Rm_Sym := Get_Decl_Symbol (Get_Addr_Object (N)); + when OE_Add => + Fill_Sib (Get_Expr_Left (N)); + Fill_Sib (Get_Expr_Right (N)); + when OE_Const => + Rm_Offset := Rm_Offset + To_Int32 (Get_Expr_Low (N)); + when OE_Shl => + if Rm_Index /= R_Nil then + raise Program_Error; + end if; + Rm_Index := Get_Expr_Reg (Get_Expr_Left (N)); + Rm_Scale := Byte (Get_Expr_Low (Get_Expr_Right (N))); + when others => + Error_Emit ("fill_sib", N); + end case; + end Fill_Sib; + + function To_Reg32 (R : O_Reg) return Byte is + begin + return O_Reg'Pos (R) - O_Reg'Pos (R_Ax); + end To_Reg32; + pragma Inline (To_Reg32); + + function To_Reg_Xmm (R : O_Reg) return Byte is + begin + return O_Reg'Pos (R) - O_Reg'Pos (R_Xmm0); + end To_Reg_Xmm; + pragma Inline (To_Reg_Xmm); + + function To_Reg32 (R : O_Reg; Sz : Insn_Size) return Byte is + begin + case Sz is + when Sz_8 => + if R in Regs_R8 then + return O_Reg'Pos (R) - O_Reg'Pos (R_Ax); + else + raise Program_Error; + end if; + when Sz_16 => + if R in Regs_R32 then + return O_Reg'Pos (R) - O_Reg'Pos (R_Ax); + else + raise Program_Error; + end if; + when Sz_32l => + case R is + when Regs_R32 => + return O_Reg'Pos (R) - O_Reg'Pos (R_Ax); + when R_Edx_Eax => + return 2#000#; + when R_Ebx_Ecx => + return 2#001#; + when R_Esi_Edi => + return 2#111#; + when others => + raise Program_Error; + end case; + when Sz_32h => + case R is + when R_Edx_Eax => + return 2#010#; + when R_Ebx_Ecx => + return 2#011#; + when R_Esi_Edi => + return 2#110#; + when others => + raise Program_Error; + end case; + end case; + end To_Reg32; + + function To_Cond (R : O_Reg) return Byte is + begin + return O_Reg'Pos (R) - O_Reg'Pos (R_Ov); + end To_Cond; + pragma Inline (To_Cond); + + procedure Gen_Sib is + begin + if Rm_Base = R_Nil then + Gen_B8 (Rm_Scale * 2#1_000_000# + + To_Reg32 (Rm_Index) * 2#1_000# + + 2#101#); + else + Gen_B8 (Rm_Scale * 2#1_000_000# + + To_Reg32 (Rm_Index) * 2#1_000# + + To_Reg32 (Rm_Base)); + end if; + end Gen_Sib; + + -- Generate an R/M (+ SIB) byte. + -- R is added to the R/M byte. + procedure Gen_Rm_Mem (R : Byte; N : O_Enode; Sz : Insn_Size) + is + Reg : O_Reg; + begin + Reg := Get_Expr_Reg (N); + Rm_Base := R_Nil; + Rm_Index := R_Nil; + if Sz = Sz_32h then + Rm_Offset := 4; + else + Rm_Offset := 0; + end if; + Rm_Scale := 0; + Rm_Sym := Null_Symbol; + case Reg is + when R_Mem + | R_Imm + | R_Eq + | R_B_Off + | R_B_I + | R_I_Off + | R_Sib => + Fill_Sib (N); + when Regs_R32 => + Rm_Base := Reg; + when R_Spill => + Rm_Base := R_Bp; + Rm_Offset := Rm_Offset + Get_Spill_Info (N); + when others => + Error_Emit ("gen_rm_mem: unhandled reg", N); + end case; + if Rm_Index /= R_Nil then + -- SIB. + if Rm_Base = R_Nil then + Gen_B8 (2#00_000_100# + R); + Rm_Base := R_Bp; + Gen_Sib; + Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset)); + elsif Rm_Sym = Null_Symbol and Rm_Offset = 0 and Rm_Base /= R_Bp then + Gen_B8 (2#00_000_100# + R); + Gen_Sib; + elsif Rm_Sym = Null_Symbol and Rm_Offset <= 127 and Rm_Offset >= -128 + then + Gen_B8 (2#01_000_100# + R); + Gen_Sib; + Gen_B8 (Byte (To_Uns32 (Rm_Offset) and 16#Ff#)); + else + Gen_B8 (2#10_000_100# + R); + Gen_Sib; + Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset)); + end if; + return; + end if; + case Rm_Base is + when R_Sp => + raise Program_Error; + when R_Nil => + Gen_B8 (2#00_000_101# + R); + Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset)); + when R_Ax + | R_Bx + | R_Cx + | R_Dx + | R_Bp + | R_Si + | R_Di => + if Rm_Offset = 0 and Rm_Sym = Null_Symbol and Rm_Base /= R_Bp then + Gen_B8 (2#00_000_000# + R + To_Reg32 (Rm_Base)); + elsif Rm_Sym = Null_Symbol + and Rm_Offset <= 127 and Rm_Offset >= -128 + then + Gen_B8 (2#01_000_000# + R + To_Reg32 (Rm_Base)); + Gen_B8 (Byte (To_Uns32 (Rm_Offset) and 16#Ff#)); + else + Gen_B8 (2#10_000_000# + R + To_Reg32 (Rm_Base)); + Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset)); + end if; + when others => + raise Program_Error; + end case; + end Gen_Rm_Mem; + + procedure Gen_Rm (R : Byte; N : O_Enode; Sz : Insn_Size) + is + Reg : O_Reg; + begin + Reg := Get_Expr_Reg (N); + if Reg in Regs_R32 or Reg in Regs_R64 then + Gen_B8 (2#11_000_000# + R + To_Reg32 (Reg, Sz)); + return; + else + Gen_Rm_Mem (R, N, Sz); + end if; + end Gen_Rm; + + procedure Emit_Op (Op : Byte; Stmt : O_Enode; Sz : Insn_Size) + is + L, R : O_Enode; + Lr, Rr : O_Reg; + begin + L := Get_Expr_Left (Stmt); + R := Get_Expr_Right (Stmt); + Lr := Get_Expr_Reg (L); + Rr := Get_Expr_Reg (R); + Start_Insn; + case Rr is + when R_Imm => + if Is_Imm8 (R, Sz) then + Gen_Insn_Sz_S8 (16#80#, Sz); + Gen_Rm (Op, L, Sz); + Gen_Imm8 (R, Sz); + elsif Lr = R_Ax then + Gen_Insn_Sz (2#000_000_100# + Op, Sz); + Gen_Imm (R, Sz); + else + Gen_Insn_Sz (16#80#, Sz); + Gen_Rm (Op, L, Sz); + Gen_Imm (R, Sz); + end if; + when R_Mem + | R_Spill + | Regs_R32 + | Regs_R64 => + Gen_Insn_Sz (2#00_000_010# + Op, Sz); + Gen_Rm (To_Reg32 (Lr, Sz) * 8, R, Sz); + when others => + Error_Emit ("emit_op", Stmt); + end case; + End_Insn; + end Emit_Op; + + procedure Gen_Into is + begin + Start_Insn; + Gen_B8 (2#1100_1110#); + End_Insn; + end Gen_Into; + + procedure Gen_Cdq is + begin + Start_Insn; + Gen_B8 (2#1001_1001#); + End_Insn; + end Gen_Cdq; + + procedure Gen_Mono_Op (Op : Byte; Val : O_Enode; Sz : Insn_Size) is + begin + Start_Insn; + Gen_Insn_Sz (2#1111_011_0#, Sz); + Gen_Rm (Op, Val, Sz); + End_Insn; + end Gen_Mono_Op; + + procedure Emit_Mono_Op_Stmt (Op : Byte; Stmt : O_Enode; Sz : Insn_Size) + is + begin + Gen_Mono_Op (Op, Get_Expr_Operand (Stmt), Sz); + end Emit_Mono_Op_Stmt; + + procedure Emit_Load_Imm (Stmt : O_Enode; Sz : Insn_Size) + is + Tr : O_Reg; + begin + Tr := Get_Expr_Reg (Stmt); + Start_Insn; + -- FIXME: handle 0. + case Sz is + when Sz_8 => + Gen_B8 (2#1011_0_000# + To_Reg32 (Tr, Sz)); + when Sz_16 => + Gen_B8 (16#66#); + Gen_B8 (2#1011_1_000# + To_Reg32 (Tr, Sz)); + when Sz_32l + | Sz_32h => + Gen_B8 (2#1011_1_000# + To_Reg32 (Tr, Sz)); + end case; + Gen_Imm (Stmt, Sz); + End_Insn; + end Emit_Load_Imm; + + function Fp_Size_To_Mf (Sz : Fp_Size) return Byte is + begin + case Sz is + when Fp_32 => + return 2#00_0#; + when Fp_64 => + return 2#10_0#; + end case; + end Fp_Size_To_Mf; + + procedure Emit_Load_Fp (Stmt : O_Enode; Sz : Fp_Size) + is + Sym : Symbol; + R : O_Reg; + begin + Set_Current_Section (Sect_Rodata); + Gen_Pow_Align (3); + Prealloc (8); + Sym := Create_Local_Symbol; + Set_Symbol_Pc (Sym, False); + Gen_Le32 (Unsigned_32 (Get_Expr_Low (Stmt))); + if Sz = Fp_64 then + Gen_Le32 (Unsigned_32 (Get_Expr_High (Stmt))); + end if; + Set_Current_Section (Sect_Text); + + R := Get_Expr_Reg (Stmt); + case R is + when R_St0 => + Start_Insn; + Gen_B8 (2#11011_001# + Fp_Size_To_Mf (Sz)); + Gen_B8 (2#00_000_101#); + Gen_X86_32 (Sym, 0); + End_Insn; + when Regs_Xmm => + Start_Insn; + case Sz is + when Fp_32 => + Gen_B8 (16#F3#); + when Fp_64 => + Gen_B8 (16#F2#); + end case; + Gen_B8 (16#0f#); + Gen_B8 (16#10#); + Gen_B8 (2#00_000_101# + To_Reg_Xmm (R) * 2#1_000#); + Gen_X86_32 (Sym, 0); + End_Insn; + when others => + raise Program_Error; + end case; + end Emit_Load_Fp; + + procedure Emit_Load_Fp_Mem (Stmt : O_Enode; Sz : Fp_Size) + is + begin + Start_Insn; + Gen_B8 (2#11011_001# + Fp_Size_To_Mf (Sz)); + Gen_Rm_Mem (2#000_000#, Get_Expr_Operand (Stmt), Sz_32l); + End_Insn; + end Emit_Load_Fp_Mem; + + procedure Emit_Load_Mem (Stmt : O_Enode; Sz : Insn_Size) + is + Tr : O_Reg; + Val : O_Enode; + begin + Tr := Get_Expr_Reg (Stmt); + Val := Get_Expr_Operand (Stmt); + case Tr is + when Regs_R32 + | Regs_R64 => + -- mov REG, OP + Start_Insn; + Gen_Insn_Sz (2#1000_101_0#, Sz); + Gen_Rm_Mem (To_Reg32 (Tr, Sz) * 8, Val, Sz); + End_Insn; + when R_Eq => + -- Cmp OP, 1 + Start_Insn; + Gen_Insn_Sz_S8 (2#1000_000_0#, Sz); + Gen_Rm_Mem (2#111_000#, Val, Sz); + Gen_B8 (1); + End_Insn; + when others => + Error_Emit ("emit_load_mem", Stmt); + end case; + end Emit_Load_Mem; + + + procedure Emit_Store (Stmt : O_Enode; Sz : Insn_Size) + is + T, R : O_Enode; + Tr, Rr : O_Reg; + B : Byte; + begin + T := Get_Assign_Target (Stmt); + R := Get_Expr_Operand (Stmt); + Tr := Get_Expr_Reg (T); + Rr := Get_Expr_Reg (R); + Start_Insn; + case Rr is + when R_Imm => + if False and (Tr in Regs_R32 or Tr in Regs_R64) then + B := 2#1011_1_000#; + case Sz is + when Sz_8 => + B := B and not 2#0000_1_000#; + when Sz_16 => + Gen_B8 (16#66#); + when Sz_32l + | Sz_32h => + null; + end case; + Gen_B8 (B + To_Reg32 (Tr, Sz)); + else + Gen_Insn_Sz (2#1100_011_0#, Sz); + Gen_Rm_Mem (16#00#, T, Sz); + end if; + Gen_Imm (R, Sz); + when Regs_R32 + | Regs_R64 => + Gen_Insn_Sz (2#1000_100_0#, Sz); + Gen_Rm_Mem (To_Reg32 (Rr, Sz) * 8, T, Sz); + when others => + Error_Emit ("emit_store", Stmt); + end case; + End_Insn; + end Emit_Store; + + procedure Emit_Store_Fp (Stmt : O_Enode; Sz : Fp_Size) + is + begin + -- fstp + Start_Insn; + Gen_B8 (2#11011_00_1# + Fp_Size_To_Mf (Sz)); + Gen_Rm_Mem (2#011_000#, Get_Assign_Target (Stmt), Sz_32l); + End_Insn; + end Emit_Store_Fp; + + procedure Emit_Push_32 (Val : O_Enode; Sz : Insn_Size) + is + R : O_Reg; + begin + R := Get_Expr_Reg (Val); + Start_Insn; + case R is + when R_Imm => + if Is_Imm8 (Val, Sz) then + Gen_B8 (2#0110_1010#); + Gen_Imm8 (Val, Sz); + else + Gen_B8 (2#0110_1000#); + Gen_Imm (Val, Sz); + end if; + when Regs_R32 + | Regs_R64 => + Gen_B8 (2#01010_000# + To_Reg32 (R, Sz)); + when others => + Gen_B8 (2#1111_1111#); + Gen_Rm (2#110_000#, Val, Sz); + end case; + End_Insn; + end Emit_Push_32; + + procedure Emit_Pop_32 (Val : O_Enode; Sz : Insn_Size) + is + R : O_Reg; + begin + R := Get_Expr_Reg (Val); + Start_Insn; + case R is + when Regs_R32 + | Regs_R64 => + Gen_B8 (2#01011_000# + To_Reg32 (R, Sz)); + when others => + Gen_B8 (2#1000_1111#); + Gen_Rm (2#000_000#, Val, Sz); + end case; + End_Insn; + end Emit_Pop_32; + + procedure Emit_Push_Fp (Op : O_Enode; Sz : Fp_Size) + is + pragma Unreferenced (Op); + begin + Start_Insn; + -- subl esp, val + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_101_100#); + case Sz is + when Fp_32 => + Gen_B8 (4); + when Fp_64 => + Gen_B8 (8); + end case; + End_Insn; + -- fstp st, (esp) + Start_Insn; + Gen_B8 (2#11011_001# + Fp_Size_To_Mf (Sz)); + Gen_B8 (2#00_011_100#); + Gen_B8 (2#00_100_100#); + End_Insn; + end Emit_Push_Fp; + + function Prepare_Label (Label : O_Enode) return Symbol + is + Sym : Symbol; + begin + Sym := Get_Label_Symbol (Label); + if Sym = Null_Symbol then + Sym := Create_Local_Symbol; + Set_Label_Symbol (Label, Sym); + end if; + return Sym; + end Prepare_Label; + + procedure Emit_Jmp_T (Stmt : O_Enode; Reg : O_Reg) + is + Sym : Symbol; + Val : Pc_Type; + Opc : Byte; + begin + Sym := Prepare_Label (Get_Jump_Label (Stmt)); + Val := Get_Symbol_Value (Sym); + Start_Insn; + Opc := To_Cond (Reg); + if Val = 0 then + -- Assume long jmp. + Gen_B8 (16#0f#); + Gen_B8 (16#80# + Opc); + Gen_X86_Pc32 (Sym); + else + if Val + 128 < Get_Current_Pc + 4 then + -- Long jmp. + Gen_B8 (16#0f#); + Gen_B8 (16#80# + Opc); + Gen_Le32 (Unsigned_32 (Val - (Get_Current_Pc + 4))); + else + -- short jmp. + Gen_B8 (16#70# + Opc); + Gen_B8 (Byte (Val - (Get_Current_Pc + 1))); + end if; + end if; + End_Insn; + end Emit_Jmp_T; + + procedure Emit_Jmp (Stmt : O_Enode) + is + Sym : Symbol; + Val : Pc_Type; + begin + Sym := Prepare_Label (Get_Jump_Label (Stmt)); + Val := Get_Symbol_Value (Sym); + Start_Insn; + if Val = 0 then + -- Assume long jmp. + Gen_B8 (16#e9#); + Gen_X86_Pc32 (Sym); + else + if Val + 128 < Get_Current_Pc + 4 then + -- Long jmp. + Gen_B8 (16#e9#); + Gen_Le32 (Unsigned_32 (Val - (Get_Current_Pc + 4))); + else + -- short jmp. + Gen_B8 (16#eb#); + Gen_B8 (Byte ((Val - (Get_Current_Pc + 1)) and 16#Ff#)); + end if; + end if; + End_Insn; + end Emit_Jmp; + + procedure Emit_Label (Stmt : O_Enode) + is + Sym : Symbol; + begin + Sym := Prepare_Label (Stmt); + Set_Symbol_Pc (Sym, False); + end Emit_Label; + + procedure Gen_Call (Sym : Symbol) is + begin + Start_Insn; + Gen_B8 (16#E8#); + Gen_X86_Pc32 (Sym); + End_Insn; + end Gen_Call; + + procedure Emit_Setup_Frame (Stmt : O_Enode) + is + Val : constant Int32 := Get_Stack_Adjust (Stmt); + begin + if Val > 0 then + Start_Insn; + -- subl esp, val + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_101_100#); + Gen_B8 (Byte (Val)); + End_Insn; + elsif Val < 0 then + Start_Insn; + if -Val <= 127 then + -- addl esp, val + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_000_100#); + Gen_B8 (Byte (-Val)); + else + -- addl esp, val + Gen_B8 (2#100000_01#); + Gen_B8 (2#11_000_100#); + Gen_Le32 (Unsigned_32 (-Val)); + end if; + End_Insn; + end if; + end Emit_Setup_Frame; + + procedure Emit_Call (Stmt : O_Enode) + is + use Ortho_Code.Decls; + Subprg : O_Dnode; + Sym : Symbol; + begin + Subprg := Get_Call_Subprg (Stmt); + Sym := Get_Decl_Symbol (Subprg); + Gen_Call (Sym); + end Emit_Call; + + procedure Emit_Intrinsic (Stmt : O_Enode) + is + Op : Int32; + begin + Op := Get_Intrinsic_Operation (Stmt); + Start_Insn; + Gen_B8 (16#E8#); + Gen_X86_Pc32 (Intrinsics_Symbol (Op)); + End_Insn; + + Start_Insn; + -- addl esp, val + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_000_100#); + Gen_B8 (16); + End_Insn; + end Emit_Intrinsic; + + procedure Emit_Setcc (Dest : O_Enode; Cond : O_Reg) + is + begin + if Cond not in Regs_Cc then + raise Program_Error; + end if; + Start_Insn; + Gen_B8 (16#0f#); + Gen_B8 (16#90# + To_Cond (Cond)); + Gen_Rm (2#000_000#, Dest, Sz_8); + End_Insn; + end Emit_Setcc; + + procedure Emit_Setcc_Reg (Reg : O_Reg; Cond : O_Reg) + is + begin + if Cond not in Regs_Cc then + raise Program_Error; + end if; + Start_Insn; + Gen_B8 (16#0f#); + Gen_B8 (16#90# + To_Cond (Cond)); + Gen_B8 (2#11_000_000# + To_Reg32 (Reg, Sz_8)); + End_Insn; + end Emit_Setcc_Reg; + + procedure Emit_Tst (Reg : O_Reg; Sz : Insn_Size) + is + begin + Start_Insn; + Gen_Insn_Sz (2#1000_0100#, Sz); + Gen_B8 (2#11_000_000# + To_Reg32 (Reg, Sz) * 9); + End_Insn; + end Emit_Tst; + + procedure Gen_Cmp_Imm (Reg : O_Reg; Val : Int32; Sz : Insn_Size) + is + B : Byte; + begin + Start_Insn; + if Val <= 127 and Val >= -128 then + B := 2#10#; + else + B := 0; + end if; + Gen_Insn_Sz (2#1000_0000# + B, Sz); + Gen_B8 (2#11_111_000# + To_Reg32 (Reg)); + if B = 0 then + Gen_Le32 (Unsigned_32 (To_Uns32 (Val))); + else + Gen_B8 (Byte (To_Uns32 (Val) and 16#Ff#)); + end if; + End_Insn; + end Gen_Cmp_Imm; + + procedure Emit_Spill (Stmt : O_Enode; Sz : Insn_Size) + is + Reg : O_Reg; + Expr : O_Enode; + begin + Expr := Get_Expr_Operand (Stmt); + Reg := Get_Expr_Reg (Expr); + if Reg = R_Spill then + if Get_Expr_Kind (Expr) = OE_Conv then + return; + else + raise Program_Error; + end if; + end if; + Start_Insn; + Gen_Insn_Sz (2#1000_1000#, Sz); + Gen_Rm (To_Reg32 (Reg, Sz) * 8, Stmt, Sz); + End_Insn; + end Emit_Spill; + + procedure Emit_Load (Reg : O_Reg; Val : O_Enode; Sz : Insn_Size) + is + begin + Start_Insn; + Gen_Insn_Sz (2#1000_1010#, Sz); + Gen_Rm (To_Reg32 (Reg, Sz) * 8, Val, Sz); + End_Insn; + end Emit_Load; + + procedure Emit_Lea (Stmt : O_Enode) + is + Reg : O_Reg; + begin + -- Hack: change the register to use the real address instead of it. + Reg := Get_Expr_Reg (Stmt); + Set_Expr_Reg (Stmt, R_Mem); + + Start_Insn; + Gen_B8 (2#10001101#); + Gen_Rm_Mem (To_Reg32 (Reg) * 8, Stmt, Sz_32l); + End_Insn; + Set_Expr_Reg (Stmt, Reg); + end Emit_Lea; + + procedure Gen_Umul (Stmt : O_Enode; Sz : Insn_Size) + is + begin + if Get_Expr_Reg (Get_Expr_Left (Stmt)) /= R_Ax then + raise Program_Error; + end if; + Start_Insn; + Gen_Insn_Sz (16#F6#, Sz); + Gen_Rm (2#100_000#, Get_Expr_Right (Stmt), Sz); + End_Insn; + end Gen_Umul; + + procedure Gen_Mul (Stmt : O_Enode; Sz : Insn_Size) + is + Reg : O_Reg; + Right : O_Enode; + Reg_R : O_Reg; + begin + Reg := Get_Expr_Reg (Stmt); + Right := Get_Expr_Right (Stmt); + if Get_Expr_Reg (Get_Expr_Left (Stmt)) /= Reg + or Sz /= Sz_32l + then + raise Program_Error; + end if; + Start_Insn; + if Reg = R_Ax then + Gen_Insn_Sz (16#F6#, Sz); + Gen_Rm (2#100_000#, Right, Sz); + else + Reg_R := Get_Expr_Reg (Right); + case Reg_R is + when R_Imm => + if Is_Imm8 (Right, Sz) then + Gen_B8 (16#6B#); + Gen_B8 (To_Reg32 (Reg, Sz) * 9 or 2#11_000_000#); + Gen_Imm8 (Right, Sz); + else + Gen_B8 (16#69#); + Gen_B8 (To_Reg32 (Reg, Sz) * 9 or 2#11_000_000#); + Gen_Imm (Right, Sz); + end if; + when R_Mem + | R_Spill + | Regs_R32 => + Gen_B8 (16#0F#); + Gen_B8 (16#AF#); + Gen_Rm (To_Reg32 (Reg, Sz) * 8, Right, Sz); + when others => + Error_Emit ("gen_mul", Stmt); + end case; + end if; + End_Insn; + end Gen_Mul; + + -- Do not trap if COND is true. + procedure Gen_Ov_Check (Cond : O_Reg) is + begin + -- JXX +2 + Start_Insn; + Gen_B8 (16#70# + To_Cond (Cond)); + Gen_B8 (16#02#); + End_Insn; + -- INT 4 (overflow). + Start_Insn; + Gen_B8 (16#CD#); + Gen_B8 (16#04#); + End_Insn; + end Gen_Ov_Check; + + procedure Emit_Abs (Val : O_Enode; Mode : Mode_Type) + is + Szh : Insn_Size; + Pc_Jmp : Pc_Type; + begin + case Mode is + when Mode_I32 => + Szh := Sz_32l; + when Mode_I64 => + Szh := Sz_32h; + when others => + raise Program_Error; + end case; + Emit_Tst (Get_Expr_Reg (Val), Szh); + -- JXX + + Start_Insn; + Gen_B8 (16#70# + To_Cond (R_Sge)); + Gen_B8 (0); + End_Insn; + Pc_Jmp := Get_Current_Pc; + -- NEG + Gen_Mono_Op (2#011_000#, Val, Sz_32l); + if Mode = Mode_I64 then + -- Propagate carray. + -- Adc reg,0 + -- neg reg + Start_Insn; + Gen_B8 (2#100000_11#); + Gen_Rm (2#010_000#, Val, Sz_32h); + Gen_B8 (0); + End_Insn; + Gen_Mono_Op (2#011_000#, Val, Sz_32h); + end if; + Gen_Into; + Patch_B8 (Pc_Jmp - 1, Unsigned_8 (Get_Current_Pc - Pc_Jmp)); + end Emit_Abs; + + procedure Gen_Alloca (Stmt : O_Enode) + is + Reg : O_Reg; + begin + Reg := Get_Expr_Reg (Get_Expr_Operand (Stmt)); + if Reg not in Regs_R32 or else Reg /= Get_Expr_Reg (Stmt) then + raise Program_Error; + end if; + -- Align stack on word. + -- Add reg, (stack_boundary - 1) + Start_Insn; + Gen_B8 (2#1000_0011#); + Gen_B8 (2#11_000_000# + To_Reg32 (Reg)); + Gen_B8 (Byte (X86.Flags.Stack_Boundary - 1)); + End_Insn; + -- and reg, ~(stack_boundary - 1) + Start_Insn; + Gen_B8 (2#1000_0001#); + Gen_B8 (2#11_100_000# + To_Reg32 (Reg)); + Gen_Le32 (not (X86.Flags.Stack_Boundary - 1)); + End_Insn; + if X86.Flags.Flag_Alloca_Call then + Gen_Call (Chkstk_Symbol); + else + -- subl esp, reg + Start_Insn; + Gen_B8 (2#0001_1011#); + Gen_B8 (2#11_100_000# + To_Reg32 (Reg)); + End_Insn; + end if; + -- movl reg, esp + Start_Insn; + Gen_B8 (2#1000_1001#); + Gen_B8 (2#11_100_000# + To_Reg32 (Reg)); + End_Insn; + end Gen_Alloca; + + -- Byte/word to long. + procedure Gen_Movzx (Reg : Regs_R32; Op : O_Enode; Sz : Insn_Size) + is + B : Byte; + begin + Start_Insn; + Gen_B8 (16#0f#); + case Sz is + when Sz_8 => + B := 0; + when Sz_16 => + B := 1; + when Sz_32l + | Sz_32h => + raise Program_Error; + end case; + Gen_B8 (2#1011_0110# + B); + Gen_Rm (To_Reg32 (Reg) * 8, Op, Sz_8); + End_Insn; + end Gen_Movzx; + + -- Convert U32 to xx. + procedure Gen_Conv_U32 (Stmt : O_Enode) + is + Op : O_Enode; + Reg_Op : O_Reg; + Reg_Res : O_Reg; + begin + Op := Get_Expr_Operand (Stmt); + Reg_Op := Get_Expr_Reg (Op); + Reg_Res := Get_Expr_Reg (Stmt); + case Get_Expr_Mode (Stmt) is + when Mode_I32 => + if Reg_Res not in Regs_R32 then + raise Program_Error; + end if; + if Reg_Op /= Reg_Res then + Emit_Load (Reg_Res, Op, Sz_32l); + end if; + Emit_Tst (Reg_Res, Sz_32l); + Gen_Ov_Check (R_Sge); + when Mode_U8 + | Mode_B2 => + if Reg_Res not in Regs_R32 then + raise Program_Error; + end if; + if Reg_Op /= Reg_Res then + Emit_Load (Reg_Res, Op, Sz_32l); + end if; + -- cmpl VAL, 0xff + Start_Insn; + Gen_B8 (2#1000_0001#); + Gen_Rm (2#111_000#, Op, Sz_32l); + Gen_Le32 (16#00_00_00_Ff#); + End_Insn; + Gen_Ov_Check (R_Ule); + when others => + Error_Emit ("gen_conv_u32", Stmt); + end case; + end Gen_Conv_U32; + + -- Convert I32 to xxx + procedure Gen_Conv_I32 (Stmt : O_Enode) + is + Op : O_Enode; + Reg_Op : O_Reg; + Reg_Res : O_Reg; + begin + Op := Get_Expr_Operand (Stmt); + Reg_Op := Get_Expr_Reg (Op); + Reg_Res := Get_Expr_Reg (Stmt); + case Get_Expr_Mode (Stmt) is + when Mode_I64 => + if Reg_Res /= R_Edx_Eax or Reg_Op /= R_Ax then + raise Program_Error; + end if; + Gen_Cdq; + when Mode_U32 => + if Reg_Res not in Regs_R32 then + raise Program_Error; + end if; + if Reg_Op /= Reg_Res then + Emit_Load (Reg_Res, Op, Sz_32l); + end if; + Emit_Tst (Reg_Res, Sz_32l); + Gen_Ov_Check (R_Sge); + when Mode_B2 => + if Reg_Op /= Reg_Res then + Emit_Load (Reg_Res, Op, Sz_32l); + end if; + Gen_Cmp_Imm (Reg_Res, 1, Sz_32l); + Gen_Ov_Check (R_Ule); + when Mode_U8 => + if Reg_Op /= Reg_Res then + Emit_Load (Reg_Res, Op, Sz_32l); + end if; + Gen_Cmp_Imm (Reg_Res, 16#Ff#, Sz_32l); + Gen_Ov_Check (R_Ule); + when Mode_F64 => + Emit_Push_32 (Op, Sz_32l); + -- fild (%esp) + Start_Insn; + Gen_B8 (2#11011_011#); + Gen_B8 (2#00_000_100#); + Gen_B8 (2#00_100_100#); + End_Insn; + -- addl %esp, 4 + Start_Insn; + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_000_100#); + Gen_B8 (4); + End_Insn; + when others => + Error_Emit ("gen_conv_i32", Stmt); + end case; + end Gen_Conv_I32; + + -- Convert U8 to xxx + procedure Gen_Conv_U8 (Stmt : O_Enode) + is + Op : O_Enode; + Reg_Res : O_Reg; + begin + Op := Get_Expr_Operand (Stmt); + Reg_Res := Get_Expr_Reg (Stmt); + case Get_Expr_Mode (Stmt) is + when Mode_U32 + | Mode_I32 + | Mode_U16 + | Mode_I16 => + if Reg_Res not in Regs_R32 then + raise Program_Error; + end if; + Gen_Movzx (Reg_Res, Op, Sz_8); + when others => + Error_Emit ("gen_conv_U8", Stmt); + end case; + end Gen_Conv_U8; + + -- Convert B2 to xxx + procedure Gen_Conv_B2 (Stmt : O_Enode) + is + Op : O_Enode; + Reg_Res : O_Reg; + begin + Op := Get_Expr_Operand (Stmt); + Reg_Res := Get_Expr_Reg (Stmt); + case Get_Expr_Mode (Stmt) is + when Mode_U32 + | Mode_I32 + | Mode_U16 + | Mode_I16 => + Gen_Movzx (Reg_Res, Op, Sz_8); + when others => + Error_Emit ("gen_conv_B2", Stmt); + end case; + end Gen_Conv_B2; + + -- Convert I64 to xxx + procedure Gen_Conv_I64 (Stmt : O_Enode) + is + Op : O_Enode; + begin + Op := Get_Expr_Operand (Stmt); + case Get_Expr_Mode (Stmt) is + when Mode_I32 => + -- move dx to reg_helper + Start_Insn; + Gen_B8 (2#1000_1001#); + Gen_B8 (2#11_010_000# + To_Reg32 (Reg_Helper)); + End_Insn; + Gen_Cdq; + -- cmp reg_helper, dx + Start_Insn; + Gen_B8 (2#0011_1001#); + Gen_B8 (2#11_010_000# + To_Reg32 (Reg_Helper)); + End_Insn; + Gen_Ov_Check (R_Eq); + when Mode_F64 => + Emit_Push_32 (Op, Sz_32h); + Emit_Push_32 (Op, Sz_32l); + -- fild (%esp) + Start_Insn; + Gen_B8 (2#11011_111#); + Gen_B8 (2#00_101_100#); + Gen_B8 (2#00_100_100#); + End_Insn; + -- addl %esp, 8 + Start_Insn; + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_000_100#); + Gen_B8 (8); + End_Insn; + when others => + Error_Emit ("gen_conv_I64", Stmt); + end case; + end Gen_Conv_I64; + + -- Convert FP to xxx. + procedure Gen_Conv_Fp (Stmt : O_Enode) is + begin + case Get_Expr_Mode (Stmt) is + when Mode_I32 => + -- subl %esp, 4 + Start_Insn; + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_101_100#); + Gen_B8 (4); + End_Insn; + -- fistp (%esp) + Start_Insn; + Gen_B8 (2#11011_011#); + Gen_B8 (2#00_011_100#); + Gen_B8 (2#00_100_100#); + End_Insn; + Emit_Pop_32 (Stmt, Sz_32l); + when Mode_I64 => + -- subl %esp, 8 + Start_Insn; + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_101_100#); + Gen_B8 (8); + End_Insn; + -- fistp (%esp) + Start_Insn; + Gen_B8 (2#11011_111#); + Gen_B8 (2#00_111_100#); + Gen_B8 (2#00_100_100#); + End_Insn; + Emit_Pop_32 (Stmt, Sz_32l); + Emit_Pop_32 (Stmt, Sz_32h); + when others => + Error_Emit ("gen_conv_fp", Stmt); + end case; + end Gen_Conv_Fp; + + procedure Gen_Emit_Op (Stmt : O_Enode; Cl : Byte; Ch : Byte) is + begin + case Get_Expr_Mode (Stmt) is + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Op (Cl, Stmt, Sz_32l); + when Mode_I64 + | Mode_U64 => + Emit_Op (Cl, Stmt, Sz_32l); + Emit_Op (Ch, Stmt, Sz_32h); + when Mode_B2 + | Mode_I8 + | Mode_U8 => + Emit_Op (Cl, Stmt, Sz_8); + when others => + Error_Emit ("gen_emit_op", Stmt); + end case; + end Gen_Emit_Op; + + procedure Gen_Check_Overflow (Mode : Mode_Type) is + begin + case Mode is + when Mode_I32 + | Mode_I64 + | Mode_I8 => + Gen_Into; + when Mode_U64 + | Mode_U32 + | Mode_U8 => + -- FIXME: check no carry. + null; + when Mode_B2 => + null; + when others => + raise Program_Error; + end case; + end Gen_Check_Overflow; + + procedure Gen_Emit_Fp_Op (Stmt : O_Enode; B_St1 : Byte; B_Mem : Byte) + is + Right : O_Enode; + Reg : O_Reg; + B_Size : Byte; + begin + Right := Get_Expr_Right (Stmt); + Reg := Get_Expr_Reg (Right); + Start_Insn; + case Reg is + when R_St0 => + Gen_B8 (2#11011_110#); + Gen_B8 (2#11_000_001# or B_St1); + when R_Mem => + case Get_Expr_Mode (Stmt) is + when Mode_F32 => + B_Size := 0; + when Mode_F64 => + B_Size := 2#100#; + when others => + raise Program_Error; + end case; + Gen_B8 (2#11011_000# or B_Size); + Gen_Rm_Mem (B_Mem, Right, Sz_32l); + when others => + raise Program_Error; + end case; + End_Insn; + end Gen_Emit_Fp_Op; + + procedure Emit_Mod (Stmt : O_Enode) + is + Right : O_Enode; + Pc1, Pc2, Pc3: Pc_Type; + begin + -- a : EAX + -- d : EDX + -- b : Rm + + -- d := Rm + -- d := d ^ a + -- cltd + -- if cc < 0 then + -- idiv b + -- if edx /= 0 then + -- edx := edx + b + -- end if + -- else + -- idiv b + -- end if + Right := Get_Expr_Right (Stmt); + -- %edx <- right + Emit_Load (R_Dx, Right, Sz_32l); + -- xorl %eax -> %edx + Start_Insn; + Gen_B8 (2#0011_0011#); + Gen_B8 (2#11_010_000#); + End_Insn; + Gen_Cdq; + -- js + Start_Insn; + Gen_B8 (2#0111_1000#); + Gen_B8 (0); + End_Insn; + Pc1 := Get_Current_Pc; + -- idiv + Gen_Mono_Op (2#111_000#, Right, Sz_32l); + -- jmp + Start_Insn; + Gen_B8 (2#1110_1011#); + Gen_B8 (0); + End_Insn; + Pc2 := Get_Current_Pc; + Patch_B8 (Pc1 - 1, Unsigned_8 (Get_Current_Pc - Pc1)); + -- idiv + Gen_Mono_Op (2#111_000#, Right, Sz_32l); + -- tstl %edx,%edx + Start_Insn; + Gen_B8 (2#1000_0101#); + Gen_B8 (2#11_010_010#); + End_Insn; + -- jz + Start_Insn; + Gen_B8 (2#0111_0100#); + Gen_B8 (0); + End_Insn; + Pc3 := Get_Current_Pc; + -- addl b, %edx + Start_Insn; + Gen_B8 (2#00_000_011#); + Gen_Rm (2#010_000#, Right, Sz_32l); + End_Insn; + Patch_B8 (Pc2 - 1, Unsigned_8 (Get_Current_Pc - Pc2)); + Patch_B8 (Pc3 - 1, Unsigned_8 (Get_Current_Pc - Pc3)); + end Emit_Mod; + + procedure Emit_Insn (Stmt : O_Enode) + is + use Ortho_Code.Flags; + Kind : OE_Kind; + Mode : Mode_Type; + Reg : O_Reg; + begin + Kind := Get_Expr_Kind (Stmt); + Mode := Get_Expr_Mode (Stmt); + case Kind is + when OE_Beg => + if Flag_Debug /= Debug_None then + Decls.Set_Block_Info1 (Get_Block_Decls (Stmt), + Int32 (Get_Current_Pc - Subprg_Pc)); + end if; + when OE_End => + if Flag_Debug /= Debug_None then + Decls.Set_Block_Info2 (Get_Block_Decls (Get_End_Beg (Stmt)), + Int32 (Get_Current_Pc - Subprg_Pc)); + end if; + when OE_Leave => + null; + when OE_BB => + null; + when OE_Add_Ov => + if Mode in Mode_Fp then + Gen_Emit_Fp_Op (Stmt, 2#000_000#, 2#000_000#); + else + Gen_Emit_Op (Stmt, 2#000_000#, 2#010_000#); + Gen_Check_Overflow (Mode); + end if; + when OE_Or => + Gen_Emit_Op (Stmt, 2#001_000#, 2#001_000#); + when OE_And => + Gen_Emit_Op (Stmt, 2#100_000#, 2#100_000#); + when OE_Xor => + Gen_Emit_Op (Stmt, 2#110_000#, 2#110_000#); + when OE_Sub_Ov => + if Mode in Mode_Fp then + Gen_Emit_Fp_Op (Stmt, 2#100_000#, 2#100_000#); + else + Gen_Emit_Op (Stmt, 2#101_000#, 2#011_000#); + Gen_Check_Overflow (Mode); + end if; + when OE_Mul_Ov + | OE_Mul => + case Mode is + when Mode_U8 => + Gen_Umul (Stmt, Sz_8); + when Mode_U16 => + Gen_Umul (Stmt, Sz_16); + when Mode_U32 => + Gen_Mul (Stmt, Sz_32l); + when Mode_I32 => + Gen_Mono_Op (2#101_000#, Get_Expr_Right (Stmt), Sz_32l); + when Mode_F32 + | Mode_F64 => + Gen_Emit_Fp_Op (Stmt, 2#001_000#, 2#001_000#); + when others => + Error_Emit ("emit_insn: mul_ov", Stmt); + end case; + when OE_Shl => + declare + Right : O_Enode; + Sz : Insn_Size; + Val : Uns32; + begin + case Mode is + when Mode_U32 => + Sz := Sz_32l; + when others => + Error_Emit ("emit_insn: shl", Stmt); + end case; + Right := Get_Expr_Right (Stmt); + if Get_Expr_Kind (Right) = OE_Const then + Val := Get_Expr_Low (Right); + Start_Insn; + if Val = 1 then + Gen_Insn_Sz (2#1101000_0#, Sz); + Gen_Rm (2#100_000#, Get_Expr_Left (Stmt), Sz); + else + Gen_Insn_Sz (2#1100000_0#, Sz); + Gen_Rm (2#100_000#, Get_Expr_Left (Stmt), Sz); + Gen_B8 (Byte (Val and 31)); + end if; + End_Insn; + else + if Get_Expr_Reg (Right) /= R_Cx then + raise Program_Error; + end if; + Start_Insn; + Gen_Insn_Sz (2#1101001_0#, Sz); + Gen_Rm (2#100_000#, Get_Expr_Left (Stmt), Sz); + End_Insn; + end if; + end; + when OE_Mod + | OE_Rem + | OE_Div_Ov => + case Mode is + when Mode_U32 => + -- Xorl edx, edx + Start_Insn; + Gen_B8 (2#0011_0001#); + Gen_B8 (2#11_010_010#); + End_Insn; + Gen_Mono_Op (2#110_000#, Get_Expr_Right (Stmt), Sz_32l); + when Mode_I32 => + if Kind = OE_Mod then + Emit_Mod (Stmt); + else + Gen_Cdq; + Gen_Mono_Op (2#111_000#, Get_Expr_Right (Stmt), Sz_32l); + end if; + when Mode_F32 + | Mode_F64 => + if Kind = OE_Div_Ov then + Gen_Emit_Fp_Op (Stmt, 2#111_000#, 2#110_000#); + else + raise Program_Error; + end if; + when others => + Error_Emit ("emit_insn: mod_ov", Stmt); + end case; + + when OE_Not => + case Mode is + when Mode_B2 => + -- Xor VAL, $1 + Start_Insn; + Gen_B8 (2#1000_0011#); + Gen_Rm (2#110_000#, Stmt, Sz_8); + Gen_B8 (16#01#); + End_Insn; + when Mode_U8 => + Emit_Mono_Op_Stmt (2#010_000#, Stmt, Sz_8); + when Mode_U16 => + Emit_Mono_Op_Stmt (2#010_000#, Stmt, Sz_16); + when Mode_U32 => + Emit_Mono_Op_Stmt (2#010_000#, Stmt, Sz_32l); + when Mode_U64 => + Emit_Mono_Op_Stmt (2#010_000#, Stmt, Sz_32l); + Emit_Mono_Op_Stmt (2#010_000#, Stmt, Sz_32h); + when others => + Error_Emit ("emit_insn: not", Stmt); + end case; + + when OE_Neg_Ov => + case Mode is + when Mode_I8 => + Emit_Mono_Op_Stmt (2#011_000#, Stmt, Sz_8); + --Gen_Into; + when Mode_I16 => + Emit_Mono_Op_Stmt (2#011_000#, Stmt, Sz_16); + --Gen_Into; + when Mode_I32 => + Emit_Mono_Op_Stmt (2#011_000#, Stmt, Sz_32l); + --Gen_Into; + when Mode_I64 => + Emit_Mono_Op_Stmt (2#011_000#, Stmt, Sz_32l); + -- adcl 0, high + Start_Insn; + Gen_B8 (2#100000_11#); + Gen_Rm (2#010_000#, Get_Expr_Operand (Stmt), Sz_32h); + Gen_B8 (0); + End_Insn; + Emit_Mono_Op_Stmt (2#011_000#, Stmt, Sz_32h); + --Gen_Into; + when Mode_F32 + | Mode_F64 => + -- fchs + Start_Insn; + Gen_B8 (2#11011_001#); + Gen_B8 (2#1110_0000#); + End_Insn; + when others => + Error_Emit ("emit_insn: neg_ov", Stmt); + end case; + + when OE_Abs_Ov => + case Mode is + when Mode_I32 + | Mode_I64 => + Emit_Abs (Get_Expr_Operand (Stmt), Mode); + when Mode_F32 + | Mode_F64 => + -- fabs + Start_Insn; + Gen_B8 (2#11011_001#); + Gen_B8 (2#1110_0001#); + End_Insn; + when others => + Error_Emit ("emit_insn: abs_ov", Stmt); + end case; + + when OE_Kind_Cmp => + case Get_Expr_Mode (Get_Expr_Left (Stmt)) is + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Op (2#111_000#, Stmt, Sz_32l); + when Mode_B2 + | Mode_I8 + | Mode_U8 => + Emit_Op (2#111_000#, Stmt, Sz_8); + when Mode_U64 => + declare + Pc : Pc_Type; + begin + Emit_Op (2#111_000#, Stmt, Sz_32h); + -- jne + Start_Insn; + Gen_B8 (2#0111_0101#); + Gen_B8 (0); + End_Insn; + Pc := Get_Current_Pc; + Emit_Op (2#111_000#, Stmt, Sz_32l); + Patch_B8 (Pc - 1, Unsigned_8 (Get_Current_Pc - Pc)); + end; + when Mode_I64 => + declare + Pc : Pc_Type; + begin + Reg := Get_Expr_Reg (Stmt); + Emit_Op (2#111_000#, Stmt, Sz_32h); + -- Note: this does not clobber a reg due to care in + -- insns. + Emit_Setcc_Reg (Reg, Ekind_Signed_To_Cc (Kind)); + -- jne + Start_Insn; + Gen_B8 (2#0111_0101#); + Gen_B8 (0); + End_Insn; + Pc := Get_Current_Pc; + Emit_Op (2#111_000#, Stmt, Sz_32l); + Emit_Setcc_Reg (Reg, Ekind_Unsigned_To_Cc (Kind)); + Patch_B8 (Pc - 1, Unsigned_8 (Get_Current_Pc - Pc)); + return; + end; + when Mode_F32 + | Mode_F64 => + -- fcomip st, st(1) + Start_Insn; + Gen_B8 (2#11011_111#); + Gen_B8 (2#1111_0001#); + End_Insn; + -- fstp st, st (0) + Start_Insn; + Gen_B8 (2#11011_101#); + Gen_B8 (2#11_011_000#); + End_Insn; + when others => + Error_Emit ("emit_insn: cmp", Stmt); + end case; + Reg := Get_Expr_Reg (Stmt); + if Reg not in Regs_Cc then + Error_Emit ("emit_insn/cmp: not cc", Stmt); + end if; + when OE_Const + | OE_Addrg => + case Mode is + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Load_Imm (Stmt, Sz_32l); + when Mode_B2 + | Mode_U8 + | Mode_I8 => + Emit_Load_Imm (Stmt, Sz_8); + when Mode_I64 + | Mode_U64 => + Emit_Load_Imm (Stmt, Sz_32l); + Emit_Load_Imm (Stmt, Sz_32h); + when Mode_F32 => + Emit_Load_Fp (Stmt, Fp_32); + when Mode_F64 => + Emit_Load_Fp (Stmt, Fp_64); + when others => + Error_Emit ("emit_insn: const", Stmt); + end case; + when OE_Indir => + case Mode is + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Load_Mem (Stmt, Sz_32l); + when Mode_B2 + | Mode_U8 + | Mode_I8 => + Emit_Load_Mem (Stmt, Sz_8); + when Mode_U64 + | Mode_I64 => + Emit_Load_Mem (Stmt, Sz_32l); + Emit_Load_Mem (Stmt, Sz_32h); + when Mode_F32 => + Emit_Load_Fp_Mem (Stmt, Fp_32); + when Mode_F64 => + Emit_Load_Fp_Mem (Stmt, Fp_64); + when others => + Error_Emit ("emit_insn: indir", Stmt); + end case; + + when OE_Conv => + case Get_Expr_Mode (Get_Expr_Operand (Stmt)) is + when Mode_U32 => + Gen_Conv_U32 (Stmt); + when Mode_I32 => + Gen_Conv_I32 (Stmt); + when Mode_U8 => + Gen_Conv_U8 (Stmt); + when Mode_B2 => + Gen_Conv_B2 (Stmt); + when Mode_I64 => + Gen_Conv_I64 (Stmt); + when Mode_F32 + | Mode_F64 => + Gen_Conv_Fp (Stmt); + when others => + Error_Emit ("emit_insn: conv", Stmt); + end case; + + when OE_Asgn => + case Mode is + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Store (Stmt, Sz_32l); + when Mode_B2 + | Mode_U8 + | Mode_I8 => + Emit_Store (Stmt, Sz_8); + when Mode_U64 + | Mode_I64 => + Emit_Store (Stmt, Sz_32l); + Emit_Store (Stmt, Sz_32h); + when Mode_F32 => + Emit_Store_Fp (Stmt, Fp_32); + when Mode_F64 => + Emit_Store_Fp (Stmt, Fp_64); + when others => + Error_Emit ("emit_insn: move", Stmt); + end case; + + when OE_Jump_F => + Reg := Get_Expr_Reg (Get_Expr_Operand (Stmt)); + if Reg not in Regs_Cc then + Error_Emit ("emit_insn/jmp_f: not cc", Stmt); + end if; + Emit_Jmp_T (Stmt, Inverse_Cc (Reg)); + when OE_Jump_T => + Reg := Get_Expr_Reg (Get_Expr_Operand (Stmt)); + if Reg not in Regs_Cc then + Error_Emit ("emit_insn/jmp_t: not cc", Stmt); + end if; + Emit_Jmp_T (Stmt, Reg); + when OE_Jump => + Emit_Jmp (Stmt); + when OE_Label => + Emit_Label (Stmt); + + when OE_Ret => + -- Value already set. + null; + + when OE_Arg => + case Mode is + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Push_32 (Get_Expr_Operand (Stmt), Sz_32l); + when Mode_U64 + | Mode_I64 => + Emit_Push_32 (Get_Expr_Operand (Stmt), Sz_32h); + Emit_Push_32 (Get_Expr_Operand (Stmt), Sz_32l); + when Mode_F32 => + Emit_Push_Fp (Get_Expr_Operand (Stmt), Fp_32); + when Mode_F64 => + Emit_Push_Fp (Get_Expr_Operand (Stmt), Fp_64); + when others => + Error_Emit ("emit_insn: oe_arg", Stmt); + end case; + when OE_Stack_Adjust => + Emit_Setup_Frame (Stmt); + when OE_Call => + Emit_Call (Stmt); + when OE_Intrinsic => + Emit_Intrinsic (Stmt); + + when OE_Move => + declare + Operand : O_Enode; + Op_Reg : O_Reg; + begin + Reg := Get_Expr_Reg (Stmt); + Operand := Get_Expr_Operand (Stmt); + Op_Reg := Get_Expr_Reg (Operand); + case Mode is + when Mode_B2 => + if Reg in Regs_R32 and then Op_Reg in Regs_Cc then + Emit_Setcc (Stmt, Op_Reg); + elsif (Reg = R_Eq or Reg = R_Ne) + and then Op_Reg in Regs_R32 + then + Emit_Tst (Op_Reg, Sz_8); + else + Error_Emit ("emit_insn: move/b2", Stmt); + end if; + when Mode_U32 + | Mode_I32 => + -- mov REG, OP + Start_Insn; + Gen_Insn_Sz (2#1000_101_0#, Sz_32l); + Gen_Rm (To_Reg32 (Reg, Sz_32l) * 8, Operand, Sz_32l); + End_Insn; + when others => + Error_Emit ("emit_insn: move", Stmt); + end case; + end; + + when OE_Alloca => + if Mode /= Mode_P32 then + raise Program_Error; + end if; + Gen_Alloca (Stmt); + + when OE_Set_Stack => + Emit_Load_Mem (Stmt, Sz_32l); + + when OE_Add + | OE_Addrl => + case Mode is + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Lea (Stmt); + when others => + Error_Emit ("emit_insn: oe_add", Stmt); + end case; + + when OE_Spill => + case Mode is + when Mode_B2 + | Mode_U8 + | Mode_I8 => + Emit_Spill (Stmt, Sz_8); + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Spill (Stmt, Sz_32l); + when Mode_U64 + | Mode_I64 => + Emit_Spill (Stmt, Sz_32l); + Emit_Spill (Stmt, Sz_32h); + when others => + Error_Emit ("emit_insn: spill", Stmt); + end case; + + when OE_Reload => + declare + Expr : O_Enode; + begin + Reg := Get_Expr_Reg (Stmt); + Expr := Get_Expr_Operand (Stmt); + case Mode is + when Mode_B2 + | Mode_U8 + | Mode_I8 => + Emit_Load (Reg, Expr, Sz_8); + when Mode_U32 + | Mode_I32 + | Mode_P32 => + Emit_Load (Reg, Expr, Sz_32l); + when Mode_U64 + | Mode_I64 => + Emit_Load (Reg, Expr, Sz_32l); + Emit_Load (Reg, Expr, Sz_32h); + when others => + Error_Emit ("emit_insn: reload", Stmt); + end case; + end; + + when OE_Reg => + Reg_Helper := Get_Expr_Reg (Stmt); + + when OE_Case_Expr + | OE_Case => + null; + + when OE_Line => + if Flag_Debug = Debug_Dwarf then + Dwarf.Set_Line_Stmt (Get_Expr_Line_Number (Stmt)); + Set_Current_Section (Sect_Text); + end if; + when others => + Error_Emit ("cannot handle insn", Stmt); + end case; + end Emit_Insn; + + procedure Push_Reg_If_Used (Reg : Regs_R32) + is + use Ortho_Code.X86.Insns; + begin + if Reg_Used (Reg) then + Start_Insn; + Gen_B8 (2#01010_000# + To_Reg32 (Reg, Sz_32l)); + End_Insn; + end if; + end Push_Reg_If_Used; + + procedure Pop_Reg_If_Used (Reg : Regs_R32) + is + use Ortho_Code.X86.Insns; + begin + if Reg_Used (Reg) then + Start_Insn; + Gen_B8 (2#01011_000# + To_Reg32 (Reg, Sz_32l)); + End_Insn; + end if; + end Pop_Reg_If_Used; + + procedure Emit_Prologue (Subprg : Subprogram_Data_Acc) + is + use Ortho_Code.Decls; + use Ortho_Code.Flags; + use Ortho_Code.X86.Insns; + Sym : Symbol; + Subprg_Decl : O_Dnode; + Is_Global : Boolean; + Frame_Size : Unsigned_32; + Saved_Regs_Size : Unsigned_32; + begin + -- Switch to .text section and align the function (to avoid the nested + -- function trick and for performance). + Set_Current_Section (Sect_Text); + Gen_Pow_Align (2); + + Subprg_Decl := Subprg.D_Decl; + Sym := Get_Decl_Symbol (Subprg_Decl); + case Get_Decl_Storage (Subprg_Decl) is + when O_Storage_Public + | O_Storage_External => + -- FIXME: should not accept the external case. + Is_Global := True; + when others => + Is_Global := False; + end case; + Set_Symbol_Pc (Sym, Is_Global); + Subprg_Pc := Get_Current_Pc; + + Saved_Regs_Size := Boolean'Pos(Reg_Used (R_Di)) * 4 + + Boolean'Pos(Reg_Used (R_Si)) * 4 + + Boolean'Pos(Reg_Used (R_Bx)) * 4; + + -- Compute frame size. + -- 8 bytes are used by return address and saved frame pointer. + Frame_Size := Unsigned_32 (Subprg.Stack_Max) + 8 + Saved_Regs_Size; + -- Align. + Frame_Size := (Frame_Size + X86.Flags.Stack_Boundary - 1) + and not (X86.Flags.Stack_Boundary - 1); + -- The 8 bytes are already allocated. + Frame_Size := Frame_Size - 8 - Saved_Regs_Size; + + -- Emit prolog. + -- push %ebp + Start_Insn; + Gen_B8 (2#01010_101#); + End_Insn; + -- movl %esp, %ebp + Start_Insn; + Gen_B8 (2#1000100_1#); + Gen_B8 (2#11_100_101#); + End_Insn; + -- subl XXX, %esp + if Frame_Size /= 0 then + if not X86.Flags.Flag_Alloca_Call + or else Frame_Size <= 4096 + then + Start_Insn; + if Frame_Size < 128 then + Gen_B8 (2#100000_11#); + Gen_B8 (2#11_101_100#); + Gen_B8 (Byte (Frame_Size)); + else + Gen_B8 (2#100000_01#); + Gen_B8 (2#11_101_100#); + Gen_Le32 (Frame_Size); + end if; + End_Insn; + else + -- mov stack_size,%eax + Start_Insn; + Gen_B8 (2#1011_1_000#); + Gen_Le32 (Frame_Size); + End_Insn; + Gen_Call (Chkstk_Symbol); + end if; + end if; + + if Flag_Profile then + Gen_Call (Mcount_Symbol); + end if; + + -- Save registers. + Push_Reg_If_Used (R_Di); + Push_Reg_If_Used (R_Si); + Push_Reg_If_Used (R_Bx); + end Emit_Prologue; + + procedure Emit_Epilogue (Subprg : Subprogram_Data_Acc) + is + use Ortho_Code.Decls; + use Ortho_Code.Types; + use Ortho_Code.Flags; + Decl : O_Dnode; + begin + -- Restore registers. + Pop_Reg_If_Used (R_Bx); + Pop_Reg_If_Used (R_Si); + Pop_Reg_If_Used (R_Di); + + Decl := Subprg.D_Decl; + if Get_Decl_Kind (Decl) = OD_Function then + case Get_Type_Mode (Get_Decl_Type (Decl)) is + when Mode_U8 + | Mode_B2 => + -- movzx %al,%eax + Start_Insn; + Gen_B8 (16#0f#); + Gen_B8 (2#1011_0110#); + Gen_B8 (2#11_000_000#); + End_Insn; + when Mode_U32 + | Mode_I32 + | Mode_U64 + | Mode_I64 + | Mode_F32 + | Mode_F64 + | Mode_P32 => + null; + when others => + raise Program_Error; + end case; + end if; + + -- leave + Start_Insn; + Gen_B8 (2#1100_1001#); + End_Insn; + + -- ret + Start_Insn; + Gen_B8 (2#1100_0011#); + End_Insn; + + if Flag_Debug = Debug_Dwarf then + Set_Body_Info (Subprg.D_Body, Int32 (Get_Current_Pc - Subprg_Pc)); + end if; + end Emit_Epilogue; + + procedure Emit_Subprg (Subprg : Subprogram_Data_Acc) + is + Stmt : O_Enode; + begin + if Debug.Flag_Debug_Code2 then + Abi.Disp_Subprg_Decl (Subprg.D_Decl); + end if; + + Emit_Prologue (Subprg); + + Stmt := Subprg.E_Entry; + loop + Stmt := Get_Stmt_Link (Stmt); + + if Debug.Flag_Debug_Code2 then + Abi.Disp_Stmt (Stmt); + end if; + + Emit_Insn (Stmt); + exit when Get_Expr_Kind (Stmt) = OE_Leave; + end loop; + + Emit_Epilogue (Subprg); + end Emit_Subprg; + + procedure Emit_Var_Decl (Decl : O_Dnode) + is + use Decls; + use Types; + Sym : Symbol; + Storage : O_Storage; + Dtype : O_Tnode; + begin + Set_Current_Section (Sect_Bss); + Sym := Create_Symbol (Get_Decl_Ident (Decl)); + Set_Decl_Info (Decl, To_Int32 (Uns32 (Sym))); + Storage := Get_Decl_Storage (Decl); + Dtype := Get_Decl_Type (Decl); + case Storage is + when O_Storage_External => + null; + when O_Storage_Public + | O_Storage_Private => + Gen_Pow_Align (Get_Type_Align (Dtype)); + Set_Symbol_Pc (Sym, Storage = O_Storage_Public); + Gen_Space (Integer_32 (Get_Type_Size (Dtype))); + when O_Storage_Local => + raise Program_Error; + end case; + Set_Current_Section (Sect_Text); + end Emit_Var_Decl; + + procedure Emit_Const_Decl (Decl : O_Dnode) + is + use Decls; + use Types; + Sym : Symbol; + begin + Set_Current_Section (Sect_Rodata); + Sym := Create_Symbol (Get_Decl_Ident (Decl)); + Set_Decl_Info (Decl, To_Int32 (Uns32 (Sym))); + Set_Current_Section (Sect_Text); + end Emit_Const_Decl; + + procedure Emit_Const (Val : O_Cnode) + is + use Consts; + use Types; + H, L : Uns32; + begin + case Get_Const_Kind (Val) is + when OC_Signed + | OC_Unsigned + | OC_Float + | OC_Null + | OC_Lit => + Get_Const_Bytes (Val, H, L); + case Get_Type_Mode (Get_Const_Type (Val)) is + when Mode_U8 + | Mode_I8 + | Mode_B2 => + Gen_B8 (Byte (L)); + when Mode_U32 + | Mode_I32 + | Mode_F32 + | Mode_P32 => + Gen_Le32 (Unsigned_32 (L)); + when Mode_F64 + | Mode_I64 + | Mode_U64 => + Gen_Le32 (Unsigned_32 (L)); + Gen_Le32 (Unsigned_32 (H)); + when others => + raise Program_Error; + end case; + when OC_Address + | OC_Subprg_Address => + Gen_X86_32 (Get_Decl_Symbol (Get_Const_Decl (Val)), 0); + when OC_Array => + for I in 0 .. Get_Const_Aggr_Length (Val) - 1 loop + Emit_Const (Get_Const_Aggr_Element (Val, I)); + end loop; + when OC_Record => + declare + E : O_Cnode; + begin + for I in 0 .. Get_Const_Aggr_Length (Val) - 1 loop + E := Get_Const_Aggr_Element (Val, I); + Gen_Pow_Align (Get_Type_Align (Get_Const_Type (E))); + Emit_Const (E); + end loop; + end; + when OC_Sizeof + | OC_Alignof + | OC_Union => + raise Program_Error; + end case; + end Emit_Const; + + procedure Emit_Const_Value (Decl : O_Dnode; Val : O_Cnode) + is + use Decls; + use Types; + Sym : Symbol; + Dtype : O_Tnode; + begin + Set_Current_Section (Sect_Rodata); + Sym := Get_Decl_Symbol (Decl); + + Dtype := Get_Decl_Type (Decl); + Gen_Pow_Align (Get_Type_Align (Dtype)); + Set_Symbol_Pc (Sym, Get_Decl_Storage (Decl) = O_Storage_Public); + Prealloc (Pc_Type (Get_Type_Size (Dtype))); + Emit_Const (Val); + + Set_Current_Section (Sect_Text); + end Emit_Const_Value; + + procedure Init + is + use Ortho_Ident; + use Ortho_Code.Flags; + begin + Arch := Arch_X86; + + Create_Section (Sect_Text, ".text", Section_Exec + Section_Read); + Create_Section (Sect_Rodata, ".rodata", Section_Read); + Create_Section (Sect_Bss, ".bss", + Section_Read + Section_Write + Section_Zero); + + Set_Current_Section (Sect_Text); + + if Flag_Profile then + Mcount_Symbol := Create_Symbol (Get_Identifier ("mcount")); + end if; + + if X86.Flags.Flag_Alloca_Call then + Chkstk_Symbol := Create_Symbol (Get_Identifier ("___chkstk")); + end if; + + Intrinsics_Symbol (Intrinsic_Mul_Ov_U64) := + Create_Symbol (Get_Identifier ("__muldi3")); + Intrinsics_Symbol (Intrinsic_Div_Ov_U64) := + Create_Symbol (Get_Identifier ("__mcode_div_ov_u64")); + Intrinsics_Symbol (Intrinsic_Mod_Ov_U64) := + Create_Symbol (Get_Identifier ("__mcode_mod_ov_u64")); + Intrinsics_Symbol (Intrinsic_Mul_Ov_I64) := + Create_Symbol (Get_Identifier ("__muldi3")); + Intrinsics_Symbol (Intrinsic_Div_Ov_I64) := + Create_Symbol (Get_Identifier ("__divdi3")); + Intrinsics_Symbol (Intrinsic_Mod_Ov_I64) := + Create_Symbol (Get_Identifier ("__mcode_mod_ov_i64")); + Intrinsics_Symbol (Intrinsic_Rem_Ov_I64) := + Create_Symbol (Get_Identifier ("__mcode_rem_ov_i64")); + + if Debug.Flag_Debug_Asm then + Dump_Asm := True; + end if; + if Debug.Flag_Debug_Hex then + Debug_Hex := True; + end if; + + if Flag_Debug = Debug_Dwarf then + Dwarf.Init; + Set_Current_Section (Sect_Text); + end if; + end Init; + + procedure Finish + is + use Ortho_Code.Flags; + begin + if Flag_Debug = Debug_Dwarf then + Set_Current_Section (Sect_Text); + Dwarf.Finish; + end if; + end Finish; + +end Ortho_Code.X86.Emits; + diff --git a/src/ortho/mcode/ortho_code-x86-emits.ads b/src/ortho/mcode/ortho_code-x86-emits.ads new file mode 100644 index 000000000..9ddb43ee5 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-emits.ads @@ -0,0 +1,36 @@ +-- Mcode back-end for ortho - Binary X86 instructions generator. +-- 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 Binary_File; use Binary_File; + +package Ortho_Code.X86.Emits is + procedure Init; + procedure Finish; + + procedure Emit_Subprg (Subprg : Subprogram_Data_Acc); + + procedure Emit_Var_Decl (Decl : O_Dnode); + procedure Emit_Const_Decl (Decl : O_Dnode); + procedure Emit_Const_Value (Decl : O_Dnode; Val : O_Cnode); + + type Intrinsic_Symbols_Map is array (Intrinsics_X86) of Symbol; + Intrinsics_Symbol : Intrinsic_Symbols_Map; + + Mcount_Symbol : Symbol; + Chkstk_Symbol : Symbol; +end Ortho_Code.X86.Emits; + diff --git a/src/ortho/mcode/ortho_code-x86-flags_linux.ads b/src/ortho/mcode/ortho_code-x86-flags_linux.ads new file mode 100644 index 000000000..30bc7f7b3 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-flags_linux.ads @@ -0,0 +1,31 @@ +-- X86 ABI flags. +-- 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 Interfaces; use Interfaces; + +package Ortho_Code.X86.Flags_Linux is + -- If true, OE_Alloca calls __chkstk (Windows), otherwise OE_Alloc + -- modifies ESP directly. + Flag_Alloca_Call : constant Boolean := False; + + -- Prefered stack alignment. + -- Must be a power of 2. + Stack_Boundary : constant Unsigned_32 := 2 ** 3; + + -- Alignment for double (64 bit float). + Mode_F64_Align : constant Natural := 2; +end Ortho_Code.X86.Flags_Linux; diff --git a/src/ortho/mcode/ortho_code-x86-flags_macosx.ads b/src/ortho/mcode/ortho_code-x86-flags_macosx.ads new file mode 100644 index 000000000..a33085294 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-flags_macosx.ads @@ -0,0 +1,31 @@ +-- X86 ABI flags. +-- 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 Interfaces; use Interfaces; + +package Ortho_Code.X86.Flags_Macosx is + -- If true, OE_Alloca calls __chkstk (Windows), otherwise OE_Alloc + -- modifies ESP directly. + Flag_Alloca_Call : constant Boolean := False; + + -- Prefered stack alignment. + -- Must be a power of 2. + Stack_Boundary : constant Unsigned_32 := 2 ** 4; + + -- Alignment for double (64 bit float). + Mode_F64_Align : constant Natural := 2; +end Ortho_Code.X86.Flags_Macosx; diff --git a/src/ortho/mcode/ortho_code-x86-flags_windows.ads b/src/ortho/mcode/ortho_code-x86-flags_windows.ads new file mode 100644 index 000000000..3296aaf2c --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-flags_windows.ads @@ -0,0 +1,31 @@ +-- X86 ABI flags. +-- 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 Interfaces; use Interfaces; + +package Ortho_Code.X86.Flags_Windows is + -- If true, OE_Alloca calls __chkstk (Windows), otherwise OE_Alloc + -- modifies ESP directly. + Flag_Alloca_Call : constant Boolean := True; + + -- Prefered stack alignment. + -- Must be a power of 2. + Stack_Boundary : constant Unsigned_32 := 2 ** 3; + + -- Alignment for double (64 bit float). + Mode_F64_Align : constant Natural := 3; +end Ortho_Code.X86.Flags_Windows; diff --git a/src/ortho/mcode/ortho_code-x86-insns.adb b/src/ortho/mcode/ortho_code-x86-insns.adb new file mode 100644 index 000000000..c218a9ae0 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-insns.adb @@ -0,0 +1,2068 @@ +-- Mcode back-end for ortho - mcode to X86 instructions. +-- 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 Interfaces; +with Ada.Text_IO; +with Ortho_Code.Abi; +with Ortho_Code.Decls; use Ortho_Code.Decls; +with Ortho_Code.Types; use Ortho_Code.Types; +with Ortho_Code.Debug; +with Ortho_Code.X86.Flags; + +package body Ortho_Code.X86.Insns is + procedure Link_Stmt (Stmt : O_Enode) + is + use Ortho_Code.Abi; + begin + Set_Stmt_Link (Last_Link, Stmt); + Last_Link := Stmt; + if Debug.Flag_Debug_Insn then + Disp_Stmt (Stmt); + end if; + end Link_Stmt; + + function Get_Reg_Any (Mode : Mode_Type) return O_Reg is + begin + case Mode is + when Mode_I16 .. Mode_I32 + | Mode_U16 .. Mode_U32 + | Mode_P32 => + return R_Any32; + when Mode_I8 + | Mode_U8 + | Mode_B2 => + return R_Any8; + when Mode_U64 + | Mode_I64 => + return R_Any64; + when Mode_F32 + | Mode_F64 => + if Abi.Flag_Sse2 then + return R_Any_Xmm; + else + return R_St0; + end if; + when Mode_P64 + | Mode_X1 + | Mode_Nil + | Mode_Blk => + raise Program_Error; + end case; + end Get_Reg_Any; + + function Get_Reg_Any (Stmt : O_Enode) return O_Reg is + begin + return Get_Reg_Any (Get_Expr_Mode (Stmt)); + end Get_Reg_Any; + + -- Stack slot management. + Stack_Offset : Uns32 := 0; + Stack_Max : Uns32 := 0; + + -- Count how many bytes have been pushed on the stack, during a call. This + -- is used to correctly align the stack for nested calls. + Push_Offset : Uns32 := 0; + + -- STMT is an OE_END statement. + -- Swap Stack_Offset with Max_Stack of STMT. + procedure Swap_Stack_Offset (Blk : O_Dnode) + is + Prev_Offset : Uns32; + begin + Prev_Offset := Get_Block_Max_Stack (Blk); + Set_Block_Max_Stack (Blk, Stack_Offset); + Stack_Offset := Prev_Offset; + end Swap_Stack_Offset; + + procedure Expand_Decls (Block : O_Dnode) + is + Last : O_Dnode; + Decl : O_Dnode; + Decl_Type : O_Tnode; + begin + if Get_Decl_Kind (Block) /= OD_Block then + raise Program_Error; + end if; + Last := Get_Block_Last (Block); + Decl := Block + 1; + while Decl <= Last loop + case Get_Decl_Kind (Decl) is + when OD_Local => + Decl_Type := Get_Decl_Type (Decl); + Stack_Offset := Do_Align (Stack_Offset, Decl_Type); + Stack_Offset := Stack_Offset + Get_Type_Size (Decl_Type); + Set_Local_Offset (Decl, -Int32 (Stack_Offset)); + if Stack_Offset > Stack_Max then + Stack_Max := Stack_Offset; + end if; + when OD_Type + | OD_Const + | OD_Const_Val + | OD_Var + | OD_Function + | OD_Procedure + | OD_Interface + | OD_Body + | OD_Subprg_Ext => + null; + when OD_Block => + Decl := Get_Block_Last (Decl); + end case; + Decl := Decl + 1; + end loop; + end Expand_Decls; + + function Ekind_To_Cc (Stmt : O_Enode; Mode : Mode_Type) return O_Reg + is + Kind : OE_Kind; + begin + Kind := Get_Expr_Kind (Stmt); + case Mode is + when Mode_U8 .. Mode_U64 + | Mode_F32 .. Mode_F64 + | Mode_P32 + | Mode_P64 + | Mode_B2 => + return Ekind_Unsigned_To_Cc (Kind); + when Mode_I8 .. Mode_I64 => + return Ekind_Signed_To_Cc (Kind); + when others => + raise Program_Error; + end case; + end Ekind_To_Cc; + + -- CC is the result of A CMP B. + -- Returns the condition for B CMP A. + function Reverse_Cc (Cc : O_Reg) return O_Reg is + begin + case Cc is + when R_Ult => + return R_Ugt; + when R_Uge => + return R_Ule; + when R_Eq => + return R_Eq; + when R_Ne => + return R_Ne; + when R_Ule => + return R_Uge; + when R_Ugt => + return R_Ult; + when R_Slt => + return R_Sgt; + when R_Sge => + return R_Sle; + when R_Sle => + return R_Sge; + when R_Sgt => + return R_Slt; + when others => + raise Program_Error; + end case; + end Reverse_Cc; + + -- Get the register in which a result of MODE is returned. + function Get_Call_Register (Mode : Mode_Type) return O_Reg is + begin + case Mode is + when Mode_U8 .. Mode_U32 + | Mode_I8 .. Mode_I32 + | Mode_P32 + | Mode_B2 => + return R_Ax; + when Mode_U64 + | Mode_I64 => + return R_Edx_Eax; + when Mode_F32 + | Mode_F64 => + if Abi.Flag_Sse2 and True then + -- Note: this shouldn't be enabled as the svr4 ABI specifies + -- ST0. + return R_Xmm0; + else + return R_St0; + end if; + when Mode_Nil => + return R_None; + when Mode_X1 + | Mode_Blk + | Mode_P64 => + raise Program_Error; + end case; + end Get_Call_Register; + +-- function Ensure_Rm (Stmt : O_Enode) return O_Enode +-- is +-- begin +-- case Get_Expr_Reg (Stmt) is +-- when R_Mem +-- | Regs_Any32 => +-- return Stmt; +-- when others => +-- raise Program_Error; +-- end case; +-- end Ensure_Rm; + +-- function Ensure_Ireg (Stmt : O_Enode) return O_Enode +-- is +-- Reg : O_Reg; +-- begin +-- Reg := Get_Expr_Reg (Stmt); +-- case Reg is +-- when Regs_Any32 +-- | R_Imm => +-- return Stmt; +-- when others => +-- raise Program_Error; +-- end case; +-- end Ensure_Ireg; + + function Insert_Move (Expr : O_Enode; Dest : O_Reg) return O_Enode + is + N : O_Enode; + begin + N := New_Enode (OE_Move, Get_Expr_Mode (Expr), O_Tnode_Null, + Expr, O_Enode_Null); + Set_Expr_Reg (N, Dest); + Link_Stmt (N); + return N; + end Insert_Move; + +-- function Insert_Spill (Expr : O_Enode) return O_Enode +-- is +-- N : O_Enode; +-- begin +-- N := New_Enode (OE_Spill, Get_Expr_Mode (Expr), O_Tnode_Null, +-- Expr, O_Enode_Null); +-- Set_Expr_Reg (N, R_Spill); +-- Link_Stmt (N); +-- return N; +-- end Insert_Spill; + + procedure Error_Gen_Insn (Stmt : O_Enode; Reg : O_Reg) + is + use Ada.Text_IO; + begin + Put_Line ("gen_insn error: cannot match reg " & Abi.Image_Reg (Reg) + & " with stmt " & OE_Kind'Image (Get_Expr_Kind (Stmt))); + raise Program_Error; + end Error_Gen_Insn; + + procedure Error_Gen_Insn (Stmt : O_Enode; Mode : Mode_Type) + is + use Ada.Text_IO; + begin + Put_Line ("gen_insn error: cannot match mode " & Mode_Type'Image (Mode) + & " with stmt " & OE_Kind'Image (Get_Expr_Kind (Stmt)) + & " of mode " & Mode_Type'Image (Get_Expr_Mode (Stmt))); + raise Program_Error; + end Error_Gen_Insn; + + pragma No_Return (Error_Gen_Insn); + + Cur_Block : O_Enode; + + type O_Inum is new Int32; + O_Free : constant O_Inum := 0; + O_Iroot : constant O_Inum := 1; + + + Insn_Num : O_Inum; + + function Get_Insn_Num return O_Inum is + begin + Insn_Num := Insn_Num + 1; + return Insn_Num; + end Get_Insn_Num; + + + type Reg_Info_Type is record + -- Statement number which use this register. + -- This is a distance. + Num : O_Inum; + + -- Statement which produces this value. + -- Used to have more info on this register (such as mode to allocate + -- a spill location). + Stmt : O_Enode; + + -- If set, this register has been used. + -- All callee-saved registers marked must be saved. + Used : Boolean; + end record; + + Init_Reg_Info : constant Reg_Info_Type := (Num => O_Free, + Stmt => O_Enode_Null, + Used => False); + type Reg32_Info_Array is array (Regs_R32) of Reg_Info_Type; + Regs : Reg32_Info_Array := (others => Init_Reg_Info); + + Reg_Cc : Reg_Info_Type := Init_Reg_Info; + + type Fp_Stack_Type is mod 8; + type RegFp_Info_Array is array (Fp_Stack_Type) of Reg_Info_Type; + Fp_Top : Fp_Stack_Type := 0; + Fp_Regs : RegFp_Info_Array; + + type Reg_Xmm_Info_Array is array (Regs_Xmm) of Reg_Info_Type; + Info_Regs_Xmm : Reg_Xmm_Info_Array := (others => Init_Reg_Info); + + function Reg_Used (Reg : Regs_R32) return Boolean is + begin + return Regs (Reg).Used; + end Reg_Used; + + procedure Dump_Reg32_Info (Reg : Regs_R32) + is + use Ada.Text_IO; + use Ortho_Code.Debug.Int32_IO; + use Abi; + begin + Put (Image_Reg (Reg)); + Put (": "); + Put (Int32 (Regs (Reg).Stmt), 0); + Put (", num: "); + Put (Int32 (Regs (Reg).Num), 0); + --Put (", twin: "); + --Put (Image_Reg (Regs (Reg).Twin_Reg)); + --Put (", link: "); + --Put (Image_Reg (Regs (Reg).Link)); + New_Line; + end Dump_Reg32_Info; + + procedure Dump_Regs + is + use Ada.Text_IO; + use Debug.Int32_IO; + begin +-- Put ("free_regs: "); +-- Put (Image_Reg (Free_Regs)); +-- Put (", to_free_regs: "); +-- Put (Image_Reg (To_Free_Regs)); +-- New_Line; + + for I in Regs_R32 loop + Dump_Reg32_Info (I); + end loop; + for I in Fp_Stack_Type loop + Put ("fp" & Fp_Stack_Type'Image (I)); + Put (": "); + Put (Int32 (Fp_Regs (I).Stmt), 0); + New_Line; + end loop; + end Dump_Regs; + + pragma Unreferenced (Dump_Regs); + + procedure Error_Reg (Msg : String; Stmt : O_Enode; Reg : O_Reg) + is + use Ada.Text_IO; + use Ortho_Code.Debug.Int32_IO; + begin + Put ("error reg: "); + Put (Msg); + New_Line; + Put (" stmt: "); + Put (Int32 (Stmt), 0); + Put (", reg: "); + Put (Abi.Image_Reg (Reg)); + New_Line; + --Dump_Regs; + raise Program_Error; + end Error_Reg; + pragma No_Return (Error_Reg); + + -- Free_XX + -- Mark a register as unused. + procedure Free_R32 (Reg : O_Reg) is + begin + if Regs (Reg).Num = O_Free then + raise Program_Error; + end if; + Regs (Reg).Num := O_Free; + end Free_R32; + + procedure Free_Fp is + begin + if Fp_Regs (Fp_Top).Stmt = O_Enode_Null then + raise Program_Error; + end if; + Fp_Regs (Fp_Top).Stmt := O_Enode_Null; + Fp_Top := Fp_Top + 1; + end Free_Fp; + + procedure Free_Cc is + begin + if Reg_Cc.Num = O_Free then + raise Program_Error; + end if; + Reg_Cc.Num := O_Free; + end Free_Cc; + + procedure Free_Xmm (Reg : O_Reg) is + begin + if Info_Regs_Xmm (Reg).Num = O_Free then + raise Program_Error; + end if; + Info_Regs_Xmm (Reg).Num := O_Free; + end Free_Xmm; + + -- Allocate a stack slot for spilling. + procedure Alloc_Spill (N : O_Enode) + is + Mode : Mode_Type; + begin + Mode := Get_Expr_Mode (N); + -- Allocate on the stack. + Stack_Offset := Types.Do_Align (Stack_Offset, Mode); + Stack_Offset := Stack_Offset + Types.Get_Mode_Size (Mode); + if Stack_Offset > Stack_Max then + Stack_Max := Stack_Offset; + end if; + Set_Spill_Info (N, -Int32 (Stack_Offset)); + end Alloc_Spill; + + -- Insert a spill statement after ORIG: will save register(s) allocated by + -- ORIG. + -- Return the register(s) spilt (There might be several registers if + -- ORIG uses a R64 register). + function Insert_Spill (Orig : O_Enode) return O_Reg + is + N : O_Enode; + Mode : Mode_Type; + Reg_Orig : O_Reg; + begin + -- Add a spill statement. + Mode := Get_Expr_Mode (Orig); + N := New_Enode (OE_Spill, Mode, O_Tnode_Null, Orig, O_Enode_Null); + Alloc_Spill (N); + + -- Insert the statement after the one that set the register + -- being spilled. + -- That's very important to be able to easily find the spill location, + -- when it will be reloaded. + if Orig = Abi.Last_Link then + Link_Stmt (N); + else + Set_Stmt_Link (N, Get_Stmt_Link (Orig)); + Set_Stmt_Link (Orig, N); + end if; + Reg_Orig := Get_Expr_Reg (Orig); + Set_Expr_Reg (N, Reg_Orig); + Set_Expr_Reg (Orig, R_Spill); + return Reg_Orig; + end Insert_Spill; + + procedure Spill_R32 (Reg : Regs_R32) + is + Reg_Orig : O_Reg; + begin + if Regs (Reg).Num = O_Free then + -- This register was not allocated. + raise Program_Error; + end if; + + Reg_Orig := Insert_Spill (Regs (Reg).Stmt); + + -- Free the register. + case Reg_Orig is + when Regs_R32 => + if Reg_Orig /= Reg then + raise Program_Error; + end if; + Free_R32 (Reg); + when Regs_R64 => + Free_R32 (Get_R64_High (Reg_Orig)); + Free_R32 (Get_R64_Low (Reg_Orig)); + when others => + raise Program_Error; + end case; + end Spill_R32; + + procedure Alloc_R32 (Reg : O_Reg; Stmt : O_Enode; Num : O_Inum) is + begin + if Regs (Reg).Num /= O_Free then + Spill_R32 (Reg); + end if; + Regs (Reg) := (Num => Num, Stmt => Stmt, Used => True); + end Alloc_R32; + + procedure Clobber_R32 (Reg : O_Reg) is + begin + if Regs (Reg).Num /= O_Free then + Spill_R32 (Reg); + end if; + end Clobber_R32; + + procedure Alloc_Fp (Stmt : O_Enode) + is + begin + Fp_Top := Fp_Top - 1; + + if Fp_Regs (Fp_Top).Stmt /= O_Enode_Null then + -- Must spill-out. + raise Program_Error; + end if; + Fp_Regs (Fp_Top).Stmt := Stmt; + end Alloc_Fp; + + procedure Alloc_R64 (Reg : O_Reg; Stmt : O_Enode; Num : O_Inum) + is + Rh, Rl : O_Reg; + begin + Rl := Get_R64_Low (Reg); + Rh := Get_R64_High (Reg); + if Regs (Rl).Num /= O_Free + or Regs (Rh).Num /= O_Free + then + Spill_R32 (Rl); + end if; + Regs (Rh) := (Num => Num, Stmt => Stmt, Used => True); + Regs (Rl) := (Num => Num, Stmt => Stmt, Used => True); + end Alloc_R64; + + procedure Alloc_Cc (Stmt : O_Enode; Num : O_Inum) is + begin + if Reg_Cc.Num /= O_Free then + raise Program_Error; + end if; + Reg_Cc := (Num => Num, Stmt => Stmt, Used => True); + end Alloc_Cc; + + procedure Spill_Xmm (Reg : Regs_Xmm) + is + Reg_Orig : O_Reg; + begin + if Info_Regs_Xmm (Reg).Num = O_Free then + -- This register was not allocated. + raise Program_Error; + end if; + + Reg_Orig := Insert_Spill (Info_Regs_Xmm (Reg).Stmt); + + -- Free the register. + if Reg_Orig /= Reg then + raise Program_Error; + end if; + Free_Xmm (Reg); + end Spill_Xmm; + + procedure Alloc_Xmm (Reg : Regs_Xmm; Stmt : O_Enode; Num : O_Inum) is + begin + if Info_Regs_Xmm (Reg).Num /= O_Free then + Spill_Xmm (Reg); + end if; + Info_Regs_Xmm (Reg) := (Num => Num, Stmt => Stmt, Used => True); + end Alloc_Xmm; + + procedure Clobber_Xmm (Reg : Regs_Xmm) is + begin + if Info_Regs_Xmm (Reg).Num /= O_Free then + Spill_Xmm (Reg); + end if; + end Clobber_Xmm; + pragma Unreferenced (Clobber_Xmm); + + function Alloc_Reg (Reg : O_Reg; Stmt : O_Enode; Num : O_Inum) return O_Reg + is + Best_Reg : O_Reg; + Best_Num : O_Inum; + begin + case Reg is + when Regs_R32 => + Alloc_R32 (Reg, Stmt, Num); + return Reg; + when Regs_R64 => + Alloc_R64 (Reg, Stmt, Num); + return Reg; + when R_St0 => + Alloc_Fp (Stmt); + return Reg; + when Regs_Xmm => + Alloc_Xmm (Reg, Stmt, Num); + return Reg; + when R_Any32 => + Best_Num := O_Inum'Last; + Best_Reg := R_None; + for I in Regs_R32 loop + if I not in R_Sp .. R_Bp then + if Regs (I).Num = O_Free then + Alloc_R32 (I, Stmt, Num); + return I; + elsif Regs (I).Num <= Best_Num then + Best_Reg := I; + Best_Num := Regs (I).Num; + end if; + end if; + end loop; + Alloc_R32 (Best_Reg, Stmt, Num); + return Best_Reg; + when R_Any8 => + Best_Num := O_Inum'Last; + Best_Reg := R_None; + for I in Regs_R8 loop + if Regs (I).Num = O_Free then + Alloc_R32 (I, Stmt, Num); + return I; + elsif Regs (I).Num <= Best_Num then + Best_Reg := I; + Best_Num := Regs (I).Num; + end if; + end loop; + Alloc_R32 (Best_Reg, Stmt, Num); + return Best_Reg; + when R_Any64 => + declare + Rh, Rl : O_Reg; + begin + Best_Num := O_Inum'Last; + Best_Reg := R_None; + for I in Regs_R64 loop + Rh := Get_R64_High (I); + Rl := Get_R64_Low (I); + if Regs (Rh).Num = O_Free + and then Regs (Rl).Num = O_Free + then + Alloc_R64 (I, Stmt, Num); + return I; + elsif Regs (Rh).Num <= Best_Num + and Regs (Rl).Num <= Best_Num + then + Best_Reg := I; + Best_Num := O_Inum'Max (Regs (Rh).Num, + Regs (Rl).Num); + end if; + end loop; + Alloc_R64 (Best_Reg, Stmt, Num); + return Best_Reg; + end; + when R_Any_Xmm => + Best_Num := O_Inum'Last; + Best_Reg := R_None; + for I in Regs_X86_Xmm loop + if Info_Regs_Xmm (I).Num = O_Free then + Alloc_Xmm (I, Stmt, Num); + return I; + elsif Info_Regs_Xmm (I).Num <= Best_Num then + Best_Reg := I; + Best_Num := Info_Regs_Xmm (I).Num; + end if; + end loop; + Alloc_Xmm (Best_Reg, Stmt, Num); + return Best_Reg; + when others => + Error_Reg ("alloc_reg: unknown reg", O_Enode_Null, Reg); + raise Program_Error; + end case; + end Alloc_Reg; + + function Gen_Reload (Spill : O_Enode; Reg : O_Reg; Num : O_Inum) + return O_Enode + is + N : O_Enode; + Mode : Mode_Type; + begin + -- Add a reload node. + Mode := Get_Expr_Mode (Spill); + N := New_Enode (OE_Reload, Mode, O_Tnode_Null, Spill, O_Enode_Null); + -- Note: this does not use a just-freed register, since + -- this case only occurs at the first call. + Set_Expr_Reg (N, Alloc_Reg (Reg, N, Num)); + Link_Stmt (N); + return N; + end Gen_Reload; + + function Reload (Expr : O_Enode; Dest : O_Reg; Num : O_Inum) return O_Enode + is + Reg : O_Reg; + Spill : O_Enode; + begin + Reg := Get_Expr_Reg (Expr); + case Reg is + when R_Spill => + -- Restore the register between the statement and the spill. + Spill := Get_Stmt_Link (Expr); + Set_Expr_Reg (Expr, Get_Expr_Reg (Spill)); + Set_Expr_Reg (Spill, R_Spill); + case Dest is + when R_Mem + | R_Irm + | R_Rm => + return Spill; + when Regs_R32 + | R_Any32 + | Regs_R64 + | R_Any64 + | R_Any8 => + return Gen_Reload (Spill, Dest, Num); + when R_Sib => + return Gen_Reload (Spill, R_Any32, Num); + when R_Ir => + return Gen_Reload (Spill, Get_Reg_Any (Expr), Num); + when others => + Error_Reg ("reload: unhandled dest in spill", Expr, Dest); + end case; + when Regs_R32 => + case Dest is + when R_Irm + | R_Rm + | R_Ir + | R_Any32 + | R_Any8 + | R_Sib => + return Expr; + when Regs_R32 => + if Dest = Reg then + return Expr; + end if; + Free_R32 (Reg); + Spill := Insert_Move (Expr, Dest); + Alloc_R32 (Dest, Spill, Num); + return Spill; + when others => + Error_Reg ("reload: unhandled dest in R32", Expr, Dest); + end case; + when Regs_R64 => + return Expr; + when R_St0 => + return Expr; + when Regs_Xmm => + return Expr; + when R_Mem => + if Get_Expr_Kind (Expr) = OE_Indir then + Set_Expr_Operand (Expr, + Reload (Get_Expr_Operand (Expr), R_Sib, Num)); + return Expr; + else + raise Program_Error; + end if; + when R_B_Off + | R_B_I + | R_I_Off + | R_Sib => + case Get_Expr_Kind (Expr) is + when OE_Add => + Set_Expr_Left + (Expr, Reload (Get_Expr_Left (Expr), R_Any32, Num)); + Set_Expr_Right + (Expr, Reload (Get_Expr_Right (Expr), R_Any32, Num)); + return Expr; + when OE_Addrl => + Spill := Get_Addrl_Frame (Expr); + if Spill /= O_Enode_Null then + Set_Addrl_Frame (Expr, Reload (Spill, R_Any32, Num)); + end if; + return Expr; + when others => + Error_Reg ("reload: unhandle expr in b_off", Expr, Dest); + end case; + when R_I => + Set_Expr_Left (Expr, Reload (Get_Expr_Left (Expr), R_Any32, Num)); + return Expr; + when R_Imm => + return Expr; + when others => + Error_Reg ("reload: unhandled reg", Expr, Reg); + end case; + end Reload; + + procedure Renum_Reg (Reg : O_Reg; Stmt : O_Enode; Num : O_Inum) is + begin + case Reg is + when Regs_R32 => + Regs (Reg).Num := Num; + Regs (Reg).Stmt := Stmt; + when Regs_Cc => + Reg_Cc.Num := Num; + Reg_Cc.Stmt := Stmt; + when R_St0 => + null; + when Regs_R64 => + declare + L, H : O_Reg; + begin + L := Get_R64_Low (Reg); + Regs (L).Num := Num; + Regs (L).Stmt := Stmt; + H := Get_R64_High (Reg); + Regs (H).Num := Num; + Regs (H).Stmt := Stmt; + end; + when others => + Error_Reg ("renum_reg", Stmt, Reg); + end case; + end Renum_Reg; + + procedure Free_Insn_Regs (Insn : O_Enode) + is + R : O_Reg; + begin + R := Get_Expr_Reg (Insn); + case R is + when R_Ax + | R_Bx + | R_Cx + | R_Dx + | R_Si + | R_Di => + Free_R32 (R); + when R_Sp + | R_Bp => + null; + when R_St0 => + Free_Fp; + when Regs_Xmm => + Free_Xmm (R); + when Regs_R64 => + Free_R32 (Get_R64_High (R)); + Free_R32 (Get_R64_Low (R)); + when R_Mem => + if Get_Expr_Kind (Insn) = OE_Indir then + Free_Insn_Regs (Get_Expr_Operand (Insn)); + else + raise Program_Error; + end if; + when R_B_Off + | R_B_I + | R_I_Off + | R_Sib => + case Get_Expr_Kind (Insn) is + when OE_Add => + Free_Insn_Regs (Get_Expr_Left (Insn)); + Free_Insn_Regs (Get_Expr_Right (Insn)); + when OE_Addrl => + if Get_Addrl_Frame (Insn) /= O_Enode_Null then + Free_Insn_Regs (Get_Addrl_Frame (Insn)); + end if; + when others => + raise Program_Error; + end case; + when R_I => + Free_Insn_Regs (Get_Expr_Left (Insn)); + when R_Imm => + null; + when R_Spill => + null; + when others => + Error_Reg ("free_insn_regs: unknown reg", Insn, R); + end case; + end Free_Insn_Regs; + + procedure Insert_Reg (Mode : Mode_Type) + is + N : O_Enode; + Num : O_Inum; + begin + Num := Get_Insn_Num; + N := New_Enode (OE_Reg, Mode, O_Tnode_Null, + O_Enode_Null, O_Enode_Null); + Set_Expr_Reg (N, Alloc_Reg (Get_Reg_Any (Mode), N, Num)); + Link_Stmt (N); + Free_Insn_Regs (N); + end Insert_Reg; + + procedure Insert_Arg (Expr : O_Enode) + is + N : O_Enode; + begin + Free_Insn_Regs (Expr); + N := New_Enode (OE_Arg, Get_Expr_Mode (Expr), O_Tnode_Null, + Expr, O_Enode_Null); + Set_Expr_Reg (N, R_None); + Link_Stmt (N); + end Insert_Arg; + + function Insert_Intrinsic (Stmt : O_Enode; Reg : O_Reg; Num : O_Inum) + return O_Enode + is + N : O_Enode; + Op : Int32; + Mode : Mode_Type; + begin + Mode := Get_Expr_Mode (Stmt); + case Get_Expr_Kind (Stmt) is + when OE_Mul_Ov => + case Mode is + when Mode_U64 => + Op := Intrinsic_Mul_Ov_U64; + when Mode_I64 => + Op := Intrinsic_Mul_Ov_I64; + when others => + raise Program_Error; + end case; + when OE_Div_Ov => + case Mode is + when Mode_U64 => + Op := Intrinsic_Div_Ov_U64; + when Mode_I64 => + Op := Intrinsic_Div_Ov_I64; + when others => + raise Program_Error; + end case; + when OE_Mod => + case Mode is + when Mode_U64 => + Op := Intrinsic_Mod_Ov_U64; + when Mode_I64 => + Op := Intrinsic_Mod_Ov_I64; + when others => + raise Program_Error; + end case; + when OE_Rem => + case Mode is + when Mode_U64 => + -- For unsigned, MOD == REM. + Op := Intrinsic_Mod_Ov_U64; + when Mode_I64 => + Op := Intrinsic_Rem_Ov_I64; + when others => + raise Program_Error; + end case; + when others => + raise Program_Error; + end case; + + -- Save caller-saved registers. + Clobber_R32 (R_Ax); + Clobber_R32 (R_Dx); + Clobber_R32 (R_Cx); + + N := New_Enode (OE_Intrinsic, Mode, O_Tnode_Null, + O_Enode (Op), O_Enode_Null); + Set_Expr_Reg (N, Alloc_Reg (Reg, N, Num)); + Link_Stmt (N); + return N; + end Insert_Intrinsic; + + -- REG is mandatory: the result of STMT must satisfy the REG constraint. + function Gen_Insn (Stmt : O_Enode; Reg : O_Reg; Pnum : O_Inum) + return O_Enode; + + function Gen_Conv_From_Fp_Insn (Stmt : O_Enode; + Reg : O_Reg; + Pnum : O_Inum) + return O_Enode + is + Num : O_Inum; + Left : O_Enode; + begin + Left := Get_Expr_Operand (Stmt); + Num := Get_Insn_Num; + Left := Gen_Insn (Left, R_St0, Num); + Free_Insn_Regs (Left); + Set_Expr_Operand (Stmt, Left); + case Reg is + when Regs_R32 + | R_Any32 + | Regs_R64 + | R_Any64 => + Set_Expr_Reg (Stmt, Alloc_Reg (Reg, Stmt, Pnum)); + when R_Rm + | R_Irm + | R_Ir => + Set_Expr_Reg (Stmt, Alloc_Reg (Get_Reg_Any (Stmt), Stmt, Pnum)); + when others => + raise Program_Error; + end case; + Link_Stmt (Stmt); + return Stmt; +-- declare +-- Spill : O_Enode; +-- begin +-- Num := Get_Insn_Num; +-- Left := Gen_Insn (Left, R_St0, Num); +-- Set_Expr_Operand (Stmt, Left); +-- Set_Expr_Reg (Stmt, R_Spill); +-- Free_Insn_Regs (Left); +-- Link_Stmt (Stmt); +-- Spill := Insert_Spill (Stmt); +-- case Reg is +-- when R_Any32 +-- | Regs_R32 => +-- return Gen_Reload (Spill, Reg, Pnum); +-- when R_Ir => +-- return Gen_Reload (Spill, R_Any32, Pnum); +-- when R_Rm +-- | R_Irm => +-- return Spill; +-- when others => +-- Error_Reg +-- ("gen_insn:oe_conv(fp)", Stmt, Reg); +-- end case; +-- end; + end Gen_Conv_From_Fp_Insn; + + function Gen_Call (Stmt : O_Enode; Reg : O_Reg; Pnum : O_Inum) + return O_Enode + is + use Interfaces; + Left : O_Enode; + Reg_Res : O_Reg; + Subprg : O_Dnode; + Push_Size : Uns32; + Pad : Uns32; + Res_Stmt : O_Enode; + begin + -- Emit Setup_Frame (to align stack). + Subprg := Get_Call_Subprg (Stmt); + Push_Size := Uns32 (Get_Subprg_Stack (Subprg)); + -- Pad the stack if necessary. + Pad := (Push_Size + Push_Offset) and Uns32 (Flags.Stack_Boundary - 1); + if Pad /= 0 then + Pad := Uns32 (Flags.Stack_Boundary) - Pad; + Link_Stmt (New_Enode (OE_Stack_Adjust, Mode_Nil, O_Tnode_Null, + O_Enode (Pad), O_Enode_Null)); + end if; + -- The stack has been adjusted by Pad bytes. + Push_Offset := Push_Offset + Pad; + + -- Generate code for arguments (if any). + Left := Get_Arg_Link (Stmt); + if Left /= O_Enode_Null then + Left := Gen_Insn (Left, R_None, Pnum); + end if; + + -- Clobber registers. + Clobber_R32 (R_Ax); + Clobber_R32 (R_Dx); + Clobber_R32 (R_Cx); + -- FIXME: fp regs. + + -- Add the call. + Reg_Res := Get_Call_Register (Get_Expr_Mode (Stmt)); + Set_Expr_Reg (Stmt, Reg_Res); + Link_Stmt (Stmt); + Res_Stmt := Stmt; + + if Push_Size + Pad /= 0 then + Res_Stmt := + New_Enode (OE_Stack_Adjust, Get_Expr_Mode (Stmt), O_Tnode_Null, + O_Enode (-Int32 (Push_Size + Pad)), O_Enode_Null); + Set_Expr_Reg (Res_Stmt, Reg_Res); + Link_Stmt (Res_Stmt); + end if; + + -- The stack has been restored (just after the call). + Push_Offset := Push_Offset - (Push_Size + Pad); + + case Reg is + when R_Any32 + | R_Any64 + | R_Any8 + | R_Irm + | R_Rm + | R_Ir + | R_Sib + | R_Ax + | R_St0 + | R_Edx_Eax => + Reg_Res := Alloc_Reg (Reg_Res, Res_Stmt, Pnum); + return Res_Stmt; + when R_Any_Cc => + -- Move to register. + -- (use the 'test' instruction). + Alloc_Cc (Res_Stmt, Pnum); + return Insert_Move (Res_Stmt, R_Ne); + when R_None => + if Reg_Res /= R_None then + raise Program_Error; + end if; + return Res_Stmt; + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + end Gen_Call; + + function Gen_Insn (Stmt : O_Enode; Reg : O_Reg; Pnum : O_Inum) + return O_Enode + is + Kind : OE_Kind; + + Left : O_Enode; + Right : O_Enode; + + Reg1 : O_Reg; + -- P_Reg : O_Reg; + Reg_L : O_Reg; + Reg_Res : O_Reg; + + Num : O_Inum; + begin + Kind := Get_Expr_Kind (Stmt); + case Kind is + when OE_Addrl => + Right := Get_Addrl_Frame (Stmt); + if Right /= O_Enode_Null then + Num := Get_Insn_Num; + Right := Gen_Insn (Right, R_Any32, Num); + Set_Addrl_Frame (Stmt, Right); + else + Num := O_Free; + end if; + case Reg is + when R_Sib => + Set_Expr_Reg (Stmt, R_B_Off); + return Stmt; + when R_Irm + | R_Ir => + if Right /= O_Enode_Null then + Free_Insn_Regs (Right); + end if; + Set_Expr_Reg (Stmt, Alloc_Reg (R_Any32, Stmt, Pnum)); + Link_Stmt (Stmt); + return Stmt; + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + when OE_Addrg => + case Reg is + when R_Sib + | R_Irm + | R_Ir => + Set_Expr_Reg (Stmt, R_Imm); + return Stmt; + when R_Any32 + | Regs_R32 => + Set_Expr_Reg (Stmt, Reg); + Link_Stmt (Stmt); + return Stmt; + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + when OE_Indir => + Left := Get_Expr_Operand (Stmt); + case Reg is + when R_Irm + | R_Rm => + Left := Gen_Insn (Left, R_Sib, Pnum); + Set_Expr_Reg (Stmt, R_Mem); + Set_Expr_Operand (Stmt, Left); + when R_Ir + | R_Sib + | R_I_Off => + Num := Get_Insn_Num; + Left := Gen_Insn (Left, R_Sib, Num); + Reg1 := Get_Reg_Any (Stmt); + if Reg1 = R_Any64 then + Reg1 := Alloc_Reg (Reg1, Stmt, Pnum); + Free_Insn_Regs (Left); + else + Free_Insn_Regs (Left); + Reg1 := Alloc_Reg (Reg1, Stmt, Pnum); + end if; + Set_Expr_Reg (Stmt, Reg1); + Set_Expr_Operand (Stmt, Left); + Link_Stmt (Stmt); + when Regs_R32 + | R_Any32 + | R_Any8 + | Regs_Fp => + Num := Get_Insn_Num; + Left := Gen_Insn (Left, R_Sib, Num); + Free_Insn_Regs (Left); + Set_Expr_Reg (Stmt, Alloc_Reg (Reg, Stmt, Pnum)); + Set_Expr_Operand (Stmt, Left); + Link_Stmt (Stmt); + when Regs_R64 + | R_Any64 => + -- Avoid overwritting: + -- Eg: axdx = indir (ax) + -- axdx = indir (ax+dx) + Num := Get_Insn_Num; + Left := Gen_Insn (Left, R_Sib, Num); + Set_Expr_Reg (Stmt, Alloc_Reg (Reg, Stmt, Pnum)); + Left := Reload (Left, R_Sib, Num); + Free_Insn_Regs (Left); + Set_Expr_Operand (Stmt, Left); + Link_Stmt (Stmt); + when R_Any_Cc => + Num := Get_Insn_Num; + Left := Gen_Insn (Left, R_Sib, Num); + -- Generate a cmp $1, XX + Set_Expr_Reg (Stmt, R_Eq); + Set_Expr_Operand (Stmt, Left); + Free_Insn_Regs (Left); + Link_Stmt (Stmt); + Alloc_Cc (Stmt, Pnum); + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + return Stmt; + when OE_Conv_Ptr => + -- Delete nops. + return Gen_Insn (Get_Expr_Operand (Stmt), Reg, Pnum); + when OE_Const => + case Get_Expr_Mode (Stmt) is + when Mode_U8 .. Mode_U32 + | Mode_I8 .. Mode_I32 + | Mode_P32 + | Mode_B2 => + case Reg is + when R_Imm + | Regs_Imm32 => + Set_Expr_Reg (Stmt, R_Imm); + when Regs_R32 + | R_Any32 + | R_Any8 => + Set_Expr_Reg (Stmt, Alloc_Reg (Reg, Stmt, Pnum)); + Link_Stmt (Stmt); + when R_Rm => + Set_Expr_Reg + (Stmt, Alloc_Reg (Get_Reg_Any (Stmt), Stmt, Pnum)); + Link_Stmt (Stmt); + when R_Any_Cc => + Num := Get_Insn_Num; + Set_Expr_Reg (Stmt, Alloc_Reg (R_Any8, Stmt, Num)); + Link_Stmt (Stmt); + Free_Insn_Regs (Stmt); + Right := Insert_Move (Stmt, R_Ne); + Alloc_Cc (Right, Pnum); + return Right; + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + when Mode_F32 + | Mode_F64 => + case Reg is + when R_Ir + | R_Irm + | R_Rm + | R_St0 => + Num := Get_Insn_Num; + if Reg = R_St0 or not Abi.Flag_Sse2 then + Reg1 := R_St0; + else + Reg1 := R_Any_Xmm; + end if; + Set_Expr_Reg (Stmt, Alloc_Reg (Reg1, Stmt, Num)); + Link_Stmt (Stmt); + when others => + raise Program_Error; + end case; + when Mode_U64 + | Mode_I64 => + case Reg is + when R_Irm + | R_Ir + | R_Rm => + Set_Expr_Reg (Stmt, R_Imm); + when R_Mem => + Set_Expr_Reg (Stmt, R_Mem); + when Regs_R64 + | R_Any64 => + Set_Expr_Reg (Stmt, Alloc_Reg (Reg, Stmt, Pnum)); + Link_Stmt (Stmt); + when others => + raise Program_Error; + end case; + when others => + raise Program_Error; + end case; + return Stmt; + when OE_Alloca => + -- Roughly speaking, emited code is: (MASK is a constant). + -- VAL := (VAL + MASK) & ~MASK + -- SP := SP - VAL + -- res <- SP + Left := Get_Expr_Operand (Stmt); + case Reg is + when R_Ir + | R_Irm + | R_Any32 => + Num := Get_Insn_Num; + if X86.Flags.Flag_Alloca_Call then + Reg_L := R_Ax; + else + Reg_L := R_Any32; + end if; + Left := Gen_Insn (Left, Reg_L, Num); + Set_Expr_Operand (Stmt, Left); + Link_Stmt (Left); + Free_Insn_Regs (Left); + Set_Expr_Reg (Stmt, Alloc_Reg (Reg_L, Stmt, Pnum)); + Link_Stmt (Stmt); + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + return Stmt; + + when OE_Kind_Cmp => + -- Return LEFT cmp RIGHT, ie compute RIGHT - LEFT + Num := Get_Insn_Num; + Left := Get_Expr_Left (Stmt); + Reg_L := Get_Reg_Any (Left); + Left := Gen_Insn (Left, Reg_L, Num); + + Right := Get_Expr_Right (Stmt); + case Get_Expr_Mode (Right) is + when Mode_F32 + | Mode_F64 => + Reg1 := R_St0; + when others => + Reg1 := R_Irm; + end case; + Right := Gen_Insn (Right, Reg1, Num); + + -- FIXME: what about if right was spilled out of FP regs ? + -- (it is reloaded in reverse). + Left := Reload (Left, Reg_L, Num); + + Set_Expr_Right (Stmt, Right); + Set_Expr_Left (Stmt, Left); + + Link_Stmt (Stmt); + + Reg_Res := Ekind_To_Cc (Stmt, Get_Expr_Mode (Left)); + case Get_Expr_Mode (Left) is + when Mode_F32 + | Mode_F64 => + Reg_Res := Reverse_Cc (Reg_Res); + when Mode_I64 => + -- I64 is a little bit special... + Reg_Res := Get_R64_High (Get_Expr_Reg (Left)); + if Reg_Res not in Regs_R8 then + Reg_Res := R_Nil; + for I in Regs_R8 loop + if Regs (I).Num = O_Free then + Reg_Res := I; + exit; + end if; + end loop; + if Reg_Res = R_Nil then + -- FIXME: to be handled. + -- Can this happen ? + raise Program_Error; + end if; + end if; + + Free_Insn_Regs (Left); + Free_Insn_Regs (Right); + + Set_Expr_Reg (Stmt, Reg_Res); + case Reg is + when R_Any_Cc => + Right := Insert_Move (Stmt, R_Ne); + Alloc_Cc (Right, Pnum); + return Right; + when R_Any8 + | Regs_R8 + | R_Irm + | R_Ir + | R_Rm => + Reg_Res := Alloc_Reg (Reg_Res, Stmt, Pnum); + return Stmt; + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + when others => + null; + end case; + Set_Expr_Reg (Stmt, Reg_Res); + + Free_Insn_Regs (Left); + Free_Insn_Regs (Right); + + case Reg is + when R_Any_Cc => + Alloc_Cc (Stmt, Pnum); + return Stmt; + when R_Any8 + | Regs_R8 => + Reg_Res := Alloc_Reg (Reg, Stmt, Pnum); + return Insert_Move (Stmt, Reg_Res); + when R_Irm + | R_Ir + | R_Rm => + Reg_Res := Alloc_Reg (R_Any8, Stmt, Pnum); + return Insert_Move (Stmt, Reg_Res); + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + when OE_Add => + declare + R_L : O_Reg; + R_R : O_Reg; + begin + Left := Gen_Insn (Get_Expr_Left (Stmt), R_Sib, Pnum); + Right := Gen_Insn (Get_Expr_Right (Stmt), R_Sib, Pnum); + Left := Reload (Left, R_Sib, Pnum); + Set_Expr_Right (Stmt, Right); + Set_Expr_Left (Stmt, Left); + R_L := Get_Expr_Reg (Left); + R_R := Get_Expr_Reg (Right); + -- Results can be: Reg, R_B_Off, R_Sib, R_Imm, R_B_I + case R_L is + when R_Any32 + | Regs_R32 => + case R_R is + when R_Imm => + Set_Expr_Reg (Stmt, R_B_Off); + when R_B_Off + | R_I + | R_I_Off => + Set_Expr_Reg (Stmt, R_Sib); + when R_Any32 + | Regs_R32 => + Set_Expr_Reg (Stmt, R_B_I); + when others => + Error_Gen_Insn (Stmt, R_R); + end case; + when R_Imm => + case R_R is + when R_Imm => + Set_Expr_Reg (Stmt, R_Imm); + when R_Any32 + | Regs_R32 + | R_B_Off => + Set_Expr_Reg (Stmt, R_B_Off); + when R_I + | R_I_Off => + Set_Expr_Reg (Stmt, R_I_Off); + when others => + Error_Gen_Insn (Stmt, R_R); + end case; + when R_B_Off => + case R_R is + when R_Imm => + Set_Expr_Reg (Stmt, R_B_Off); + when R_Any32 + | Regs_R32 + | R_I => + Set_Expr_Reg (Stmt, R_Sib); + when others => + Error_Gen_Insn (Stmt, R_R); + end case; + when R_I_Off => + case R_R is + when R_Imm => + Set_Expr_Reg (Stmt, R_I_Off); + when R_Any32 + | Regs_R32 => + Set_Expr_Reg (Stmt, R_Sib); + when others => + Error_Gen_Insn (Stmt, R_R); + end case; + when R_I => + case R_R is + when R_Imm + | Regs_R32 + | R_B_Off => + Set_Expr_Reg (Stmt, R_Sib); + when others => + Error_Gen_Insn (Stmt, R_R); + end case; + when R_Sib + | R_B_I => + if R_R = R_Imm then + Set_Expr_Reg (Stmt, R_Sib); + else + Num := Get_Insn_Num; + Free_Insn_Regs (Left); + Set_Expr_Reg (Left, Alloc_Reg (R_Any32, Left, Num)); + Link_Stmt (Left); + case R_R is + when R_Any32 + | Regs_R32 + | R_I => + Set_Expr_Reg (Stmt, R_B_I); + when others => + Error_Gen_Insn (Stmt, R_R); + end case; + end if; + when others => + Error_Gen_Insn (Stmt, R_L); + end case; + + case Reg is + when R_Sib => + null; + when R_Ir + | R_Irm => + if Get_Expr_Reg (Stmt) /= R_Imm then + Set_Expr_Reg (Stmt, Alloc_Reg (R_Any32, Stmt, Pnum)); + Free_Insn_Regs (Left); + Free_Insn_Regs (Right); + Link_Stmt (Stmt); + end if; + when R_Any32 + | Regs_R32 => + Set_Expr_Reg (Stmt, Alloc_Reg (Reg, Stmt, Pnum)); + Link_Stmt (Stmt); + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + end; + return Stmt; + when OE_Mul => + Num := Get_Insn_Num; + Left := Gen_Insn (Get_Expr_Left (Stmt), R_Ax, Num); + Set_Expr_Left (Stmt, Left); + + Right := Gen_Insn (Get_Expr_Right (Stmt), R_Any32, Num); + if Get_Expr_Kind (Right) /= OE_Const then + raise Program_Error; + end if; + Set_Expr_Right (Stmt, Right); + + Free_Insn_Regs (Left); + Free_Insn_Regs (Right); + Clobber_R32 (R_Dx); + Set_Expr_Reg (Stmt, Alloc_Reg (R_Ax, Stmt, Pnum)); + case Reg is + when R_Sib + | R_B_Off => + null; + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + Link_Stmt (Stmt); + return Stmt; + when OE_Shl => + Num := Get_Insn_Num; + Right := Get_Expr_Right (Stmt); + if Get_Expr_Kind (Right) /= OE_Const then + Right := Gen_Insn (Right, R_Cx, Num); + else + Right := Gen_Insn (Right, R_Imm, Num); + end if; + Left := Get_Expr_Left (Stmt); + Reg1 := Get_Reg_Any (Stmt); + Left := Gen_Insn (Left, Reg1, Pnum); + if Get_Expr_Kind (Right) /= OE_Const then + Right := Reload (Right, R_Cx, Num); + end if; + Left := Reload (Left, Reg1, Pnum); + Set_Expr_Left (Stmt, Left); + Set_Expr_Right (Stmt, Right); + if Reg = R_Sib + and then Get_Expr_Kind (Right) = OE_Const + and then Get_Expr_Low (Right) in 0 .. 3 + then + Set_Expr_Reg (Stmt, R_I); + else + Link_Stmt (Stmt); + Set_Expr_Reg (Stmt, Get_Expr_Reg (Left)); + Free_Insn_Regs (Right); + end if; + return Stmt; + + when OE_Add_Ov + | OE_Sub_Ov + | OE_And + | OE_Xor + | OE_Or => + -- Accepted is: R with IMM or R/M + Num := Get_Insn_Num; + Right := Get_Expr_Right (Stmt); + Left := Get_Expr_Left (Stmt); + case Reg is + when R_Irm + | R_Rm + | R_Ir + | R_Sib => + Right := Gen_Insn (Right, R_Irm, Num); + Reg1 := Get_Reg_Any (Stmt); + Left := Gen_Insn (Left, Reg1, Num); + Right := Reload (Right, R_Irm, Num); + Left := Reload (Left, Reg1, Num); + Reg_Res := Get_Expr_Reg (Left); + when R_Any_Cc => + Right := Gen_Insn (Right, R_Irm, Num); + Left := Gen_Insn (Left, R_Any8, Num); + Reg_Res := R_Ne; + Alloc_Cc (Stmt, Num); + Free_Insn_Regs (Left); + when R_Any32 + | Regs_R32 + | R_Any8 + | R_Any64 + | Regs_R64 + | Regs_Fp => + Right := Gen_Insn (Right, R_Irm, Num); + Left := Gen_Insn (Left, Reg, Num); + Right := Reload (Right, R_Irm, Num); + Left := Reload (Left, Reg, Num); + Reg_Res := Get_Expr_Reg (Left); + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + Set_Expr_Right (Stmt, Right); + Set_Expr_Left (Stmt, Left); + Set_Expr_Reg (Stmt, Reg_Res); + Renum_Reg (Reg_Res, Stmt, Pnum); + Link_Stmt (Stmt); + Free_Insn_Regs (Right); + return Stmt; + + when OE_Mod + | OE_Rem + | OE_Mul_Ov + | OE_Div_Ov => + declare + Mode : Mode_Type; + begin + Num := Get_Insn_Num; + Mode := Get_Expr_Mode (Stmt); + Left := Get_Expr_Left (Stmt); + Right := Get_Expr_Right (Stmt); + case Mode is + when Mode_I32 + | Mode_U32 + | Mode_I16 + | Mode_U16 => + Left := Gen_Insn (Left, R_Ax, Num); + Right := Gen_Insn (Right, R_Rm, Num); + Left := Reload (Left, R_Ax, Num); + case Kind is + when OE_Div_Ov + | OE_Rem + | OE_Mod => + -- Be sure EDX is free. + Reg_Res := Alloc_Reg (R_Dx, Stmt, Pnum); + when others => + Reg_Res := R_Nil; + end case; + Right := Reload (Right, R_Rm, Num); + Set_Expr_Right (Stmt, Right); + Set_Expr_Left (Stmt, Left); + Free_Insn_Regs (Left); + Free_Insn_Regs (Right); + if Reg_Res /= R_Nil then + Free_R32 (Reg_Res); + end if; + if Kind = OE_Div_Ov or Kind = OE_Mul_Ov then + Reg_Res := R_Ax; + Clobber_R32 (R_Dx); + else + Reg_Res := R_Dx; + Clobber_R32 (R_Ax); + end if; + Set_Expr_Reg (Stmt, Alloc_Reg (Reg_Res, Stmt, Pnum)); + Link_Stmt (Stmt); + return Reload (Stmt, Reg, Pnum); + when Mode_U64 + | Mode_I64 => + -- FIXME: align stack + Insert_Arg (Gen_Insn (Right, R_Irm, Num)); + Insert_Arg (Gen_Insn (Left, R_Irm, Num)); + return Insert_Intrinsic (Stmt, R_Edx_Eax, Pnum); + when Mode_F32 + | Mode_F64 => + Left := Gen_Insn (Left, R_St0, Num); + Right := Gen_Insn (Right, R_Rm, Num); + Set_Expr_Left (Stmt, Left); + Set_Expr_Right (Stmt, Right); + Free_Insn_Regs (Right); + Free_Insn_Regs (Left); + Set_Expr_Reg (Stmt, Alloc_Reg (R_St0, Stmt, Pnum)); + Link_Stmt (Stmt); + return Stmt; + when others => + Error_Gen_Insn (Stmt, Mode); + end case; + end; + + when OE_Not + | OE_Abs_Ov + | OE_Neg_Ov => + Left := Get_Expr_Operand (Stmt); + case Reg is + when R_Any32 + | Regs_R32 + | R_Any64 + | Regs_R64 + | R_Any8 + | R_St0 => + Reg_Res := Reg; + when R_Any_Cc => + if Kind /= OE_Not then + raise Program_Error; + end if; + Left := Gen_Insn (Left, R_Any_Cc, Pnum); + Set_Expr_Operand (Stmt, Left); + Reg_Res := Inverse_Cc (Get_Expr_Reg (Left)); + Free_Cc; + Set_Expr_Reg (Stmt, Reg_Res); + Alloc_Cc (Stmt, Pnum); + return Stmt; + when R_Irm + | R_Rm + | R_Ir => + Reg_Res := Get_Reg_Any (Get_Expr_Mode (Left)); + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + Left := Gen_Insn (Left, Reg_Res, Pnum); + Set_Expr_Operand (Stmt, Left); + Reg_Res := Get_Expr_Reg (Left); + Free_Insn_Regs (Left); + Set_Expr_Reg (Stmt, Alloc_Reg (Reg_Res, Stmt, Pnum)); + Link_Stmt (Stmt); + return Stmt; + when OE_Conv => + declare + O_Mode : Mode_Type; -- Operand mode + R_Mode : Mode_Type; -- Result mode + begin + Left := Get_Expr_Operand (Stmt); + O_Mode := Get_Expr_Mode (Left); + R_Mode := Get_Expr_Mode (Stmt); + -- Simple case: no conversion. + -- FIXME: should be handled by EXPR and convert to NOP. + if Get_Expr_Mode (Left) = Get_Expr_Mode (Stmt) then + -- A no-op. + return Gen_Insn (Left, Reg, Pnum); + end if; + case R_Mode is + when Mode_B2 => + case O_Mode is + when Mode_U32 + | Mode_I32 => + -- Detect for bound. + null; + when others => + Error_Gen_Insn (Stmt, O_Mode); + end case; + when Mode_U8 => + case O_Mode is + when Mode_U16 + | Mode_U32 + | Mode_I32 => + -- Detect for bound. + null; + when others => + Error_Gen_Insn (Stmt, O_Mode); + end case; + when Mode_U32 => + case O_Mode is + when Mode_I32 => + -- Detect for bound. + null; + when Mode_B2 + | Mode_U8 + | Mode_U16 => + -- Zero extend. + null; + when others => + Error_Gen_Insn (Stmt, O_Mode); + end case; + when Mode_I32 => + case O_Mode is + when Mode_U8 + | Mode_I8 + | Mode_B2 + | Mode_U16 + | Mode_U32 => + -- Zero extend + -- Detect for bound (U32). + null; + when Mode_I64 => + -- Detect for bound (U32) + Num := Get_Insn_Num; + Left := Gen_Insn (Left, R_Edx_Eax, Num); + Free_Insn_Regs (Left); + Set_Expr_Operand (Stmt, Left); + case Reg is + when R_Ax + | R_Any32 + | R_Rm + | R_Irm + | R_Ir => + Set_Expr_Reg + (Stmt, Alloc_Reg (R_Ax, Stmt, Num)); + when others => + raise Program_Error; + end case; + Insert_Reg (Mode_U32); + Link_Stmt (Stmt); + return Stmt; + when Mode_F64 + | Mode_F32 => + return Gen_Conv_From_Fp_Insn (Stmt, Reg, Pnum); + when others => + Error_Gen_Insn (Stmt, O_Mode); + end case; + when Mode_I64 => + case O_Mode is + when Mode_I32 => + -- Sign extend. + Num := Get_Insn_Num; + Left := Gen_Insn (Left, R_Ax, Num); + Set_Expr_Operand (Stmt, Left); + Free_Insn_Regs (Left); + case Reg is + when R_Edx_Eax + | R_Any64 + | R_Rm + | R_Irm + | R_Ir => + Set_Expr_Reg + (Stmt, Alloc_Reg (R_Edx_Eax, Stmt, Pnum)); + when others => + raise Program_Error; + end case; + Link_Stmt (Stmt); + return Stmt; + when Mode_F64 + | Mode_F32 => + return Gen_Conv_From_Fp_Insn (Stmt, Reg, Pnum); + when others => + Error_Gen_Insn (Stmt, O_Mode); + end case; + when Mode_F64 => + case O_Mode is + when Mode_I32 + | Mode_I64 => + null; + when others => + Error_Gen_Insn (Stmt, O_Mode); + end case; + when others => + Error_Gen_Insn (Stmt, O_Mode); + end case; + Left := Gen_Insn (Left, R_Rm, Pnum); + Set_Expr_Operand (Stmt, Left); + case Reg is + when R_Irm + | R_Rm + | R_Ir + | R_Sib + | R_Any32 + | Regs_R32 + | R_Any64 + | R_Any8 + | Regs_R64 + | Regs_Fp => + Free_Insn_Regs (Left); + Set_Expr_Reg + (Stmt, Alloc_Reg (Get_Reg_Any (Stmt), Stmt, Pnum)); + when others => + Error_Gen_Insn (Stmt, Reg); + end case; + Link_Stmt (Stmt); + return Stmt; + end; + when OE_Arg => + if Reg /= R_None then + raise Program_Error; + end if; + Left := Get_Arg_Link (Stmt); + if Left /= O_Enode_Null then + -- Recurse on next argument, so the first argument is pushed + -- the last one. + Left := Gen_Insn (Left, R_None, Pnum); + end if; + + Left := Get_Expr_Operand (Stmt); + case Get_Expr_Mode (Left) is + when Mode_F32 .. Mode_F64 => + -- fstp instruction. + Reg_Res := R_St0; + when others => + -- Push instruction. + Reg_Res := R_Irm; + end case; + Left := Gen_Insn (Left, Reg_Res, Pnum); + Set_Expr_Operand (Stmt, Left); + Push_Offset := Push_Offset + + Do_Align (Get_Mode_Size (Get_Expr_Mode (Left)), Mode_U32); + Link_Stmt (Stmt); + Free_Insn_Regs (Left); + return Stmt; + when OE_Call => + return Gen_Call (Stmt, Reg, Pnum); + when OE_Case_Expr => + Left := Get_Expr_Operand (Stmt); + Set_Expr_Reg (Stmt, Alloc_Reg (Get_Expr_Reg (Left), Stmt, Pnum)); + return Stmt; + when OE_Get_Stack => + Set_Expr_Reg (Stmt, R_Sp); + return Stmt; + when OE_Get_Frame => + Set_Expr_Reg (Stmt, R_Bp); + return Stmt; + when others => + Ada.Text_IO.Put_Line + ("gen_insn: unhandled enode " & OE_Kind'Image (Kind)); + raise Program_Error; + end case; + end Gen_Insn; + + procedure Assert_Free_Regs (Stmt : O_Enode) is + begin + for I in Regs_R32 loop + if Regs (I).Num /= O_Free then + Error_Reg ("gen_insn_stmt: reg is not free", Stmt, I); + end if; + end loop; + for I in Fp_Stack_Type loop + if Fp_Regs (I).Stmt /= O_Enode_Null then + Error_Reg ("gen_insn_stmt: reg is not free", Stmt, R_St0); + end if; + end loop; + end Assert_Free_Regs; + + procedure Gen_Insn_Stmt (Stmt : O_Enode) + is + Kind : OE_Kind; + + Left : O_Enode; + Right : O_Enode; + P_Reg : O_Reg; + Num : O_Inum; + + Prev_Stack_Offset : Uns32; + begin + Insn_Num := O_Iroot; + Num := Get_Insn_Num; + Prev_Stack_Offset := Stack_Offset; + + Kind := Get_Expr_Kind (Stmt); + case Kind is + when OE_Asgn => + Left := Gen_Insn (Get_Expr_Operand (Stmt), R_Ir, Num); + Right := Gen_Insn (Get_Assign_Target (Stmt), R_Sib, Num); + Left := Reload (Left, R_Ir, Num); + --Right := Reload (Right, R_Sib, Num); + Set_Expr_Operand (Stmt, Left); + Set_Assign_Target (Stmt, Right); + Link_Stmt (Stmt); + Free_Insn_Regs (Left); + Free_Insn_Regs (Right); + when OE_Set_Stack => + Left := Gen_Insn (Get_Expr_Operand (Stmt), R_Rm, Num); + Set_Expr_Operand (Stmt, Left); + Set_Expr_Reg (Stmt, R_Sp); + Link_Stmt (Stmt); + when OE_Jump_F + | OE_Jump_T => + Left := Gen_Insn (Get_Expr_Operand (Stmt), R_Any_Cc, Num); + Set_Expr_Operand (Stmt, Left); + Link_Stmt (Stmt); + Free_Cc; + when OE_Beg => + declare + Block_Decl : O_Dnode; + begin + Cur_Block := Stmt; + Block_Decl := Get_Block_Decls (Cur_Block); + Set_Block_Max_Stack (Block_Decl, Stack_Offset); + Expand_Decls (Block_Decl); + end; + Link_Stmt (Stmt); + when OE_End => + Swap_Stack_Offset (Get_Block_Decls (Cur_Block)); + Cur_Block := Get_Block_Parent (Cur_Block); + Link_Stmt (Stmt); + when OE_Jump + | OE_Label => + Link_Stmt (Stmt); + when OE_Leave => + Link_Stmt (Stmt); + when OE_Call => + Link_Stmt (Gen_Call (Stmt, R_None, Num)); + when OE_Ret => + Left := Get_Expr_Operand (Stmt); + P_Reg := Get_Call_Register (Get_Expr_Mode (Stmt)); + Left := Gen_Insn (Left, P_Reg, Num); + Set_Expr_Operand (Stmt, Left); + Link_Stmt (Stmt); + Free_Insn_Regs (Left); + when OE_Case => + Left := Gen_Insn (Get_Expr_Operand (Stmt), + Get_Reg_Any (Get_Expr_Mode (Stmt)), + Num); + Set_Expr_Operand (Stmt, Left); + Set_Expr_Reg (Stmt, Get_Expr_Reg (Left)); + Link_Stmt (Stmt); + Free_Insn_Regs (Left); + when OE_Line => + Set_Expr_Reg (Stmt, R_None); + Link_Stmt (Stmt); + when OE_BB => + -- Keep BB. + Link_Stmt (Stmt); + when others => + Ada.Text_IO.Put_Line + ("gen_insn_stmt: unhandled enode " & OE_Kind'Image (Kind)); + raise Program_Error; + end case; + + -- Free any spill stack slots. + case Kind is + when OE_Beg + | OE_End => + null; + when others => + Stack_Offset := Prev_Stack_Offset; + end case; + + -- Check all registers are free. + if Debug.Flag_Debug_Assert then + Assert_Free_Regs (Stmt); + end if; + end Gen_Insn_Stmt; + + procedure Gen_Subprg_Insns (Subprg : Subprogram_Data_Acc) + is + First : O_Enode; + Stmt : O_Enode; + N_Stmt : O_Enode; + begin + if Debug.Flag_Debug_Insn then + declare + Inter : O_Dnode; + begin + Disp_Decl (1, Subprg.D_Decl); + Inter := Get_Subprg_Interfaces (Subprg.D_Decl); + while Inter /= O_Dnode_Null loop + Disp_Decl (2, Inter); + Inter := Get_Interface_Chain (Inter); + end loop; + end; + end if; + + for I in Regs_R32 loop + Regs (I).Used := False; + end loop; + + Stack_Max := 0; + Stack_Offset := 0; + First := Subprg.E_Entry; + Expand_Decls (Subprg.D_Body + 1); + Abi.Last_Link := First; + + -- Generate instructions. + -- Skip OE_Entry. + Stmt := Get_Stmt_Link (First); + loop + N_Stmt := Get_Stmt_Link (Stmt); + Gen_Insn_Stmt (Stmt); + exit when Get_Expr_Kind (Stmt) = OE_Leave; + Stmt := N_Stmt; + end loop; + + -- Keep stack depth for this subprogram. + Subprg.Stack_Max := Stack_Max; + + -- Sanity check: there must be no remaining pushed bytes. + if Push_Offset /= 0 then + raise Program_Error with "gen_subprg_insn: push_offset not 0"; + end if; + end Gen_Subprg_Insns; + +end Ortho_Code.X86.Insns; diff --git a/src/ortho/mcode/ortho_code-x86-insns.ads b/src/ortho/mcode/ortho_code-x86-insns.ads new file mode 100644 index 000000000..9411737a0 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86-insns.ads @@ -0,0 +1,25 @@ +-- Mcode back-end for ortho - mcode to X86 instructions. +-- 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. +package Ortho_Code.X86.Insns is + function Reg_Used (Reg : Regs_R32) return Boolean; + + -- Split enodes of SUBPRG into instructions. + procedure Gen_Subprg_Insns (Subprg : Subprogram_Data_Acc); + +end Ortho_Code.X86.Insns; + diff --git a/src/ortho/mcode/ortho_code-x86.adb b/src/ortho/mcode/ortho_code-x86.adb new file mode 100644 index 000000000..175dd7e99 --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86.adb @@ -0,0 +1,109 @@ +-- Mcode back-end for ortho - X86 common definitions. +-- 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. +package body Ortho_Code.X86 is + function Inverse_Cc (R : O_Reg) return O_Reg is + begin + case R is + when R_Ult => + return R_Uge; + when R_Uge => + return R_Ult; + when R_Eq => + return R_Ne; + when R_Ne => + return R_Eq; + when R_Ule => + return R_Ugt; + when R_Ugt => + return R_Ule; + when R_Slt => + return R_Sge; + when R_Sge => + return R_Slt; + when R_Sle => + return R_Sgt; + when R_Sgt => + return R_Sle; + when others => + raise Program_Error; + end case; + end Inverse_Cc; + + function Get_R64_High (Reg : Regs_R64) return Regs_R32 is + begin + case Reg is + when R_Edx_Eax => + return R_Dx; + when R_Ebx_Ecx => + return R_Bx; + when R_Esi_Edi => + return R_Si; + end case; + end Get_R64_High; + + function Get_R64_Low (Reg : Regs_R64) return Regs_R32 is + begin + case Reg is + when R_Edx_Eax => + return R_Ax; + when R_Ebx_Ecx => + return R_Cx; + when R_Esi_Edi => + return R_Di; + end case; + end Get_R64_Low; + + function Ekind_Unsigned_To_Cc (Kind : OE_Kind_Cmp) return O_Reg is + begin + case Kind is + when OE_Eq => + return R_Eq; + when OE_Neq => + return R_Ne; + when OE_Lt => + return R_Ult; + when OE_Le => + return R_Ule; + when OE_Gt => + return R_Ugt; + when OE_Ge => + return R_Uge; + end case; + end Ekind_Unsigned_To_Cc; + + function Ekind_Signed_To_Cc (Kind : OE_Kind_Cmp) return O_Reg is + begin + case Kind is + when OE_Eq => + return R_Eq; + when OE_Neq => + return R_Ne; + when OE_Lt => + return R_Slt; + when OE_Le => + return R_Sle; + when OE_Gt => + return R_Sgt; + when OE_Ge => + return R_Sge; + end case; + end Ekind_Signed_To_Cc; + +end Ortho_Code.X86; + + diff --git a/src/ortho/mcode/ortho_code-x86.ads b/src/ortho/mcode/ortho_code-x86.ads new file mode 100644 index 000000000..24be1eb6c --- /dev/null +++ b/src/ortho/mcode/ortho_code-x86.ads @@ -0,0 +1,160 @@ +-- Mcode back-end for ortho - X86 common definitions. +-- 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 Ortho_Code.Exprs; use Ortho_Code.Exprs; + +package Ortho_Code.X86 is + -- Registers. + R_Nil : constant O_Reg := 0; + + -- Not a value. Used for statements. + R_None : constant O_Reg := 1; + + -- Memory. + R_Mem : constant O_Reg := 2; + + -- Spilled out. + R_Spill : constant O_Reg := 3; + + -- Register or memory. + -- THis can only be requested. + R_Rm : constant O_Reg := 48; + + -- Immediat + R_Imm : constant O_Reg := 49; + + -- Immediat, register or memory. + -- This can be requested. + R_Irm : constant O_Reg := 50; + + -- Immediat or register. + -- This can be requested. + R_Ir : constant O_Reg := 51; + + -- BASE + OFFSET + R_B_Off : constant O_Reg := 52; + + -- BASE+INDEX*SCALE+OFFSET + -- This can be requested. + R_Sib : constant O_Reg := 53; + + -- INDEX*SCALE + OFFSET + -- This can be requested. + R_I_Off : constant O_Reg := 54; + + -- BASE + INDEX*SCALE + R_B_I : constant O_Reg := 55; + + -- INDEX*SCALE + R_I : constant O_Reg := 56; + + subtype Regs_Imm32 is O_Reg range R_Irm .. R_I_Off; + + R_Any8 : constant O_Reg := 6; + R_Any32 : constant O_Reg := 7; + R_Ax : constant O_Reg := 8; + R_Cx : constant O_Reg := 9; + R_Dx : constant O_Reg := 10; + R_Bx : constant O_Reg := 11; + R_Sp : constant O_Reg := 12; + R_Bp : constant O_Reg := 13; + R_Si : constant O_Reg := 14; + R_Di : constant O_Reg := 15; + + subtype Regs_R8 is O_Reg range R_Ax .. R_Bx; + subtype Regs_R32 is O_Reg range R_Ax .. R_Di; + + R_St0 : constant O_Reg := 16; + R_St1 : constant O_Reg := 17; + R_St2 : constant O_Reg := 18; + R_St3 : constant O_Reg := 19; + R_St4 : constant O_Reg := 20; + R_St5 : constant O_Reg := 21; + R_St6 : constant O_Reg := 22; + R_St7 : constant O_Reg := 23; + --R_Any_Fp : constant O_Reg := 24; + + subtype Regs_Fp is O_Reg range R_St0 .. R_St7; + + -- Any condition register. + R_Any_Cc : constant O_Reg := 32; + R_Ov : constant O_Reg := 32; + R_Ult : constant O_Reg := 34; + R_Uge : constant O_Reg := 35; + R_Eq : constant O_Reg := 36; + R_Ne : constant O_Reg := 37; + R_Ule : constant O_Reg := 38; + R_Ugt : constant O_Reg := 39; + R_Slt : constant O_Reg := 44; + R_Sge : constant O_Reg := 45; + R_Sle : constant O_Reg := 46; + R_Sgt : constant O_Reg := 47; + + subtype Regs_Cc is O_Reg range R_Ov .. R_Sgt; + + R_Edx_Eax : constant O_Reg := 64; + R_Ebx_Ecx : constant O_Reg := 65; + R_Esi_Edi : constant O_Reg := 66; + R_Any64 : constant O_Reg := 67; + + subtype Regs_R64 is O_Reg range R_Edx_Eax .. R_Esi_Edi; + + R_Any_Xmm : constant O_Reg := 79; + + R_Xmm0 : constant O_Reg := 80; + R_Xmm1 : constant O_Reg := R_Xmm0 + 1; + R_Xmm2 : constant O_Reg := R_Xmm0 + 2; + R_Xmm3 : constant O_Reg := R_Xmm0 + 3; + R_Xmm4 : constant O_Reg := R_Xmm0 + 4; + R_Xmm5 : constant O_Reg := R_Xmm0 + 5; + R_Xmm6 : constant O_Reg := R_Xmm0 + 6; + R_Xmm7 : constant O_Reg := R_Xmm0 + 7; + R_Xmm8 : constant O_Reg := R_Xmm0 + 8; + R_Xmm9 : constant O_Reg := R_Xmm0 + 9; + R_Xmm10 : constant O_Reg := R_Xmm0 + 10; + R_Xmm11 : constant O_Reg := R_Xmm0 + 11; + R_Xmm12 : constant O_Reg := R_Xmm0 + 12; + R_Xmm13 : constant O_Reg := R_Xmm0 + 13; + R_Xmm14 : constant O_Reg := R_Xmm0 + 14; + R_Xmm15 : constant O_Reg := R_Xmm0 + 15; + + subtype Regs_X86_64_Xmm is O_Reg range R_Xmm0 .. R_Xmm15; + subtype Regs_X86_Xmm is O_Reg range R_Xmm0 .. R_Xmm7; + subtype Regs_Xmm is O_Reg range R_Xmm0 .. R_Xmm15; + + function Get_R64_High (Reg : Regs_R64) return Regs_R32; + function Get_R64_Low (Reg : Regs_R64) return Regs_R32; + + function Inverse_Cc (R : O_Reg) return O_Reg; + + -- Intrinsic subprograms. + Intrinsic_Mul_Ov_U64 : constant Int32 := 1; + Intrinsic_Div_Ov_U64 : constant Int32 := 2; + Intrinsic_Mod_Ov_U64 : constant Int32 := 3; + Intrinsic_Mul_Ov_I64 : constant Int32 := 4; + Intrinsic_Div_Ov_I64 : constant Int32 := 5; + Intrinsic_Mod_Ov_I64 : constant Int32 := 6; + Intrinsic_Rem_Ov_I64 : constant Int32 := 7; + + subtype Intrinsics_X86 is Int32 + range Intrinsic_Mul_Ov_U64 .. Intrinsic_Rem_Ov_I64; + + -- Convert a KIND to a reg. + function Ekind_Unsigned_To_Cc (Kind : OE_Kind_Cmp) return O_Reg; + function Ekind_Signed_To_Cc (Kind : OE_Kind_Cmp) return O_Reg; + +end Ortho_Code.X86; diff --git a/src/ortho/mcode/ortho_code.ads b/src/ortho/mcode/ortho_code.ads new file mode 100644 index 000000000..0657b07e6 --- /dev/null +++ b/src/ortho/mcode/ortho_code.ads @@ -0,0 +1,150 @@ +-- Mcode back-end for ortho - common definitions. +-- 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.Unchecked_Conversion; + +package Ortho_Code is + type Int32 is range -(2 ** 31) .. (2 ** 31) - 1; + + type Uns32 is mod 2 ** 32; + + type Uns64 is mod 2 ** 64; + + function Shift_Right (L : Uns64; R : Natural) return Uns64; + function Shift_Right (L : Uns32; R : Natural) return Uns32; + pragma Import (Intrinsic, Shift_Right); + + function Shift_Right_Arithmetic (L : Uns32; R : Natural) return Uns32; + pragma Import (Intrinsic, Shift_Right_Arithmetic); + + function Shift_Left (L : Uns32; R : Natural) return Uns32; + pragma Import (Intrinsic, Shift_Left); + + type O_Tnode is new Int32; + for O_Tnode'Size use 32; + O_Tnode_Null : constant O_Tnode := 0; + O_Tnode_First : constant O_Tnode := 2; + + -- A generic pointer. + -- This is used by static chains. + O_Tnode_Ptr : constant O_Tnode := 2; + + type O_Cnode is new Int32; + for O_Cnode'Size use 32; + O_Cnode_Null : constant O_Cnode := 0; + + type O_Dnode is new Int32; + for O_Dnode'Size use 32; + O_Dnode_Null : constant O_Dnode := 0; + O_Dnode_First : constant O_Dnode := 2; + + type O_Enode is new Int32; + for O_Enode'Size use 32; + O_Enode_Null : constant O_Enode := 0; + O_Enode_Err : constant O_Enode := 1; + + type O_Fnode is new Int32; + for O_Fnode'Size use 32; + O_Fnode_Null : constant O_Fnode := 0; + + type O_Lnode is new Int32; + for O_Lnode'Size use 32; + O_Lnode_Null : constant O_Lnode := 0; + + type O_Ident is new Int32; + O_Ident_Nul : constant O_Ident := 0; + + function To_Int32 is new Ada.Unchecked_Conversion + (Source => Uns32, Target => Int32); + + function To_Uns32 is new Ada.Unchecked_Conversion + (Source => Int32, Target => Uns32); + + + -- Specifies the storage kind of a declaration. + -- O_STORAGE_EXTERNAL: + -- The declaration do not either reserve memory nor generate code, and + -- is imported either from an other file or from a later place in the + -- current file. + -- O_STORAGE_PUBLIC, O_STORAGE_PRIVATE: + -- The declaration reserves memory or generates code. + -- With O_STORAGE_PUBLIC, the declaration is exported outside of the + -- file while with O_STORAGE_PRIVATE, the declaration is local to the + -- file. + type O_Storage is (O_Storage_External, + O_Storage_Public, + O_Storage_Private, + O_Storage_Local); + + -- Depth of a declaration. + -- 0 for top-level, + -- 1 for declared in a top-level subprogram + type O_Depth is range 0 .. (2 ** 16) - 1; + O_Toplevel : constant O_Depth := 0; + + -- BE representation of a register. + type O_Reg is mod 256; + R_Nil : constant O_Reg := 0; + + type Mode_Type is (Mode_U8, Mode_U16, Mode_U32, Mode_U64, + Mode_I8, Mode_I16, Mode_I32, Mode_I64, + Mode_X1, Mode_Nil, Mode_F32, Mode_F64, + Mode_B2, Mode_Blk, Mode_P32, Mode_P64); + + subtype Mode_Uns is Mode_Type range Mode_U8 .. Mode_U64; + subtype Mode_Int is Mode_Type range Mode_I8 .. Mode_I64; + subtype Mode_Fp is Mode_Type range Mode_F32 .. Mode_F64; + -- Mode_Ptr : constant Mode_Type := Mode_P32; + + type ON_Op_Kind is + ( + -- Not an operation; invalid. + ON_Nil, + + -- Dyadic operations. + ON_Add_Ov, -- ON_Dyadic_Op_Kind + ON_Sub_Ov, -- ON_Dyadic_Op_Kind + ON_Mul_Ov, -- ON_Dyadic_Op_Kind + ON_Div_Ov, -- ON_Dyadic_Op_Kind + ON_Rem_Ov, -- ON_Dyadic_Op_Kind + ON_Mod_Ov, -- ON_Dyadic_Op_Kind + + -- Binary operations. + ON_And, -- ON_Dyadic_Op_Kind + ON_Or, -- ON_Dyadic_Op_Kind + ON_Xor, -- ON_Dyadic_Op_Kind + + -- Monadic operations. + ON_Not, -- ON_Monadic_Op_Kind + ON_Neg_Ov, -- ON_Monadic_Op_Kind + ON_Abs_Ov, -- ON_Monadic_Op_Kind + + -- Comparaisons + ON_Eq, -- ON_Compare_Op_Kind + ON_Neq, -- ON_Compare_Op_Kind + ON_Le, -- ON_Compare_Op_Kind + ON_Lt, -- ON_Compare_Op_Kind + ON_Ge, -- ON_Compare_Op_Kind + ON_Gt -- ON_Compare_Op_Kind + ); + + subtype ON_Dyadic_Op_Kind is ON_Op_Kind range ON_Add_Ov .. ON_Xor; + subtype ON_Monadic_Op_Kind is ON_Op_Kind range ON_Not .. ON_Abs_Ov; + subtype ON_Compare_Op_Kind is ON_Op_Kind range ON_Eq .. ON_Gt; + + Syntax_Error : exception; +end Ortho_Code; diff --git a/src/ortho/mcode/ortho_code_main.adb b/src/ortho/mcode/ortho_code_main.adb new file mode 100644 index 000000000..a0e6dc6c6 --- /dev/null +++ b/src/ortho/mcode/ortho_code_main.adb @@ -0,0 +1,198 @@ +-- Mcode back-end for ortho - Main subprogram. +-- 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.Unchecked_Conversion; +with Ada.Command_Line; use Ada.Command_Line; +with Ada.Unchecked_Deallocation; +with Ada.Text_IO; use Ada.Text_IO; +with Binary_File; use Binary_File; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Ortho_Code.Debug; +with Ortho_Mcode; use Ortho_Mcode; +with Ortho_Front; use Ortho_Front; +with Ortho_Code.Flags; use Ortho_Code.Flags; +with Binary_File.Elf; +with Binary_File.Coff; +with Binary_File.Memory; + +procedure Ortho_Code_Main +is + Output : String_Acc := null; + type Format_Type is (Format_Coff, Format_Elf); + Format : constant Format_Type := Format_Elf; + Fd : File_Descriptor; + + First_File : Natural; + Opt : String_Acc; + Opt_Arg : String_Acc; + Filename : String_Acc; + Exec_Func : String_Acc; + Res : Natural; + I : Natural; + Argc : Natural; + procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation + (Name => String_Acc, Object => String); +begin + First_File := Natural'Last; + Exec_Func := null; + + Ortho_Front.Init; + + Argc := Argument_Count; + I := 1; + while I <= Argc loop + declare + Arg : constant String := Argument (I); + begin + if Arg (1) = '-' then + if Arg'Length > 5 and then Arg (1 .. 5) = "--be-" then + Ortho_Code.Debug.Set_Be_Flag (Arg); + I := I + 1; + elsif Arg = "-o" then + if I = Argc then + Put_Line (Standard_Error, "error: missing filename to '-o'"); + return; + end if; + Output := new String'(Argument (I + 1)); + I := I + 2; + elsif Arg = "-quiet" then + -- Skip silently. + I := I + 1; + elsif Arg = "--exec" then + if I = Argc then + Put_Line (Standard_Error, + "error: missing function name to '--exec'"); + return; + end if; + Exec_Func := new String'(Argument (I + 1)); + I := I + 2; + elsif Arg = "-g" then + Flag_Debug := Debug_Dwarf; + I := I + 1; + elsif Arg = "-p" or Arg = "-pg" then + Flag_Profile := True; + I := I + 1; + else + -- This is really an argument. + Opt := new String'(Arg); + if I < Argument_Count then + Opt_Arg := new String'(Argument (I + 1)); + else + Opt_Arg := null; + end if; + Res := Ortho_Front.Decode_Option (Opt, Opt_Arg); + case Res is + when 0 => + Put_Line (Standard_Error, "unknown option '" & Arg & "'"); + return; + when 1 => + I := I + 1; + when 2 => + I := I + 2; + when others => + raise Program_Error; + end case; + Unchecked_Deallocation (Opt); + Unchecked_Deallocation (Opt_Arg); + end if; + else + First_File := I; + exit; + end if; + end; + end loop; + + Ortho_Mcode.Init; + + Set_Exit_Status (Failure); + + if First_File > Argument_Count then + begin + if not Parse (null) then + return; + end if; + exception + when others => + return; + end; + else + for I in First_File .. Argument_Count loop + Filename := new String'(Argument (First_File)); + begin + if not Parse (Filename) then + return; + end if; + exception + when others => + return; + end; + end loop; + end if; + + Ortho_Mcode.Finish; + + if Ortho_Code.Debug.Flag_Debug_Hli then + Set_Exit_Status (Success); + return; + end if; + + if Output /= null then + Fd := Create_File (Output.all, Binary); + if Fd /= Invalid_FD then + case Format is + when Format_Elf => + Binary_File.Elf.Write_Elf (Fd); + when Format_Coff => + Binary_File.Coff.Write_Coff (Fd); + end case; + Close (Fd); + end if; + elsif Exec_Func /= null then + declare + Sym : Symbol; + + type Func_Acc is access function return Integer; + function Conv is new Ada.Unchecked_Conversion + (Source => Pc_Type, Target => Func_Acc); + F : Func_Acc; + V : Integer; + Err : Boolean; + begin + Binary_File.Memory.Write_Memory_Init; + Binary_File.Memory.Write_Memory_Relocate (Err); + if Err then + return; + end if; + Sym := Binary_File.Get_Symbol (Exec_Func.all); + if Sym = Null_Symbol then + Put_Line (Standard_Error, "no '" & Exec_Func.all & "' symbol"); + else + F := Conv (Get_Symbol_Vaddr (Sym)); + V := F.all; + Put_Line ("Result is " & Integer'Image (V)); + end if; + end; + end if; + + Set_Exit_Status (Success); +exception + when others => + Set_Exit_Status (2); + raise; +end Ortho_Code_Main; + + diff --git a/src/ortho/mcode/ortho_ident.adb b/src/ortho/mcode/ortho_ident.adb new file mode 100644 index 000000000..0893b75dd --- /dev/null +++ b/src/ortho/mcode/ortho_ident.adb @@ -0,0 +1,117 @@ +-- Mcode back-end for ortho. +-- 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 GNAT.Table; + +package body Ortho_Ident is + package Ids is new GNAT.Table + (Table_Component_Type => Natural, + Table_Index_Type => O_Ident, + Table_Low_Bound => 2, + Table_Initial => 128, + Table_Increment => 100); + + package Strs is new GNAT.Table + (Table_Component_Type => Character, + Table_Index_Type => Natural, + Table_Low_Bound => 2, + Table_Initial => 128, + Table_Increment => 100); + + function Get_Identifier (Str : String) return O_Ident + is + Start : Natural; + begin + Start := Strs.Allocate (Str'Length + 1); + for I in Str'Range loop + Strs.Table (Start + I - Str'First) := Str (I); + end loop; + Strs.Table (Start + Str'Length) := ASCII.Nul; + Ids.Append (Start); + return Ids.Last; + end Get_Identifier; + + function Is_Equal (L, R : O_Ident) return Boolean + is + begin + return L = R; + end Is_Equal; + + function Get_String_Length (Id : O_Ident) return Natural + is + Start : Natural; + begin + Start := Ids.Table (Id); + if Id = Ids.Last then + return Strs.Last - Start + 1 - 1; + else + return Ids.Table (Id + 1) - 1 - Start; + end if; + end Get_String_Length; + + function Get_String (Id : O_Ident) return String + is + Res : String (1 .. Get_String_Length (Id)); + Start : constant Natural := Ids.Table (Id); + begin + for I in Res'Range loop + Res (I) := Strs.Table (Start + I - Res'First); + end loop; + return Res; + end Get_String; + + function Get_Cstring (Id : O_Ident) return System.Address is + begin + return Strs.Table (Ids.Table (Id))'Address; + end Get_Cstring; + + function Is_Equal (Id : O_Ident; Str : String) return Boolean + is + Start : constant Natural := Ids.Table (Id); + Len : constant Natural := Get_String_Length (Id); + begin + if Len /= Str'Length then + return False; + end if; + for I in Str'Range loop + if Str (I) /= Strs.Table (Start + I - Str'First) then + return False; + end if; + end loop; + return True; + end Is_Equal; + + function Is_Nul (Id : O_Ident) return Boolean is + begin + return Id = O_Ident_Nul; + end Is_Nul; + + procedure Disp_Stats + is + use Ada.Text_IO; + begin + Put_Line ("Number of Ident: " & O_Ident'Image (Ids.Last)); + Put_Line ("Number of Ident-Strs: " & Natural'Image (Strs.Last)); + end Disp_Stats; + + procedure Finish is + begin + Ids.Free; + Strs.Free; + end Finish; +end Ortho_Ident; diff --git a/src/ortho/mcode/ortho_ident.ads b/src/ortho/mcode/ortho_ident.ads new file mode 100644 index 000000000..cdc42fcad --- /dev/null +++ b/src/ortho/mcode/ortho_ident.ads @@ -0,0 +1,38 @@ +-- Mcode back-end for ortho. +-- 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 System; +with Ortho_Code; use Ortho_Code; + +package Ortho_Ident is + subtype O_Ident is Ortho_Code.O_Ident; + + function Get_Identifier (Str : String) return O_Ident; + function Is_Equal (L, R : O_Ident) return Boolean; + function Is_Equal (Id : O_Ident; Str : String) return Boolean; + function Is_Nul (Id : O_Ident) return Boolean; + function Get_String (Id : O_Ident) return String; + function Get_String_Length (Id : O_Ident) return Natural; + + -- Note: the address is valid until the next call to get_identifier. + function Get_Cstring (Id : O_Ident) return System.Address; + + O_Ident_Nul : constant O_Ident := Ortho_Code.O_Ident_Nul; + + procedure Disp_Stats; + procedure Finish; +end Ortho_Ident; diff --git a/src/ortho/mcode/ortho_jit.adb b/src/ortho/mcode/ortho_jit.adb new file mode 100644 index 000000000..7aa9724f2 --- /dev/null +++ b/src/ortho/mcode/ortho_jit.adb @@ -0,0 +1,125 @@ +-- Ortho JIT implementation for mcode. +-- Copyright (C) 2009 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 GNAT.OS_Lib; use GNAT.OS_Lib; +with Ada.Text_IO; + +with Binary_File; use Binary_File; +with Binary_File.Memory; +with Ortho_Mcode; use Ortho_Mcode; +with Ortho_Mcode.Jit; +with Ortho_Code.Flags; use Ortho_Code.Flags; +with Ortho_Code.Debug; +with Ortho_Code.Abi; +with Binary_File.Elf; + +package body Ortho_Jit is + Snap_Filename : GNAT.OS_Lib.String_Access := null; + + -- Initialize the whole engine. + procedure Init is + begin + Ortho_Mcode.Init; + Binary_File.Memory.Write_Memory_Init; + end Init; + + -- Set address of non-defined global variables or functions. + procedure Set_Address (Decl : O_Dnode; Addr : Address) + renames Ortho_Mcode.Jit.Set_Address; + + -- Get address of a global. + function Get_Address (Decl : O_Dnode) return Address + renames Ortho_Mcode.Jit.Get_Address; + + -- Do link. + procedure Link (Status : out Boolean) is + begin + if Ortho_Code.Debug.Flag_Debug_Hli then + -- Can't generate code in HLI. + Status := True; + return; + end if; + + Ortho_Mcode.Finish; + + Ortho_Code.Abi.Link_Intrinsics; + + Binary_File.Memory.Write_Memory_Relocate (Status); + if Status then + return; + end if; + + if Snap_Filename /= null then + declare + use Ada.Text_IO; + Fd : File_Descriptor; + begin + Fd := Create_File (Snap_Filename.all, Binary); + if Fd = Invalid_FD then + Put_Line (Standard_Error, + "can't open '" & Snap_Filename.all & "'"); + Status := False; + return; + else + Binary_File.Elf.Write_Elf (Fd); + Close (Fd); + end if; + end; + end if; + end Link; + + procedure Finish is + begin + -- Free all the memory. + Ortho_Mcode.Free_All; + + Binary_File.Finish; + end Finish; + + function Decode_Option (Option : String) return Boolean + is + Opt : constant String (1 .. Option'Length) := Option; + begin + if Opt = "-g" then + Flag_Debug := Debug_Dwarf; + return True; + elsif Opt'Length > 5 and then Opt (1 .. 5) = "--be-" then + Ortho_Code.Debug.Set_Be_Flag (Opt); + return True; + elsif Opt'Length > 7 and then Opt (1 .. 7) = "--snap=" then + Snap_Filename := new String'(Opt (8 .. Opt'Last)); + return True; + else + return False; + end if; + end Decode_Option; + + procedure Disp_Help is + use Ada.Text_IO; + begin + Put_Line (" -g Generate debugging informations"); + Put_Line (" --debug-be=X Set X internal debugging flags"); + Put_Line (" --snap=FILE Write memory snapshot to FILE"); + end Disp_Help; + + function Get_Jit_Name return String is + begin + return "mcode"; + end Get_Jit_Name; + +end Ortho_Jit; diff --git a/src/ortho/mcode/ortho_mcode-jit.adb b/src/ortho/mcode/ortho_mcode-jit.adb new file mode 100644 index 000000000..7e845cc6e --- /dev/null +++ b/src/ortho/mcode/ortho_mcode-jit.adb @@ -0,0 +1,28 @@ +with Ada.Unchecked_Conversion; + +with Ortho_Code.Binary; +with Binary_File; use Binary_File; +with Binary_File.Memory; + +package body Ortho_Mcode.Jit is + -- Set address of non-defined global variables or functions. + procedure Set_Address (Decl : O_Dnode; Addr : Address) + is + use Ortho_Code.Binary; + begin + Binary_File.Memory.Set_Symbol_Address + (Get_Decl_Symbol (Ortho_Code.O_Dnode (Decl)), Addr); + end Set_Address; + + -- Get address of a global. + function Get_Address (Decl : O_Dnode) return Address + is + use Ortho_Code.Binary; + + function Conv is new Ada.Unchecked_Conversion + (Source => Pc_Type, Target => Address); + begin + return Conv (Get_Symbol_Vaddr + (Get_Decl_Symbol (Ortho_Code.O_Dnode (Decl)))); + end Get_Address; +end Ortho_Mcode.Jit; diff --git a/src/ortho/mcode/ortho_mcode-jit.ads b/src/ortho/mcode/ortho_mcode-jit.ads new file mode 100644 index 000000000..c689a1e12 --- /dev/null +++ b/src/ortho/mcode/ortho_mcode-jit.ads @@ -0,0 +1,9 @@ +with System; use System; + +package Ortho_Mcode.Jit is + -- Set address of non-defined global variables or functions. + procedure Set_Address (Decl : O_Dnode; Addr : Address); + + -- Get address of a global. + function Get_Address (Decl : O_Dnode) return Address; +end Ortho_Mcode.Jit; diff --git a/src/ortho/mcode/ortho_mcode.adb b/src/ortho/mcode/ortho_mcode.adb new file mode 100644 index 000000000..55e890bf3 --- /dev/null +++ b/src/ortho/mcode/ortho_mcode.adb @@ -0,0 +1,738 @@ +-- Mcode back-end for ortho. +-- 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 Ortho_Code.Debug; +with Ortho_Ident; +with Ortho_Code.Abi; +-- with Binary_File; + +package body Ortho_Mcode is + procedure New_Debug_Comment_Stmt (Comment : String) + is + pragma Unreferenced (Comment); + begin + null; + end New_Debug_Comment_Stmt; + + procedure Start_Const_Value (Const : in out O_Dnode) + is + pragma Unreferenced (Const); + begin + null; + end Start_Const_Value; + + procedure Start_Record_Type (Elements : out O_Element_List) is + begin + Ortho_Code.Types.Start_Record_Type + (Ortho_Code.Types.O_Element_List (Elements)); + end Start_Record_Type; + + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode) is + begin + Ortho_Code.Types.New_Record_Field + (Ortho_Code.Types.O_Element_List (Elements), + Ortho_Code.O_Fnode (El), Ident, Ortho_Code.O_Tnode (Etype)); + end New_Record_Field; + + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode) is + begin + Ortho_Code.Types.Finish_Record_Type + (Ortho_Code.Types.O_Element_List (Elements), + Ortho_Code.O_Tnode (Res)); + end Finish_Record_Type; + + procedure New_Uncomplete_Record_Type (Res : out O_Tnode) is + begin + Ortho_Code.Types.New_Uncomplete_Record_Type (Ortho_Code.O_Tnode (Res)); + end New_Uncomplete_Record_Type; + + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List) is + begin + Ortho_Code.Types.Start_Uncomplete_Record_Type + (Ortho_Code.O_Tnode (Res), + Ortho_Code.Types.O_Element_List (Elements)); + end Start_Uncomplete_Record_Type; + + procedure Start_Union_Type (Elements : out O_Element_List) is + begin + Ortho_Code.Types.Start_Union_Type + (Ortho_Code.Types.O_Element_List (Elements)); + end Start_Union_Type; + + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode) is + begin + Ortho_Code.Types.New_Union_Field + (Ortho_Code.Types.O_Element_List (Elements), + Ortho_Code.O_Fnode (El), + Ident, + Ortho_Code.O_Tnode (Etype)); + end New_Union_Field; + + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode) is + begin + Ortho_Code.Types.Finish_Union_Type + (Ortho_Code.Types.O_Element_List (Elements), + Ortho_Code.O_Tnode (Res)); + end Finish_Union_Type; + + function New_Access_Type (Dtype : O_Tnode) return O_Tnode is + begin + return O_Tnode + (Ortho_Code.Types.New_Access_Type (Ortho_Code.O_Tnode (Dtype))); + end New_Access_Type; + + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode) is + begin + Ortho_Code.Types.Finish_Access_Type (Ortho_Code.O_Tnode (Atype), + Ortho_Code.O_Tnode (Dtype)); + end Finish_Access_Type; + + procedure Finish_Const_Value (Const : in out O_Dnode; Val : O_Cnode) + is + pragma Warnings (Off, Const); + begin + New_Const_Value (Ortho_Code.O_Dnode (Const), Ortho_Code.O_Cnode (Val)); + end Finish_Const_Value; + + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode is + begin + return O_Tnode + (Ortho_Code.Types.New_Array_Type (Ortho_Code.O_Tnode (El_Type), + Ortho_Code.O_Tnode (Index_Type))); + end New_Array_Type; + + function New_Constrained_Array_Type (Atype : O_Tnode; Length : O_Cnode) + return O_Tnode + is + Len : constant Ortho_Code.O_Cnode := Ortho_Code.O_Cnode (Length); + L_Type : Ortho_Code.O_Tnode; + begin + L_Type := Get_Const_Type (Len); + if Get_Type_Kind (L_Type) /= OT_Unsigned then + raise Syntax_Error; + end if; + return O_Tnode (New_Constrained_Array_Type + (Ortho_Code.O_Tnode (Atype), Get_Const_U32 (Len))); + end New_Constrained_Array_Type; + + function New_Unsigned_Type (Size : Natural) return O_Tnode is + begin + return O_Tnode (Ortho_Code.Types.New_Unsigned_Type (Size)); + end New_Unsigned_Type; + + function New_Signed_Type (Size : Natural) return O_Tnode is + begin + return O_Tnode (Ortho_Code.Types.New_Signed_Type (Size)); + end New_Signed_Type; + + function New_Float_Type return O_Tnode is + begin + return O_Tnode (Ortho_Code.Types.New_Float_Type); + end New_Float_Type; + + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode) is + begin + Ortho_Code.Types.New_Boolean_Type (Ortho_Code.O_Tnode (Res), + False_Id, + Ortho_Code.O_Cnode (False_E), + True_Id, + Ortho_Code.O_Cnode (True_E)); + end New_Boolean_Type; + + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural) is + begin + Ortho_Code.Types.Start_Enum_Type (Ortho_Code.Types.O_Enum_List (List), + Size); + end Start_Enum_Type; + + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; Res : out O_Cnode) is + begin + Ortho_Code.Types.New_Enum_Literal (Ortho_Code.Types.O_Enum_List (List), + Ident, Ortho_Code.O_Cnode (Res)); + end New_Enum_Literal; + + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode) is + begin + Ortho_Code.Types.Finish_Enum_Type (Ortho_Code.Types.O_Enum_List (List), + Ortho_Code.O_Tnode (Res)); + end Finish_Enum_Type; + + ------------------- + -- Expressions -- + ------------------- + + To_Op : constant array (ON_Op_Kind) of Ortho_Code.ON_Op_Kind := + ( + ON_Nil => ON_Nil, + + -- Dyadic operations. + ON_Add_Ov => ON_Add_Ov, + ON_Sub_Ov => ON_Sub_Ov, + ON_Mul_Ov => ON_Mul_Ov, + ON_Div_Ov => ON_Div_Ov, + ON_Rem_Ov => ON_Rem_Ov, + ON_Mod_Ov => ON_Mod_Ov, + + -- Binary operations. + ON_And => ON_And, + ON_Or => ON_Or, + ON_Xor => ON_Xor, + + -- Monadic operations. + ON_Not => ON_Not, + ON_Neg_Ov => ON_Neg_Ov, + ON_Abs_Ov => ON_Abs_Ov, + + -- Comparaisons + ON_Eq => ON_Eq, + ON_Neq => ON_Neq, + ON_Le => ON_Le, + ON_Lt => ON_Lt, + ON_Ge => ON_Ge, + ON_Gt => ON_Gt + ); + + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Signed_Literal (Ortho_Code.O_Tnode (Ltype), + Value)); + end New_Signed_Literal; + + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Unsigned_Literal (Ortho_Code.O_Tnode (Ltype), + Value)); + end New_Unsigned_Literal; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Float_Literal (Ortho_Code.O_Tnode (Ltype), + Value)); + end New_Float_Literal; + + function New_Null_Access (Ltype : O_Tnode) return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Null_Access (Ortho_Code.O_Tnode (Ltype))); + end New_Null_Access; + + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; + Atype : O_Tnode) is + begin + Ortho_Code.Consts.Start_Record_Aggr + (Ortho_Code.Consts.O_Record_Aggr_List (List), + Ortho_Code.O_Tnode (Atype)); + end Start_Record_Aggr; + + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode) is + begin + Ortho_Code.Consts.New_Record_Aggr_El + (Ortho_Code.Consts.O_Record_Aggr_List (List), + Ortho_Code.O_Cnode (Value)); + end New_Record_Aggr_El; + + procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; + Res : out O_Cnode) is + begin + Ortho_Code.Consts.Finish_Record_Aggr + (Ortho_Code.Consts.O_Record_Aggr_List (List), + Ortho_Code.O_Cnode (Res)); + end Finish_Record_Aggr; + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode) + is + begin + Ortho_Code.Consts.Start_Array_Aggr + (Ortho_Code.Consts.O_Array_Aggr_List (List), + Ortho_Code.O_Tnode (Atype)); + end Start_Array_Aggr; + + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode) is + begin + Ortho_Code.Consts.New_Array_Aggr_El + (Ortho_Code.Consts.O_Array_Aggr_List (List), + Ortho_Code.O_Cnode (Value)); + end New_Array_Aggr_El; + + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode) is + begin + Ortho_Code.Consts.Finish_Array_Aggr + (Ortho_Code.Consts.O_Array_Aggr_List (List), + Ortho_Code.O_Cnode (Res)); + end Finish_Array_Aggr; + + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Union_Aggr (Ortho_Code.O_Tnode (Atype), + Ortho_Code.O_Fnode (Field), + Ortho_Code.O_Cnode (Value))); + end New_Union_Aggr; + + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Sizeof (Ortho_Code.O_Tnode (Atype), + Ortho_Code.O_Tnode (Rtype))); + end New_Sizeof; + + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Alignof (Ortho_Code.O_Tnode (Atype), + Ortho_Code.O_Tnode (Rtype))); + end New_Alignof; + + function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Offsetof (Ortho_Code.O_Tnode (Atype), + Ortho_Code.O_Fnode (Field), + Ortho_Code.O_Tnode (Rtype))); + end New_Offsetof; + + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Subprogram_Address + (Ortho_Code.O_Dnode (Subprg), Ortho_Code.O_Tnode (Atype))); + end New_Subprogram_Address; + + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Global_Address + (Ortho_Code.O_Dnode (Decl), Ortho_Code.O_Tnode (Atype))); + end New_Global_Address; + + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode is + begin + return O_Cnode + (Ortho_Code.Consts.New_Global_Unchecked_Address + (Ortho_Code.O_Dnode (Decl), Ortho_Code.O_Tnode (Atype))); + end New_Global_Unchecked_Address; + + function New_Lit (Lit : O_Cnode) return O_Enode is + begin + return O_Enode (Ortho_Code.Exprs.New_Lit (Ortho_Code.O_Cnode (Lit))); + end New_Lit; + + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode is + begin + return O_Enode + (Ortho_Code.Exprs.New_Dyadic_Op (To_Op (Kind), + Ortho_Code.O_Enode (Left), + Ortho_Code.O_Enode (Right))); + end New_Dyadic_Op; + + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode is + begin + return O_Enode + (Ortho_Code.Exprs.New_Monadic_Op (To_Op (Kind), + Ortho_Code.O_Enode (Operand))); + end New_Monadic_Op; + + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) + return O_Enode is + begin + return O_Enode + (Ortho_Code.Exprs.New_Compare_Op (To_Op (Kind), + Ortho_Code.O_Enode (Left), + Ortho_Code.O_Enode (Right), + Ortho_Code.O_Tnode (Ntype))); + end New_Compare_Op; + + function New_Indexed_Element (Arr : O_Lnode; Index : O_Enode) + return O_Lnode is + begin + return O_Lnode + (Ortho_Code.Exprs.New_Indexed_Element (Ortho_Code.O_Lnode (Arr), + Ortho_Code.O_Enode (Index))); + end New_Indexed_Element; + + function New_Slice (Arr : O_Lnode; Res_Type : O_Tnode; Index : O_Enode) + return O_Lnode is + begin + return O_Lnode + (Ortho_Code.Exprs.New_Slice (Ortho_Code.O_Lnode (Arr), + Ortho_Code.O_Tnode (Res_Type), + Ortho_Code.O_Enode (Index))); + end New_Slice; + + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode is + begin + return O_Lnode + (Ortho_Code.Exprs.New_Selected_Element (Ortho_Code.O_Lnode (Rec), + Ortho_Code.O_Fnode (El))); + end New_Selected_Element; + + function New_Access_Element (Acc : O_Enode) return O_Lnode is + begin + return O_Lnode + (Ortho_Code.Exprs.New_Access_Element (Ortho_Code.O_Enode (Acc))); + end New_Access_Element; + + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode is + begin + return O_Enode + (Ortho_Code.Exprs.New_Convert_Ov (Ortho_Code.O_Enode (Val), + Ortho_Code.O_Tnode (Rtype))); + end New_Convert_Ov; + + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode is + begin + return O_Enode + (Ortho_Code.Exprs.New_Address (Ortho_Code.O_Lnode (Lvalue), + Ortho_Code.O_Tnode (Atype))); + end New_Address; + + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode is + begin + return O_Enode + (Ortho_Code.Exprs.New_Unchecked_Address (Ortho_Code.O_Lnode (Lvalue), + Ortho_Code.O_Tnode (Atype))); + end New_Unchecked_Address; + + function New_Value (Lvalue : O_Lnode) return O_Enode is + begin + return O_Enode + (Ortho_Code.Exprs.New_Value (Ortho_Code.O_Lnode (Lvalue))); + end New_Value; + + function New_Obj_Value (Obj : O_Dnode) return O_Enode is + begin + return New_Value (New_Obj (Obj)); + end New_Obj_Value; + + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode is + begin + return O_Enode (Ortho_Code.Exprs.New_Alloca (Ortho_Code.O_Tnode (Rtype), + Ortho_Code.O_Enode (Size))); + end New_Alloca; + + --------------------- + -- Declarations. -- + --------------------- + + procedure New_Debug_Filename_Decl (Filename : String) + renames Ortho_Code.Abi.New_Debug_Filename_Decl; + + procedure New_Debug_Line_Decl (Line : Natural) + is + pragma Unreferenced (Line); + begin + null; + end New_Debug_Line_Decl; + + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode) is + begin + Ortho_Code.Decls.New_Type_Decl (Ident, Ortho_Code.O_Tnode (Atype)); + end New_Type_Decl; + + To_Storage : constant array (O_Storage) of Ortho_Code.O_Storage := + (O_Storage_External => O_Storage_External, + O_Storage_Public => O_Storage_Public, + O_Storage_Private => O_Storage_Private, + O_Storage_Local => O_Storage_Local); + + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode) is + begin + Ortho_Code.Decls.New_Const_Decl + (Ortho_Code.O_Dnode (Res), Ident, To_Storage (Storage), + Ortho_Code.O_Tnode (Atype)); + end New_Const_Decl; + + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode) is + begin + Ortho_Code.Decls.New_Var_Decl + (Ortho_Code.O_Dnode (Res), Ident, To_Storage (Storage), + Ortho_Code.O_Tnode (Atype)); + end New_Var_Decl; + + function New_Obj (Obj : O_Dnode) return O_Lnode is + begin + return O_Lnode (Ortho_Code.Exprs.New_Obj (Ortho_Code.O_Dnode (Obj))); + end New_Obj; + + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode) is + begin + Ortho_Code.Decls.Start_Function_Decl + (Ortho_Code.Decls.O_Inter_List (Interfaces), + Ident, To_Storage (Storage), Ortho_Code.O_Tnode (Rtype)); + end Start_Function_Decl; + + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage) is + begin + Ortho_Code.Decls.Start_Procedure_Decl + (Ortho_Code.Decls.O_Inter_List (Interfaces), + Ident, To_Storage (Storage)); + end Start_Procedure_Decl; + + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode) is + begin + Ortho_Code.Decls.New_Interface_Decl + (Ortho_Code.Decls.O_Inter_List (Interfaces), + Ortho_Code.O_Dnode (Res), + Ident, + Ortho_Code.O_Tnode (Atype)); + end New_Interface_Decl; + + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode) is + begin + Ortho_Code.Decls.Finish_Subprogram_Decl + (Ortho_Code.Decls.O_Inter_List (Interfaces), Ortho_Code.O_Dnode (Res)); + end Finish_Subprogram_Decl; + + procedure Start_Subprogram_Body (Func : O_Dnode) is + begin + Ortho_Code.Exprs.Start_Subprogram_Body (Ortho_Code.O_Dnode (Func)); + end Start_Subprogram_Body; + + procedure Finish_Subprogram_Body + renames Ortho_Code.Exprs.Finish_Subprogram_Body; + + ------------------- + -- Statements. -- + ------------------- + + procedure New_Debug_Line_Stmt (Line : Natural) + renames Ortho_Code.Exprs.New_Debug_Line_Stmt; + + procedure New_Debug_Comment_Decl (Comment : String) + is + pragma Unreferenced (Comment); + begin + null; + end New_Debug_Comment_Decl; + + procedure Start_Declare_Stmt renames + Ortho_Code.Exprs.Start_Declare_Stmt; + procedure Finish_Declare_Stmt renames + Ortho_Code.Exprs.Finish_Declare_Stmt; + + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode) is + begin + Ortho_Code.Exprs.Start_Association + (Ortho_Code.Exprs.O_Assoc_List (Assocs), Ortho_Code.O_Dnode (Subprg)); + end Start_Association; + + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode) is + begin + Ortho_Code.Exprs.New_Association + (Ortho_Code.Exprs.O_Assoc_List (Assocs), Ortho_Code.O_Enode (Val)); + end New_Association; + + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode is + begin + return O_Enode (Ortho_Code.Exprs.New_Function_Call + (Ortho_Code.Exprs.O_Assoc_List (Assocs))); + end New_Function_Call; + + procedure New_Procedure_Call (Assocs : in out O_Assoc_List) is + begin + Ortho_Code.Exprs.New_Procedure_Call + (Ortho_Code.Exprs.O_Assoc_List (Assocs)); + end New_Procedure_Call; + + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode) is + begin + Ortho_Code.Exprs.New_Assign_Stmt (Ortho_Code.O_Lnode (Target), + Ortho_Code.O_Enode (Value)); + end New_Assign_Stmt; + + procedure New_Return_Stmt (Value : O_Enode) is + begin + Ortho_Code.Exprs.New_Return_Stmt (Ortho_Code.O_Enode (Value)); + end New_Return_Stmt; + + procedure New_Return_Stmt + renames Ortho_Code.Exprs.New_Return_Stmt; + + procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode) is + begin + Ortho_Code.Exprs.Start_If_Stmt (Ortho_Code.Exprs.O_If_Block (Block), + Ortho_Code.O_Enode (Cond)); + end Start_If_Stmt; + + procedure New_Else_Stmt (Block : in out O_If_Block) is + begin + Ortho_Code.Exprs.New_Else_Stmt (Ortho_Code.Exprs.O_If_Block (Block)); + end New_Else_Stmt; + + procedure Finish_If_Stmt (Block : in out O_If_Block) is + begin + Ortho_Code.Exprs.Finish_If_Stmt (Ortho_Code.Exprs.O_If_Block (Block)); + end Finish_If_Stmt; + + procedure Start_Loop_Stmt (Label : out O_Snode) is + begin + Ortho_Code.Exprs.Start_Loop_Stmt (Ortho_Code.Exprs.O_Snode (Label)); + end Start_Loop_Stmt; + + procedure Finish_Loop_Stmt (Label : in out O_Snode) is + begin + Ortho_Code.Exprs.Finish_Loop_Stmt (Ortho_Code.Exprs.O_Snode (Label)); + end Finish_Loop_Stmt; + + procedure New_Exit_Stmt (L : O_Snode) is + begin + Ortho_Code.Exprs.New_Exit_Stmt (Ortho_Code.Exprs.O_Snode (L)); + end New_Exit_Stmt; + + procedure New_Next_Stmt (L : O_Snode) is + begin + Ortho_Code.Exprs.New_Next_Stmt (Ortho_Code.Exprs.O_Snode (L)); + end New_Next_Stmt; + + procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode) is + begin + Ortho_Code.Exprs.Start_Case_Stmt + (Ortho_Code.Exprs.O_Case_Block (Block), Ortho_Code.O_Enode (Value)); + end Start_Case_Stmt; + + procedure Start_Choice (Block : in out O_Case_Block) is + begin + Ortho_Code.Exprs.Start_Choice (Ortho_Code.Exprs.O_Case_Block (Block)); + end Start_Choice; + + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode) is + begin + Ortho_Code.Exprs.New_Expr_Choice (Ortho_Code.Exprs.O_Case_Block (Block), + Ortho_Code.O_Cnode (Expr)); + end New_Expr_Choice; + + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode) is + begin + Ortho_Code.Exprs.New_Range_Choice + (Ortho_Code.Exprs.O_Case_Block (Block), + Ortho_Code.O_Cnode (Low), Ortho_Code.O_Cnode (High)); + end New_Range_Choice; + + procedure New_Default_Choice (Block : in out O_Case_Block) is + begin + Ortho_Code.Exprs.New_Default_Choice + (Ortho_Code.Exprs.O_Case_Block (Block)); + end New_Default_Choice; + + procedure Finish_Choice (Block : in out O_Case_Block) is + begin + Ortho_Code.Exprs.Finish_Choice (Ortho_Code.Exprs.O_Case_Block (Block)); + end Finish_Choice; + + procedure Finish_Case_Stmt (Block : in out O_Case_Block) is + begin + Ortho_Code.Exprs.Finish_Case_Stmt + (Ortho_Code.Exprs.O_Case_Block (Block)); + end Finish_Case_Stmt; + + procedure Init is + begin + -- Create an anonymous pointer type. + if New_Access_Type (O_Tnode_Null) /= O_Tnode (O_Tnode_Ptr) then + raise Program_Error; + end if; + -- Do not finish the access, since this creates an infinite recursion + -- in gdb (at least for GDB 6.3). + --Finish_Access_Type (O_Tnode_Ptr, O_Tnode_Ptr); + Ortho_Code.Abi.Init; + end Init; + + procedure Finish is + begin + if False then + Ortho_Code.Decls.Disp_All_Decls; + --Ortho_Code.Exprs.Disp_All_Enode; + end if; + Ortho_Code.Abi.Finish; + if Debug.Flag_Debug_Stat then + Ada.Text_IO.Put_Line ("Statistics:"); + Ortho_Code.Exprs.Disp_Stats; + Ortho_Code.Decls.Disp_Stats; + Ortho_Code.Types.Disp_Stats; + Ortho_Code.Consts.Disp_Stats; + Ortho_Ident.Disp_Stats; + -- Binary_File.Disp_Stats; + end if; + end Finish; + + procedure Free_All is + begin + Ortho_Code.Types.Finish; + Ortho_Code.Exprs.Finish; + Ortho_Code.Consts.Finish; + Ortho_Code.Decls.Finish; + Ortho_Ident.Finish; + end Free_All; +end Ortho_Mcode; diff --git a/src/ortho/mcode/ortho_mcode.ads b/src/ortho/mcode/ortho_mcode.ads new file mode 100644 index 000000000..45e803690 --- /dev/null +++ b/src/ortho/mcode/ortho_mcode.ads @@ -0,0 +1,583 @@ +-- DO NOT MODIFY - this file was generated from: +-- ortho_nodes.common.ads and ortho_mcode.private.ads +-- +-- Mcode back-end for ortho. +-- 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 Interfaces; use Interfaces; +with Ortho_Code; use Ortho_Code; +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.Exprs; use Ortho_Code.Exprs; + +-- Interface to create nodes. +package Ortho_Mcode is + -- Initialize nodes. + procedure Init; + procedure Finish; + + procedure Free_All; + +-- Start of common part + + type O_Enode is private; + type O_Cnode is private; + type O_Lnode is private; + type O_Tnode is private; + type O_Snode is private; + type O_Dnode is private; + type O_Fnode is private; + + O_Cnode_Null : constant O_Cnode; + O_Dnode_Null : constant O_Dnode; + O_Enode_Null : constant O_Enode; + O_Fnode_Null : constant O_Fnode; + O_Lnode_Null : constant O_Lnode; + O_Snode_Null : constant O_Snode; + O_Tnode_Null : constant O_Tnode; + + -- True if the code generated supports nested subprograms. + Has_Nested_Subprograms : constant Boolean; + + ------------------------ + -- Type definitions -- + ------------------------ + + type O_Element_List is limited private; + + -- Build a record type. + procedure Start_Record_Type (Elements : out O_Element_List); + -- Add a field in the record; not constrained array are prohibited, since + -- its size is unlimited. + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode); + -- Finish the record type. + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an uncomplete record type: + -- First call NEW_UNCOMPLETE_RECORD_TYPE, which returns a record type. + -- This type can be declared or used to define access types on it. + -- Then, complete (if necessary) the record type, by calling + -- START_UNCOMPLETE_RECORD_TYPE, NEW_RECORD_FIELD and FINISH_RECORD_TYPE. + procedure New_Uncomplete_Record_Type (Res : out O_Tnode); + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List); + + -- Build an union type. + procedure Start_Union_Type (Elements : out O_Element_List); + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode); + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an access type. + -- DTYPE may be O_tnode_null in order to build an incomplete access type. + -- It is completed with finish_access_type. + function New_Access_Type (Dtype : O_Tnode) return O_Tnode; + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode); + + -- Build an array type. + -- The array is not constrained and unidimensional. + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode; + + -- Build a constrained array type. + function New_Constrained_Array_Type (Atype : O_Tnode; Length : O_Cnode) + return O_Tnode; + + -- Build a scalar type; size may be 8, 16, 32 or 64. + function New_Unsigned_Type (Size : Natural) return O_Tnode; + function New_Signed_Type (Size : Natural) return O_Tnode; + + -- Build a float type. + function New_Float_Type return O_Tnode; + + -- Build a boolean type. + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode); + + -- Create an enumeration + type O_Enum_List is limited private; + + -- Elements are declared in order, the first is ordered from 0. + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural); + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; Res : out O_Cnode); + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode); + + ---------------- + -- Literals -- + ---------------- + + -- Create a literal from an integer. + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode; + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode; + + -- Create a null access literal. + function New_Null_Access (Ltype : O_Tnode) return O_Cnode; + + -- Build a record/array aggregate. + -- The aggregate is constant, and therefore can be only used to initialize + -- constant declaration. + -- ATYPE must be either a record type or an array subtype. + -- Elements must be added in the order, and must be literals or aggregates. + type O_Record_Aggr_List is limited private; + type O_Array_Aggr_List is limited private; + + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; + Atype : O_Tnode); + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode); + procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; + Res : out O_Cnode); + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode); + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode); + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode); + + -- Build an union aggregate. + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode; + + -- Returns the size in bytes of ATYPE. The result is a literal of + -- unsigned type RTYPE + -- ATYPE cannot be an unconstrained array type. + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the alignment in bytes for ATYPE. The result is a literal of + -- unsgined type RTYPE. + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the offset of FIELD in its record ATYPE. The result is a + -- literal of unsigned type or access type RTYPE. + function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode; + + -- Get the address of a subprogram. + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Same as New_Address but without any restriction. + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + ------------------- + -- Expressions -- + ------------------- + + type ON_Op_Kind is + ( + -- Not an operation; invalid. + ON_Nil, + + -- Dyadic operations. + ON_Add_Ov, -- ON_Dyadic_Op_Kind + ON_Sub_Ov, -- ON_Dyadic_Op_Kind + ON_Mul_Ov, -- ON_Dyadic_Op_Kind + ON_Div_Ov, -- ON_Dyadic_Op_Kind + ON_Rem_Ov, -- ON_Dyadic_Op_Kind + ON_Mod_Ov, -- ON_Dyadic_Op_Kind + + -- Binary operations. + ON_And, -- ON_Dyadic_Op_Kind + ON_Or, -- ON_Dyadic_Op_Kind + ON_Xor, -- ON_Dyadic_Op_Kind + + -- Monadic operations. + ON_Not, -- ON_Monadic_Op_Kind + ON_Neg_Ov, -- ON_Monadic_Op_Kind + ON_Abs_Ov, -- ON_Monadic_Op_Kind + + -- Comparaisons + ON_Eq, -- ON_Compare_Op_Kind + ON_Neq, -- ON_Compare_Op_Kind + ON_Le, -- ON_Compare_Op_Kind + ON_Lt, -- ON_Compare_Op_Kind + ON_Ge, -- ON_Compare_Op_Kind + ON_Gt -- ON_Compare_Op_Kind + ); + + subtype ON_Dyadic_Op_Kind is ON_Op_Kind range ON_Add_Ov .. ON_Xor; + subtype ON_Monadic_Op_Kind is ON_Op_Kind range ON_Not .. ON_Abs_Ov; + subtype ON_Compare_Op_Kind is ON_Op_Kind range ON_Eq .. ON_Gt; + + type O_Storage is (O_Storage_External, + O_Storage_Public, + O_Storage_Private, + O_Storage_Local); + -- Specifies the storage kind of a declaration. + -- O_STORAGE_EXTERNAL: + -- The declaration do not either reserve memory nor generate code, and + -- is imported either from an other file or from a later place in the + -- current file. + -- O_STORAGE_PUBLIC, O_STORAGE_PRIVATE: + -- The declaration reserves memory or generates code. + -- With O_STORAGE_PUBLIC, the declaration is exported outside of the + -- file while with O_STORAGE_PRIVATE, the declaration is local to the + -- file. + + Type_Error : exception; + Syntax_Error : exception; + + -- Create a value from a literal. + function New_Lit (Lit : O_Cnode) return O_Enode; + + -- Create a dyadic operation. + -- Left and right nodes must have the same type. + -- Binary operation is allowed only on boolean types. + -- The result is of the type of the operands. + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode; + + -- Create a monadic operation. + -- Result is of the type of operand. + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode; + + -- Create a comparaison operator. + -- NTYPE is the type of the result and must be a boolean type. + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) + return O_Enode; + + + type O_Inter_List is limited private; + type O_Assoc_List is limited private; + type O_If_Block is limited private; + type O_Case_Block is limited private; + + + -- 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; + + -- 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; + + -- Get an element of a record. + -- Type of REC must be a record type. + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode; + + -- Reference an access. + -- Type of ACC must be an access type. + function New_Access_Element (Acc : O_Enode) return O_Lnode; + + -- Do a conversion. + -- Allowed conversions are: + -- FIXME: to write. + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode; + + -- Same as New_Address but without any restriction. + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode; + + -- Get the value of an Lvalue. + function New_Value (Lvalue : O_Lnode) return O_Enode; + function New_Obj_Value (Obj : O_Dnode) return O_Enode; + + -- Get an lvalue from a declaration. + function New_Obj (Obj : O_Dnode) return O_Lnode; + + -- Return a pointer of type RTPE to SIZE bytes allocated on the stack. + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode; + + -- Declare a type. + -- This simply gives a name to a type. + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode); + + --------------------- + -- Declarations. -- + --------------------- + + -- Filename of the next declaration. + procedure New_Debug_Filename_Decl (Filename : String); + + -- Line number of the next declaration. + procedure New_Debug_Line_Decl (Line : Natural); + + -- Add a comment in the declarative region. + procedure New_Debug_Comment_Decl (Comment : String); + + -- Declare a constant. + -- This simply gives a name to a constant value or aggregate. + -- A constant cannot be modified and its storage cannot be local. + -- ATYPE must be constrained. + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Set the value of a non-external constant. + procedure Start_Const_Value (Const : in out O_Dnode); + procedure Finish_Const_Value (Const : in out O_Dnode; Val : O_Cnode); + + -- Create a variable declaration. + -- A variable can be local only inside a function. + -- ATYPE must be constrained. + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Start a subprogram declaration. + -- Note: nested subprograms are allowed, ie o_storage_local subprograms can + -- be declared inside a subprograms. It is not allowed to declare + -- o_storage_external subprograms inside a subprograms. + -- Return type and interfaces cannot be a composite type. + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode); + -- For a subprogram without return value. + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage); + + -- Add an interface declaration to INTERFACES. + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode); + -- Finish the function declaration, get the node and a statement list. + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode); + -- Start a subprogram body. + -- Note: the declaration may have an external storage, in this case it + -- becomes public. + procedure Start_Subprogram_Body (Func : O_Dnode); + -- Finish a subprogram body. + procedure Finish_Subprogram_Body; + + + ------------------- + -- Statements. -- + ------------------- + + -- Add a line number as a statement. + procedure New_Debug_Line_Stmt (Line : Natural); + + -- Add a comment as a statement. + procedure New_Debug_Comment_Stmt (Comment : String); + + -- Start a declarative region. + procedure Start_Declare_Stmt; + procedure Finish_Declare_Stmt; + + -- Create a function call or a procedure call. + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode); + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode); + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode; + procedure New_Procedure_Call (Assocs : in out O_Assoc_List); + + -- Assign VALUE to TARGET, type must be the same or compatible. + -- FIXME: what about slice assignment? + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode); + + -- Exit from the subprogram and return VALUE. + procedure New_Return_Stmt (Value : O_Enode); + -- Exit from the subprogram, which doesn't return value. + procedure New_Return_Stmt; + + -- Build an IF statement. + procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode); + procedure New_Else_Stmt (Block : in out O_If_Block); + procedure Finish_If_Stmt (Block : in out O_If_Block); + + -- Create a infinite loop statement. + procedure Start_Loop_Stmt (Label : out O_Snode); + procedure Finish_Loop_Stmt (Label : in out O_Snode); + + -- Exit from a loop stmt or from a for stmt. + procedure New_Exit_Stmt (L : O_Snode); + -- Go to the start of a loop stmt or of a for stmt. + -- Loops/Fors between L and the current points are exited. + procedure New_Next_Stmt (L : O_Snode); + + -- Case statement. + -- VALUE is the selector and must be a discrete type. + procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode); + -- A choice branch is composed of expr, range or default choices. + -- A choice branch is enclosed between a Start_Choice and a Finish_Choice. + -- The statements are after the finish_choice. + procedure Start_Choice (Block : in out O_Case_Block); + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode); + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode); + procedure New_Default_Choice (Block : in out O_Case_Block); + procedure Finish_Choice (Block : in out O_Case_Block); + procedure Finish_Case_Stmt (Block : in out O_Case_Block); + +-- End of common part +private + -- MCode supports nested subprograms. + Has_Nested_Subprograms : constant Boolean := True; + + type O_Tnode is new Ortho_Code.O_Tnode; + type O_Cnode is new Ortho_Code.O_Cnode; + type O_Dnode is new Ortho_Code.O_Dnode; + type O_Enode is new Ortho_Code.O_Enode; + type O_Fnode is new Ortho_Code.O_Fnode; + type O_Lnode is new Ortho_Code.O_Lnode; + type O_Snode is new Ortho_Code.Exprs.O_Snode; + + O_Lnode_Null : constant O_Lnode := O_Lnode (Ortho_Code.O_Lnode_Null); + O_Cnode_Null : constant O_Cnode := O_Cnode (Ortho_Code.O_Cnode_Null); + O_Dnode_Null : constant O_Dnode := O_Dnode (Ortho_Code.O_Dnode_Null); + O_Enode_Null : constant O_Enode := O_Enode (Ortho_Code.O_Enode_Null); + O_Fnode_Null : constant O_Fnode := O_Fnode (Ortho_Code.O_Fnode_Null); + O_Snode_Null : constant O_Snode := O_Snode (Ortho_Code.Exprs.O_Snode_Null); + O_Tnode_Null : constant O_Tnode := O_Tnode (Ortho_Code.O_Tnode_Null); + + type O_Element_List is new Ortho_Code.Types.O_Element_List; + type O_Enum_List is new Ortho_Code.Types.O_Enum_List; + type O_Inter_List is new Ortho_Code.Decls.O_Inter_List; + type O_Record_Aggr_List is new Ortho_Code.Consts.O_Record_Aggr_List; + type O_Array_Aggr_List is new Ortho_Code.Consts.O_Array_Aggr_List; + type O_Assoc_List is new Ortho_Code.Exprs.O_Assoc_List; + type O_If_Block is new Ortho_Code.Exprs.O_If_Block; + type O_Case_Block is new Ortho_Code.Exprs.O_Case_Block; + + pragma Inline (New_Lit); + pragma Inline (New_Dyadic_Op); + pragma Inline (New_Monadic_Op); + pragma Inline (New_Compare_Op); + pragma Inline (New_Signed_Literal); + pragma Inline (New_Unsigned_Literal); + pragma Inline (New_Float_Literal); + pragma Inline (New_Null_Access); + + pragma Inline (Start_Record_Aggr); + pragma Inline (New_Record_Aggr_El); + pragma Inline (Finish_Record_Aggr); + + pragma Inline (Start_Array_Aggr); + pragma Inline (New_Array_Aggr_El); + pragma Inline (Finish_Array_Aggr); + + pragma Inline (New_Union_Aggr); + pragma Inline (New_Sizeof); + pragma Inline (New_Alignof); + pragma Inline (New_Offsetof); + + pragma Inline (New_Indexed_Element); + pragma Inline (New_Slice); + pragma Inline (New_Selected_Element); + pragma Inline (New_Access_Element); + + pragma Inline (New_Convert_Ov); + + pragma Inline (New_Address); + pragma Inline (New_Global_Address); + pragma Inline (New_Unchecked_Address); + pragma Inline (New_Global_Unchecked_Address); + pragma Inline (New_Subprogram_Address); + + pragma Inline (New_Value); + pragma Inline (New_Obj_Value); + + pragma Inline (New_Alloca); + + pragma Inline (New_Debug_Filename_Decl); + pragma Inline (New_Debug_Line_Decl); + pragma Inline (New_Debug_Comment_Decl); + + pragma Inline (New_Type_Decl); + pragma Inline (New_Const_Decl); + + pragma Inline (Start_Const_Value); + pragma Inline (Finish_Const_Value); + pragma Inline (New_Var_Decl); + + pragma Inline (New_Obj); + pragma Inline (Start_Function_Decl); + pragma Inline (Start_Procedure_Decl); + pragma Inline (New_Interface_Decl); + pragma Inline (Finish_Subprogram_Decl); + pragma Inline (Start_Subprogram_Body); + pragma Inline (Finish_Subprogram_Body); + + pragma Inline (New_Debug_Line_Stmt); + pragma Inline (New_Debug_Comment_Stmt); + + pragma Inline (Start_Declare_Stmt); + pragma Inline (Finish_Declare_Stmt); + + -- Create a function call or a procedure call. + pragma Inline (Start_Association); + pragma Inline (New_Association); + pragma Inline (New_Function_Call); + pragma Inline (New_Procedure_Call); + + pragma Inline (New_Assign_Stmt); + pragma Inline (New_Return_Stmt); + pragma Inline (Start_If_Stmt); + pragma Inline (New_Else_Stmt); + pragma Inline (Finish_If_Stmt); + + pragma Inline (Start_Loop_Stmt); + pragma Inline (Finish_Loop_Stmt); + pragma Inline (New_Exit_Stmt); + pragma Inline (New_Next_Stmt); + + pragma Inline (Start_Case_Stmt); + pragma Inline (Start_Choice); + pragma Inline (New_Expr_Choice); + pragma Inline (New_Range_Choice); + pragma Inline (New_Default_Choice); + pragma Inline (Finish_Choice); + pragma Inline (Finish_Case_Stmt); +end Ortho_Mcode; diff --git a/src/ortho/mcode/ortho_mcode.private.ads b/src/ortho/mcode/ortho_mcode.private.ads new file mode 100644 index 000000000..1b414773f --- /dev/null +++ b/src/ortho/mcode/ortho_mcode.private.ads @@ -0,0 +1,151 @@ +-- Mcode back-end for ortho. +-- 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 Interfaces; use Interfaces; +with Ortho_Code; use Ortho_Code; +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.Exprs; use Ortho_Code.Exprs; + +-- Interface to create nodes. +package Ortho_Mcode is + -- Initialize nodes. + procedure Init; + procedure Finish; + + procedure Free_All; + +private + -- MCode supports nested subprograms. + Has_Nested_Subprograms : constant Boolean := True; + + type O_Tnode is new Ortho_Code.O_Tnode; + type O_Cnode is new Ortho_Code.O_Cnode; + type O_Dnode is new Ortho_Code.O_Dnode; + type O_Enode is new Ortho_Code.O_Enode; + type O_Fnode is new Ortho_Code.O_Fnode; + type O_Lnode is new Ortho_Code.O_Lnode; + type O_Snode is new Ortho_Code.Exprs.O_Snode; + + O_Lnode_Null : constant O_Lnode := O_Lnode (Ortho_Code.O_Lnode_Null); + O_Cnode_Null : constant O_Cnode := O_Cnode (Ortho_Code.O_Cnode_Null); + O_Dnode_Null : constant O_Dnode := O_Dnode (Ortho_Code.O_Dnode_Null); + O_Enode_Null : constant O_Enode := O_Enode (Ortho_Code.O_Enode_Null); + O_Fnode_Null : constant O_Fnode := O_Fnode (Ortho_Code.O_Fnode_Null); + O_Snode_Null : constant O_Snode := O_Snode (Ortho_Code.Exprs.O_Snode_Null); + O_Tnode_Null : constant O_Tnode := O_Tnode (Ortho_Code.O_Tnode_Null); + + type O_Element_List is new Ortho_Code.Types.O_Element_List; + type O_Enum_List is new Ortho_Code.Types.O_Enum_List; + type O_Inter_List is new Ortho_Code.Decls.O_Inter_List; + type O_Record_Aggr_List is new Ortho_Code.Consts.O_Record_Aggr_List; + type O_Array_Aggr_List is new Ortho_Code.Consts.O_Array_Aggr_List; + type O_Assoc_List is new Ortho_Code.Exprs.O_Assoc_List; + type O_If_Block is new Ortho_Code.Exprs.O_If_Block; + type O_Case_Block is new Ortho_Code.Exprs.O_Case_Block; + + pragma Inline (New_Lit); + pragma Inline (New_Dyadic_Op); + pragma Inline (New_Monadic_Op); + pragma Inline (New_Compare_Op); + pragma Inline (New_Signed_Literal); + pragma Inline (New_Unsigned_Literal); + pragma Inline (New_Float_Literal); + pragma Inline (New_Null_Access); + + pragma Inline (Start_Record_Aggr); + pragma Inline (New_Record_Aggr_El); + pragma Inline (Finish_Record_Aggr); + + pragma Inline (Start_Array_Aggr); + pragma Inline (New_Array_Aggr_El); + pragma Inline (Finish_Array_Aggr); + + pragma Inline (New_Union_Aggr); + pragma Inline (New_Sizeof); + pragma Inline (New_Alignof); + pragma Inline (New_Offsetof); + + pragma Inline (New_Indexed_Element); + pragma Inline (New_Slice); + pragma Inline (New_Selected_Element); + pragma Inline (New_Access_Element); + + pragma Inline (New_Convert_Ov); + + pragma Inline (New_Address); + pragma Inline (New_Global_Address); + pragma Inline (New_Unchecked_Address); + pragma Inline (New_Global_Unchecked_Address); + pragma Inline (New_Subprogram_Address); + + pragma Inline (New_Value); + pragma Inline (New_Obj_Value); + + pragma Inline (New_Alloca); + + pragma Inline (New_Debug_Filename_Decl); + pragma Inline (New_Debug_Line_Decl); + pragma Inline (New_Debug_Comment_Decl); + + pragma Inline (New_Type_Decl); + pragma Inline (New_Const_Decl); + + pragma Inline (Start_Const_Value); + pragma Inline (Finish_Const_Value); + pragma Inline (New_Var_Decl); + + pragma Inline (New_Obj); + pragma Inline (Start_Function_Decl); + pragma Inline (Start_Procedure_Decl); + pragma Inline (New_Interface_Decl); + pragma Inline (Finish_Subprogram_Decl); + pragma Inline (Start_Subprogram_Body); + pragma Inline (Finish_Subprogram_Body); + + pragma Inline (New_Debug_Line_Stmt); + pragma Inline (New_Debug_Comment_Stmt); + + pragma Inline (Start_Declare_Stmt); + pragma Inline (Finish_Declare_Stmt); + + -- Create a function call or a procedure call. + pragma Inline (Start_Association); + pragma Inline (New_Association); + pragma Inline (New_Function_Call); + pragma Inline (New_Procedure_Call); + + pragma Inline (New_Assign_Stmt); + pragma Inline (New_Return_Stmt); + pragma Inline (Start_If_Stmt); + pragma Inline (New_Else_Stmt); + pragma Inline (Finish_If_Stmt); + + pragma Inline (Start_Loop_Stmt); + pragma Inline (Finish_Loop_Stmt); + pragma Inline (New_Exit_Stmt); + pragma Inline (New_Next_Stmt); + + pragma Inline (Start_Case_Stmt); + pragma Inline (Start_Choice); + pragma Inline (New_Expr_Choice); + pragma Inline (New_Range_Choice); + pragma Inline (New_Default_Choice); + pragma Inline (Finish_Choice); + pragma Inline (Finish_Case_Stmt); +end Ortho_Mcode; diff --git a/src/ortho/mcode/ortho_nodes.ads b/src/ortho/mcode/ortho_nodes.ads new file mode 100644 index 000000000..7a2df3f30 --- /dev/null +++ b/src/ortho/mcode/ortho_nodes.ads @@ -0,0 +1,2 @@ +with Ortho_Mcode; +package Ortho_Nodes renames Ortho_Mcode; diff --git a/src/ortho/oread/Makefile b/src/ortho/oread/Makefile new file mode 100644 index 000000000..f94535181 --- /dev/null +++ b/src/ortho/oread/Makefile @@ -0,0 +1,43 @@ +# -*- Makefile -*- for the ortho-code compiler. +# Copyright (C) 2005 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. +BE = gcc +ortho_srcdir=.. +BACK_END=$(ortho_srcdir)/$(BE) +ortho_exec=oread-$(BE) + +all: $(ortho_exec) + +test: test.s + $(CC) -o $@ $^ + +test.s: $(ortho_exec) + ./$(ortho_exec) test + +$(ortho_exec): force + $(MAKE) -f $(BACK_END)/Makefile ortho_exec=$(ortho_exec) + +clean: + $(MAKE) -f $(BACK_END)/Makefile clean + $(RM) -f oread-gcc oread-mcode *.o *~ + +distclean: clean + $(MAKE) -f $(BACK_END)/Makefile distclean + +force: + +.PHONY: force diff --git a/src/ortho/oread/ortho_front.adb b/src/ortho/oread/ortho_front.adb new file mode 100644 index 000000000..84bbd1b9d --- /dev/null +++ b/src/ortho/oread/ortho_front.adb @@ -0,0 +1,2677 @@ +-- Ortho code compiler. +-- Copyright (C) 2005 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.Unchecked_Deallocation; +with Ortho_Nodes; use Ortho_Nodes; +with Ortho_Ident; use Ortho_Ident; +with Ada.Characters.Latin_1; use Ada.Characters.Latin_1; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Interfaces; use Interfaces; +with Ada.Exceptions; +--with GNAT.Debug_Pools; + +-- TODO: +-- uncomplete type: check for type redefinition + +package body Ortho_Front is + -- If true, emit line number before each statement. + -- If flase, keep line number indication in the source file. + Flag_Renumber : Boolean := True; + + procedure Init is + begin + null; + end Init; + + function Decode_Option (Opt : String_Acc; Arg : String_Acc) return Natural + is + pragma Unreferenced (Arg); + begin + if Opt.all = "-r" or Opt.all = "--ghdl-r" then + Flag_Renumber := True; + return 1; + else + return 0; + end if; + end Decode_Option; + + -- File buffer. + File_Name : String_Acc; + Buf : String (1 .. 2048 + 1); + Buf_Len : Natural; + Pos : Natural; + Lineno : Natural; + + Fd : File_Descriptor; + + Error : exception; + + procedure Puterr (Msg : String) + is + L : Integer; + pragma Unreferenced (L); + begin + L := Write (Standerr, Msg'Address, Msg'Length); + end Puterr; + + procedure Puterr (N : Natural) + is + Str : constant String := Natural'Image (N); + begin + Puterr (Str (Str'First + 1 .. Str'Last)); + end Puterr; + + procedure Newline_Err is + begin + Puterr ((1 => LF)); + end Newline_Err; + + procedure Scan_Error (Msg : String) is + begin + Puterr (File_Name.all); + Puterr (":"); + Puterr (Lineno); + Puterr (": "); + Puterr (Msg); + Newline_Err; + raise Error; + end Scan_Error; + + procedure Parse_Error (Msg : String); + pragma No_Return (Parse_Error); + + procedure Parse_Error (Msg : String) is + begin + Puterr (File_Name.all); + Puterr (":"); + Puterr (Lineno); + Puterr (": "); + Puterr (Msg); + Newline_Err; + raise Error; + end Parse_Error; + + +-- Uniq_Num : Natural := 0; + +-- function Get_Uniq_Id return O_Ident +-- is +-- Str : String (1 .. 8); +-- V : Natural; +-- begin +-- V := Uniq_Num; +-- Uniq_Num := Uniq_Num + 1; +-- Str (1) := 'L'; +-- Str (2) := '.'; +-- for I in reverse 3 .. Str'Last loop +-- Str (I) := Character'Val ((V mod 10) + Character'Pos('0')); +-- V := V / 10; +-- end loop; +-- return Get_Identifier (Str); +-- end Get_Uniq_Id; + + -- Get the next character. + -- Return NUL on end of file. + function Get_Char return Character + is + Res : Character; + begin + if Buf (Pos) = NUL then + -- Read line. + Buf_Len := Read (Fd, Buf'Address, Buf'Length - 1); + if Buf_Len = 0 then + -- End of file. + return NUL; + end if; + Pos := 1; + Buf (Buf_Len + 1) := NUL; + end if; + + Res := Buf (Pos); + Pos := Pos + 1; + return Res; + end Get_Char; + + procedure Unget_Char is + begin + if Pos = Buf'First then + raise Program_Error; + end if; + Pos := Pos - 1; + end Unget_Char; + + type Token_Type is + (Tok_Eof, + Tok_Line_Number, Tok_File_Name, Tok_Comment, + Tok_Ident, Tok_Num, Tok_String, Tok_Float_Num, + Tok_Plus, Tok_Minus, + Tok_Star, Tok_Div, Tok_Mod, Tok_Rem, + Tok_Sharp, + Tok_Not, Tok_Abs, + Tok_Or, Tok_And, Tok_Xor, + Tok_Equal, Tok_Not_Equal, + Tok_Greater, Tok_Greater_Eq, + Tok_Less, Tok_Less_Eq, + Tok_Colon, Tok_Semicolon, + Tok_Comma, Tok_Dot, Tok_Tick, Tok_Arob, Tok_Elipsis, + Tok_Assign, + Tok_Left_Paren, Tok_Right_Paren, + Tok_Left_Brace, Tok_Right_Brace, + Tok_Left_Brack, Tok_Right_Brack, + Tok_Unsigned, Tok_Signed, Tok_Float, + Tok_Array, Tok_Subarray, + Tok_Access, Tok_Record, Tok_Union, + Tok_Boolean, Tok_Enum, + Tok_If, Tok_Then, Tok_Else, Tok_Elsif, + Tok_Loop, Tok_Exit, Tok_Next, + Tok_Is, Tok_Of, Tok_All, + Tok_Return, + Tok_Type, + Tok_External, Tok_Private, Tok_Public, Tok_Local, + Tok_Procedure, Tok_Function, + Tok_Constant, Tok_Var, + Tok_Declare, Tok_Begin, Tok_End, + Tok_Case, Tok_When, Tok_Default, Tok_Arrow, + Tok_Null); + + type Hash_Type is new Unsigned_32; + + type Name_Type; + type Name_Acc is access Name_Type; + + -- Symbol table. + type Syment_Type; + type Syment_Acc is access Syment_Type; + type Syment_type is record + -- The hash for the symbol. + Hash : Hash_Type; + -- Identification of the symbol. + Ident : O_Ident; + -- Next symbol with the same collision. + Next : Syment_Acc; + -- Meaning of the symbol. + Name : Name_Acc; + end record; + + -- Well known identifiers (used for attributes). + Id_Address : Syment_Acc; + Id_Unchecked_Address : Syment_Acc; + Id_Subprg_Addr : Syment_Acc; + Id_Conv : Syment_Acc; + Id_Sizeof : Syment_Acc; + Id_Alignof : Syment_Acc; + Id_Alloca : Syment_Acc; + Id_Offsetof : Syment_Acc; + + Token_Number : Unsigned_64; + Token_Float : IEEE_Float_64; + Token_Ident : String (1 .. 256); + Token_Idlen : Natural; + Token_Hash : Hash_Type; + Token_Sym : Syment_Acc; + + -- The symbol table. + type Syment_Acc_Array is array (Hash_Type range <>) of Syment_Acc; + Hash_Max : constant Hash_Type := 511; + Symtable : Syment_Acc_Array (0 .. Hash_Max - 1) := (others => null); + + type Node_Kind is (Decl_Keyword, Decl_Type, Decl_Param, + Node_Function, Node_Procedure, Node_Object, Node_Field, + Node_Lit, + Type_Boolean, Type_Enum, + Type_Unsigned, Type_Signed, Type_Float, + Type_Array, Type_Subarray, + Type_Access, Type_Record, Type_Union); + subtype Nodes_Subprogram is Node_Kind range Node_Function .. Node_Procedure; + + type Node (<>); + type Node_Acc is access Node; + type Node (Kind : Node_Kind) is record + case Kind is + when Decl_Keyword => + -- Keyword. + -- A keyword is not a declaration since the identifier has only + -- one meaning (the keyword). + Keyword : Token_Type; + when Decl_Type + | Decl_Param + | Node_Function + | Node_Procedure + | Node_Object + | Node_Lit => + -- Declarations + -- All declarations but NODE_PROCEDURE have a type. + Decl_Dtype : Node_Acc; + Decl_Storage : O_Storage; + case Kind is + when Decl_Type => + -- Type declaration. + null; + when Decl_Param => + -- Parameter identifier. + Param_Name : Syment_Acc; + -- Parameter ortho node. + Param_Node : O_Dnode; + -- Next parameter of the parameters list. + Param_Next : Node_Acc; + when Node_Procedure + | Node_Function => + -- Subprogram symbol name. + Subprg_Name : Syment_Acc; + -- List of parameters. + Subprg_Params : Node_Acc; + -- Subprogram ortho node. + Subprg_Node : O_Dnode; + when Node_Object => + -- Name of the object (constant, variable). + Obj_Name : O_Ident; + -- Ortho node of the object. + Obj_Node : O_Dnode; + when Node_Lit => + -- Name of the literal. + Lit_Name : O_Ident; + -- Enum literal + Lit_Cnode : O_Cnode; + -- Next literal for the type. + Lit_Next : Node_Acc; + when others => + null; + end case; + when Node_Field => + -- Record field. + Field_Ident : Syment_Acc; + Field_Fnode : O_Fnode; + Field_Type : Node_Acc; + Field_Next : Node_Acc; + when Type_Signed + | Type_Unsigned + | Type_Float + | Type_Array + | Type_Subarray + | Type_Record + | Type_Union + | Type_Access + | Type_Boolean + | Type_Enum => + -- Ortho node type. + Type_Onode : O_Tnode; + case Kind is + when Type_Array => + Array_Index : Node_Acc; + Array_Element : Node_Acc; + when Type_Subarray => + Subarray_Base : Node_Acc; + --Subarray_Length : Natural; + when Type_Access => + Access_Dtype : Node_Acc; + when Type_Record + | Type_Union => + Record_Union_Fields : Node_Acc; + when Type_Enum + | Type_Boolean => + Enum_Lits : Node_Acc; + when Type_Float => + null; + when others => + null; + end case; + end case; + end record; + + type Scope_Type; + type Scope_Acc is access Scope_Type; + + type Name_Type is record + -- Current interpretation of the symbol. + Inter : Node_Acc; + -- Next declaration in the current scope. + Next : Syment_Acc; + -- Interpretation in a previous scope. + Up : Name_Acc; + -- Current scope. + Scope : Scope_Acc; + end record; + + type Scope_Type is record + -- Simply linked list of names. + Names : Syment_Acc; + -- Previous scope. + Prev : Scope_Acc; + end record; + + -- Return the current declaration for symbol SYM. + function Get_Decl (Sym : Syment_Acc) return Node_Acc; + pragma Inline (Get_Decl); + + procedure Scan_Char (C : Character) + is + R : Character; + begin + + if C = '\' then + R := Get_Char; + case R is + when 'n' => + R := LF; + when 'r' => + R := CR; + when ''' => + R := '''; + when '"' => -- " + R := '"'; -- " + when others => + Scan_Error ("bad character sequence \" & R); + end case; + else + R := C; + end if; + Token_Idlen := Token_Idlen + 1; + Token_Ident (Token_Idlen) := R; + end Scan_Char; + + function Get_Hash (Str : String) return Hash_Type + is + Res : Hash_Type; + begin + Res := 0; + for I in Str'Range loop + Res := Res * 31 + Character'Pos (Str (I)); + end loop; + return Res; + end Get_Hash; + + -- Previous token. + Tok_Previous : Token_Type; + + function Scan_Number (First_Char : Character) return Token_Type + is + function To_Digit (C : Character) return Integer is + begin + case C is + when '0' .. '9' => + return Character'Pos (C) - Character'Pos ('0'); + when 'A' .. 'F' => + return Character'Pos (C) - Character'Pos ('A') + 10; + when 'a' .. 'f' => + return Character'Pos (C) - Character'Pos ('a') + 10; + when others => + return -1; + end case; + end To_Digit; + + function Is_Digit (C : Character) return Boolean is + begin + case C is + when '0' .. '9' + | 'A' .. 'F' + | 'a' .. 'f' => + return True; + when others => + return False; + end case; + end Is_Digit; + + After_Point : Integer; + C : Character; + Exp : Integer; + Exp_Neg : Boolean; + Base : Unsigned_64; + begin + Token_Number := 0; + C := First_Char; + loop + Token_Number := Token_Number * 10 + Unsigned_64 (To_Digit (C)); + C := Get_Char; + exit when not Is_Digit (C); + end loop; + if C = '#' then + Base := Token_Number; + Token_Number := 0; + C := Get_Char; + loop + Token_Number := Token_Number * Base + Unsigned_64 (To_Digit (C)); + C := Get_Char; + exit when C = '#'; + end loop; + return Tok_Num; + end if; + if C = '.' then + -- A real number. + After_Point := 0; + Token_Float := IEEE_Float_64 (Token_Number); + loop + C := Get_Char; + exit when C not in '0' .. '9'; + Token_Float := Token_Float * 10.0 + IEEE_Float_64 (To_Digit (C)); + After_Point := After_Point + 1; + end loop; + if C = 'e' or C = 'E' then + Exp := 0; + C := Get_Char; + Exp_Neg := False; + if C = '-' then + Exp_Neg := True; + C := Get_Char; + elsif C = '+' then + C := Get_Char; + elsif not Is_Digit (C) then + Scan_Error ("digit expected"); + end if; + while Is_Digit (C) loop + Exp := Exp * 10 + To_Digit (C); + C := Get_Char; + end loop; + if Exp_Neg then + Exp := -Exp; + end if; + Exp := Exp - After_Point; + else + Exp := - After_Point; + end if; + Unget_Char; + Token_Float := Token_Float * 10.0 ** Exp; + if Token_Float > IEEE_Float_64'Last then + Token_Float := IEEE_Float_64'Last; + end if; + return Tok_Float_Num; + else + Unget_Char; + return Tok_Num; + end if; + end Scan_Number; + + procedure Scan_Comment + is + C : Character; + begin + Token_Idlen := 0; + loop + C := Get_Char; + exit when C = CR or C = LF; + Token_Idlen := Token_Idlen + 1; + Token_Ident (Token_Idlen) := C; + end loop; + Unget_Char; + end Scan_Comment; + + -- Get the next token. + function Get_Token return Token_Type + is + C : Character; + begin + loop + + C := Get_Char; + << Again >> null; + case C is + when NUL => + return Tok_Eof; + when ' ' | HT => + null; + when LF => + Lineno := Lineno + 1; + C := Get_Char; + if C /= CR then + goto Again; + end if; + when CR => + Lineno := Lineno + 1; + C := Get_Char; + if C /= LF then + goto Again; + end if; + when '+' => + return Tok_Plus; + when '-' => + C := Get_Char; + if C = '-' then + C := Get_Char; + if C = '#' then + return Tok_Line_Number; + elsif C = 'F' then + Scan_Comment; + return Tok_File_Name; + elsif C = ' ' then + Scan_Comment; + return Tok_Comment; + else + Scan_Error ("bad comment"); + end if; + else + Unget_Char; + return Tok_Minus; + end if; + when '/' => + C := Get_Char; + if C = '=' then + return Tok_Not_Equal; + else + Unget_Char; + return Tok_Div; + end if; + when '*' => + return Tok_Star; + when '#' => + return Tok_Sharp; + when '=' => + C := Get_Char; + if C = '>' then + return Tok_Arrow; + else + Unget_Char; + return Tok_Equal; + end if; + when '>' => + C := Get_Char; + if C = '=' then + return Tok_Greater_Eq; + else + Unget_Char; + return Tok_Greater; + end if; + when '(' => + return Tok_Left_Paren; + when ')' => + return Tok_Right_Paren; + when '{' => + return Tok_Left_Brace; + when '}' => + return Tok_Right_Brace; + when '[' => + return Tok_Left_Brack; + when ']' => + return Tok_Right_Brack; + when '<' => + C := Get_Char; + if C = '=' then + return Tok_Less_Eq; + else + Unget_Char; + return Tok_Less; + end if; + when ':' => + C := Get_Char; + if C = '=' then + return Tok_Assign; + else + Unget_Char; + return Tok_Colon; + end if; + when '.' => + C := Get_Char; + if C = '.' then + C := Get_Char; + if C = '.' then + return Tok_Elipsis; + else + Scan_Error ("'...' expected"); + end if; + else + Unget_Char; + return Tok_Dot; + end if; + when ';' => + return Tok_Semicolon; + when ',' => + return Tok_Comma; + when '@' => + return Tok_Arob; + when ''' => + if Tok_Previous = Tok_Ident then + return Tok_Tick; + else + Token_Number := Character'Pos (Get_Char); + C := Get_Char; + if C /= ''' then + Scan_Error ("ending single quote expected"); + end if; + return Tok_Num; + end if; + when '"' => -- " + -- Eat double quote. + C := Get_Char; + Token_Idlen := 0; + loop + Scan_Char (C); + C := Get_Char; + exit when C = '"'; -- " + end loop; + return Tok_String; + when '0' .. '9' => + return Scan_Number (C); + when 'a' .. 'z' + | 'A' .. 'Z' + | '_' => + Token_Idlen := 0; + Token_Hash := 0; + loop + Token_Idlen := Token_Idlen + 1; + Token_Ident (Token_Idlen) := C; + Token_Hash := Token_Hash * 31 + Character'Pos (C); + C := Get_Char; + exit when (C < 'A' or C > 'Z') + and (C < 'a' or C > 'z') + and (C < '0' or C > '9') + and (C /= '_'); + end loop; + Unget_Char; + declare + H : Hash_Type; + S : Syment_Acc; + N : Node_Acc; + begin + H := Token_Hash mod Hash_Max; + S := Symtable (H); + while S /= null loop + if S.Hash = Token_Hash + and then Is_Equal (S.Ident, + Token_Ident (1 .. Token_Idlen)) + then + -- This identifier is known. + Token_Sym := S; + + -- It may be a keyword. + if S.Name /= null then + N := Get_Decl (S); + if N.Kind = Decl_Keyword then + return N.Keyword; + end if; + end if; + + return Tok_Ident; + end if; + S := S.Next; + end loop; + Symtable (H) := new Syment_Type' + (Hash => Token_Hash, + Ident => Get_Identifier (Token_Ident (1 .. Token_Idlen)), + Next => Symtable (H), + Name => null); + Token_Sym := Symtable (H); + return Tok_Ident; + end; + when others => + Scan_Error ("Bad character:" + & Integer'Image (Character'Pos (C)) + & C); + return Tok_Eof; + end case; + end loop; + end Get_Token; + + -- The current token. + Tok : Token_Type; + + procedure Next_Token is + begin + Tok_Previous := Tok; + Tok := Get_Token; + end Next_Token; + + procedure Expect (T : Token_Type; Msg : String := "") is + begin + if Tok /= T then + if Msg'Length = 0 then + case T is + when Tok_Left_Brace => + Parse_Error ("'{' expected"); + when others => + if Tok = Tok_Ident then + Parse_Error + (Token_Type'Image (T) & " expected, found '" & + Token_Ident (1 .. Token_Idlen) & "'"); + else + Parse_Error (Token_Type'Image (T) & " expected, found " + & Token_Type'Image (Tok)); + end if; + end case; + else + Parse_Error (Msg); + end if; + end if; + end Expect; + + procedure Next_Expect (T : Token_Type; Msg : String := "") is + begin + Next_Token; + Expect (T, Msg); + end Next_Expect; + + -- Scopes and identifiers. + + + -- Current scope. + Scope : Scope_Acc := null; + + -- Add a declaration for symbol SYM in the current scope. + -- INTER defines the meaning of the declaration. + -- There must be at most one declaration for a symbol in the current scope, + -- i.e. a symbol cannot be redefined. + procedure Add_Decl (Sym : Syment_Acc; Inter : Node_Acc); + + -- Return TRUE iff SYM is already defined in the current scope. + function Is_Defined (Sym : Syment_Acc) return Boolean; + + -- Create new scope. + procedure Push_Scope; + + -- Close the current scope. Symbols defined in the scope regain their + -- previous declaration. + procedure Pop_Scope; + + + procedure Push_Scope + is + Nscope : Scope_Acc; + begin + Nscope := new Scope_Type'(Names => null, Prev => Scope); + Scope := Nscope; + end Push_Scope; + + procedure Pop_Scope + is + procedure Free is new Ada.Unchecked_Deallocation + (Object => Name_Type, Name => Name_Acc); + + procedure Free is new Ada.Unchecked_Deallocation + (Object => Scope_Type, Name => Scope_Acc); + + Sym : Syment_Acc; + N_Sym : Syment_Acc; + Name : Name_Acc; + Old_Scope : Scope_Acc; + begin + Sym := Scope.Names; + while Sym /= null loop + Name := Sym.Name; + -- Check. + if Name.Scope /= Scope then + raise Program_Error; + end if; + + -- Set the interpretation of this symbol. + Sym.Name := Name.Up; + + N_Sym := Name.Next; + + Free (Name); + Sym := N_Sym; + end loop; + + -- Free scope. + Old_Scope := Scope; + Scope := Scope.Prev; + Free (Old_Scope); + end Pop_Scope; + + function Is_Defined (Sym : Syment_Acc) return Boolean is + begin + if Sym.Name /= null + and then Sym.Name.Scope = Scope + then + return True; + else + return False; + end if; + end Is_Defined; + + function New_Symbol (Str : String) return Syment_Acc + is + Ent : Syment_Acc; + H : Hash_Type; + begin + Ent := new Syment_Type'(Hash => Get_Hash (Str), + Ident => Get_Identifier (Str), + Next => null, + Name => null); + H := Ent.Hash mod Hash_Max; + Ent.Next := Symtable (H); + Symtable (H) := Ent; + return Ent; + end New_Symbol; + + procedure Add_Keyword (Str : String; Token : Token_Type) + is + Ent : Syment_Acc; + begin + Ent := New_Symbol (Str); + if Ent.Name /= null + or else Scope /= null + then + -- Redefinition of a keyword. + raise Program_Error; + end if; + Ent.Name := new Name_Type'(Inter => new Node'(Kind => Decl_Keyword, + Keyword => Token), + Next => null, + Up => null, + Scope => null); + end Add_Keyword; + + procedure Add_Decl (Sym : Syment_Acc; Inter : Node_Acc) + is + Name : Name_Acc; + Prev : Node_Acc; + begin + Name := Sym.Name; + if Name /= null and then Name.Scope = Scope then + Prev := Name.Inter; + if Prev.Kind = Inter.Kind + and then Prev.Decl_Dtype = Inter.Decl_Dtype + and then Prev.Decl_Storage = O_Storage_External + and then Inter.Decl_Storage = O_Storage_Public + then + -- Redefinition + Name.Inter := Inter; + return; + end if; + Parse_Error ("redefinition of " & Get_String (Sym.Ident)); + end if; + Name := new Name_Type'(Inter => Inter, + Next => Scope.Names, + Up => Sym.Name, + Scope => Scope); + Sym.Name := Name; + Scope.Names := Sym; + end Add_Decl; + + function Get_Decl (Sym : Syment_Acc) return Node_Acc is + begin + if Sym.Name = null then + Parse_Error ("undefined identifier " & Get_String (Sym.Ident)); + else + return Sym.Name.Inter; + end if; + end Get_Decl; + + function Parse_Constant_Value (Atype : Node_Acc) return O_Cnode; + function Parse_Address (Prefix : Node_Acc) return O_Enode; + function Parse_Constant_Address (Prefix : Node_Acc) return O_Cnode; + procedure Parse_Declaration; + procedure Parse_Compound_Statement; + + function Parse_Type return Node_Acc; + + procedure Parse_Fields (Aggr_Type : Node_Acc; + Constr : in out O_Element_List) + is + F_Type : Node_Acc; + F : Syment_Acc; + Last_Field : Node_Acc; + Field : Node_Acc; + begin + Last_Field := null; + loop + exit when Tok = Tok_End; + + if Tok /= Tok_Ident then + Parse_Error ("field name expected"); + end if; + F := Token_Sym; + Next_Expect (Tok_Colon, "':' expected"); + Next_Token; + F_Type := Parse_Type; + Field := new Node'(Kind => Node_Field, + Field_Ident => F, + Field_Fnode => O_Fnode_Null, + Field_Type => F_Type, + Field_Next => null); + case Aggr_Type.Kind is + when Type_Record => + New_Record_Field (Constr, Field.Field_Fnode, F.Ident, + F_Type.Type_Onode); + when Type_Union => + New_Union_Field (Constr, Field.Field_Fnode, F.Ident, + F_Type.Type_Onode); + when others => + raise Program_Error; + end case; + if Last_Field = null then + Aggr_Type.Record_Union_Fields := Field; + else + Last_Field.Field_Next := Field; + end if; + Last_Field := Field; + Expect (Tok_Semicolon, "';' expected"); + Next_Token; + end loop; + end Parse_Fields; + + procedure Parse_Record_Type (Def : Node_Acc) + is + Constr : O_Element_List; + begin + if Def.Type_Onode = O_Tnode_Null then + Start_Record_Type (Constr); + else + Start_Uncomplete_Record_Type (Def.Type_Onode, Constr); + end if; + Parse_Fields (Def, Constr); + Next_Expect (Tok_Record, "end record expected"); + Finish_Record_Type (Constr, Def.Type_Onode); + end Parse_Record_Type; + + procedure Parse_Union_Type (Def : Node_Acc) + is + Constr : O_Element_List; + begin + Start_Union_Type (Constr); + Parse_Fields (Def, Constr); + Next_Expect (Tok_Union, "end union expected"); + Finish_Union_Type (Constr, Def.Type_Onode); + end Parse_Union_Type; + + function Parse_Type return Node_Acc + is + Res : Node_Acc; + T : Token_Type; + begin + T := Tok; + case T is + when Tok_Unsigned + | Tok_Signed => + Next_Expect (Tok_Left_Paren, "'(' expected"); + Next_Expect (Tok_Num, "number expected"); + case T is + when Tok_Unsigned => + Res := new Node' + (Kind => Type_Unsigned, + Type_Onode => New_Unsigned_Type (Natural + (Token_Number))); + when Tok_Signed => + Res := new Node' + (Kind => Type_Signed, + Type_Onode => New_Signed_Type (Natural + (Token_Number))); + when others => + raise Program_Error; + end case; + Next_Expect (Tok_Right_Paren, "')' expected"); + when Tok_Float => + Res := new Node'(Kind => Type_Float, + Type_Onode => New_Float_Type); + when Tok_Array => + declare + Index_Node : Node_Acc; + El_Node : Node_Acc; + begin + Next_Expect (Tok_Left_Brack, "'[' expected"); + Next_Token; + Index_Node := Parse_Type; + Expect (Tok_Right_Brack, "']' expected"); + Next_Expect (Tok_Of, "'of' expected"); + Next_Token; + El_Node := Parse_Type; + Res := new Node' + (Kind => Type_Array, + Type_Onode => New_Array_Type (El_Node.Type_Onode, + Index_Node.Type_Onode), + Array_Index => Index_Node, + Array_Element => El_Node); + end; + return Res; + when Tok_Subarray => + declare + Base_Node : Node_Acc; + Res_Type : O_Tnode; + begin + Next_Token; + Base_Node := Parse_Type; + Expect (Tok_Left_Brack); + Next_Token; + Res_Type := New_Constrained_Array_Type + (Base_Node.Type_Onode, + Parse_Constant_Value (Base_Node.Array_Index)); + Expect (Tok_Right_Brack); + Next_Token; + Res := new Node' (Kind => Type_Subarray, + Type_Onode => Res_Type, + Subarray_Base => Base_Node); + return Res; + end; + when Tok_Ident => + declare + Inter : Node_Acc; + begin + Inter := Get_Decl (Token_Sym); + if Inter = null then + Parse_Error ("undefined type name symbol " + & Get_String (Token_Sym.Ident)); + end if; + if Inter.Kind /= Decl_Type then + Parse_Error ("type declarator expected"); + end if; + Res := Inter.Decl_Dtype; + end; + when Tok_Access => + declare + Dtype : Node_Acc; + begin + Next_Token; + if Tok = Tok_Semicolon then + Res := new Node' + (Kind => Type_Access, + Type_Onode => New_Access_Type (O_Tnode_Null), + Access_Dtype => null); + else + Dtype := Parse_Type; + Res := new Node' + (Kind => Type_Access, + Type_Onode => New_Access_Type (Dtype.Type_Onode), + Access_Dtype => Dtype); + end if; + return Res; + end; + when Tok_Record => + Next_Token; + if Tok = Tok_Semicolon then + -- Uncomplete record type. + Res := new Node'(Kind => Type_Record, + Type_Onode => O_Tnode_Null, + Record_Union_Fields => null); + New_Uncomplete_Record_Type (Res.Type_Onode); + return Res; + end if; + + Res := new Node'(Kind => Type_Record, + Type_Onode => O_Tnode_Null, + Record_Union_Fields => null); + Parse_Record_Type (Res); + when Tok_Union => + Next_Token; + Res := new Node'(Kind => Type_Union, + Type_Onode => O_Tnode_Null, + Record_Union_Fields => null); + Parse_Union_Type (Res); + + when Tok_Boolean => + declare + False_Lit, True_Lit : Node_Acc; + begin + Res := new Node'(Kind => Type_Boolean, + Type_Onode => O_Tnode_Null, + Enum_Lits => null); + Next_Expect (Tok_Left_Brace, "'{' expected"); + Next_Expect (Tok_Ident, "identifier expected"); + False_Lit := new Node'(Kind => Node_Lit, + Decl_Dtype => Res, + Decl_Storage => O_Storage_Public, + Lit_Name => Token_Sym.Ident, + Lit_Cnode => O_Cnode_Null, + Lit_Next => null); + Next_Expect (Tok_Comma, "',' expected"); + Next_Expect (Tok_Ident, "identifier expected"); + True_Lit := new Node'(Kind => Node_Lit, + Decl_Dtype => Res, + Decl_Storage => O_Storage_Public, + Lit_Name => Token_Sym.Ident, + Lit_Cnode => O_Cnode_Null, + Lit_Next => null); + Next_Expect (Tok_Right_Brace, "'}' expected"); + False_Lit.Lit_Next := True_Lit; + Res.Enum_Lits := False_Lit; + New_Boolean_Type (Res.Type_Onode, + False_Lit.Lit_Name, False_Lit.Lit_Cnode, + True_Lit.Lit_Name, True_Lit.Lit_Cnode); + end; + when Tok_Enum => + declare + List : O_Enum_List; + Lit : Node_Acc; + Last_Lit : Node_Acc; + begin + Res := new Node'(Kind => Type_Enum, + Type_Onode => O_Tnode_Null, + Enum_Lits => null); + Last_Lit := null; + Push_Scope; + Next_Expect (Tok_Left_Brace); + Next_Token; + -- FIXME: set a size to the enum. + Start_Enum_Type (List, 8); + loop + Expect (Tok_Ident); + Lit := new Node'(Kind => Node_Lit, + Decl_Dtype => Res, + Decl_Storage => O_Storage_Public, + Lit_Name => Token_Sym.Ident, + Lit_Cnode => O_Cnode_Null, + Lit_Next => null); + Add_Decl (Token_Sym, Lit); + New_Enum_Literal (List, Lit.Lit_Name, Lit.Lit_Cnode); + if Last_Lit = null then + Res.Enum_Lits := Lit; + else + Last_Lit.Lit_Next := Lit; + end if; + Last_Lit := Lit; + Next_Expect (Tok_Equal); + Next_Expect (Tok_Num); + Next_Token; + exit when Tok = Tok_Right_Brace; + Expect (Tok_Comma); + Next_Token; + end loop; + Finish_Enum_Type (List, Res.Type_Onode); + Pop_Scope; + end; + when others => + Parse_Error ("bad type " & Token_Type'Image (Tok)); + return null; + end case; + Next_Token; + return Res; + end Parse_Type; + + procedure Parse_Type_Completion (Decl : Node_Acc) + is + begin + case Tok is + when Tok_Record => + Next_Token; + Parse_Record_Type (Decl.Decl_Dtype); + Next_Token; + when Tok_Access => + Next_Token; + declare + Dtype : Node_Acc; + begin + Dtype := Parse_Type; + Decl.Decl_Dtype.Access_Dtype := Dtype; + Finish_Access_Type (Decl.Decl_Dtype.Type_Onode, + Dtype.Type_Onode); + end; + when others => + Parse_Error ("'access' or 'record' expected"); + end case; + end Parse_Type_Completion; + +-- procedure Parse_Declaration; + + procedure Parse_Expression (Expr_Type : Node_Acc; + Expr : out O_Enode; + Res_Type : out Node_Acc); + procedure Parse_Name (Prefix : Node_Acc; + Name : out O_Lnode; N_Type : out Node_Acc); + procedure Parse_Lvalue (N : in out O_Lnode; N_Type : in out Node_Acc); + + -- Expect: '(' + -- Let: next token. + procedure Parse_Association (Constr : in out O_Assoc_List; + Decl : Node_Acc); + + function Find_Field_By_Name (Aggr_Type : Node_Acc) return Node_Acc + is + Field : Node_Acc; + begin + Field := Aggr_Type.Record_Union_Fields; + while Field /= null loop + exit when Field.Field_Ident = Token_Sym; + Field := Field.Field_Next; + end loop; + if Field = null then + Parse_Error ("no such field name"); + end if; + return Field; + end Find_Field_By_Name; + + -- expect: offsetof id. + function Parse_Offsetof (Atype : Node_Acc) return O_Cnode + is + Rec_Type : Node_Acc; + Rec_Field : Node_Acc; + begin + Next_Expect (Tok_Left_Paren); + Next_Expect (Tok_Ident); + Rec_Type := Get_Decl (Token_Sym); + if Rec_Type.Kind /= Decl_Type + or else Rec_Type.Decl_Dtype.Kind /= Type_Record + then + Parse_Error ("type name expected"); + end if; + Next_Expect (Tok_Dot); + Next_Expect (Tok_Ident); + Rec_Field := Find_Field_By_Name (Rec_Type.Decl_Dtype); + Next_Expect (Tok_Right_Paren); + return New_Offsetof (Rec_Type.Decl_Dtype.Type_Onode, + Rec_Field.Field_Fnode, + Atype.Type_Onode); + end Parse_Offsetof; + + function Parse_Sizeof (Atype : Node_Acc) return O_Cnode + is + Res : O_Cnode; + begin + Next_Expect (Tok_Left_Paren); + Next_Token; + if Tok /= Tok_Ident then + Parse_Error ("type name expected"); + end if; + Res := New_Sizeof + (Get_Decl (Token_Sym).Decl_Dtype.Type_Onode, + Atype.Type_Onode); + Next_Expect (Tok_Right_Paren); + return Res; + end Parse_Sizeof; + + function Parse_Alignof (Atype : Node_Acc) return O_Cnode + is + Res : O_Cnode; + begin + Next_Expect (Tok_Left_Paren); + Next_Token; + if Tok /= Tok_Ident then + Parse_Error ("type name expected"); + end if; + Res := New_Alignof + (Get_Decl (Token_Sym).Decl_Dtype.Type_Onode, + Atype.Type_Onode); + Next_Expect (Tok_Right_Paren); + return Res; + end Parse_Alignof; + + -- Parse a literal whose type is ATYPE. + function Parse_Typed_Literal (Atype : Node_Acc) return O_Cnode + is + Res : O_Cnode; + begin + case Tok is + when Tok_Num => + case Atype.Kind is + when Type_Signed => + Res := New_Signed_Literal + (Atype.Type_Onode, Integer_64 (Token_Number)); + when Type_Unsigned => + Res := New_Unsigned_Literal + (Atype.Type_Onode, Token_Number); + when others => + Parse_Error ("bad type for integer literal"); + end case; + when Tok_Minus => + Next_Token; + case Tok is + when Tok_Num => + declare + V : Integer_64; + begin + if Token_Number = Unsigned_64 (Integer_64'Last) + 1 then + V := Integer_64'First; + else + V := -Integer_64 (Token_Number); + end if; + Res := New_Signed_Literal (Atype.Type_Onode, V); + end; + when Tok_Float_Num => + Res := New_Float_Literal (Atype.Type_Onode, -Token_Float); + when others => + Parse_Error ("bad token after '-'"); + end case; + when Tok_Float_Num => + Res := New_Float_Literal (Atype.Type_Onode, Token_Float); + when Tok_Ident => + declare + Pfx : Node_Acc; + N : Node_Acc; + begin + -- Note: we don't use get_decl, since the name can be a literal + -- name, which is not directly visible. + if Token_Sym.Name /= null + and then Token_Sym.Name.Inter.Kind = Decl_Type + then + -- A typed expression. + Pfx := Token_Sym.Name.Inter; + N := Pfx.Decl_Dtype; + if Atype /= null and then N /= Atype then + Parse_Error ("type mismatch"); + end if; + Next_Expect (Tok_Tick); + Next_Token; + if Tok = Tok_Left_Brack then + Next_Token; + Res := Parse_Typed_Literal (N); + Expect (Tok_Right_Brack); + elsif Tok = Tok_Ident then + if Token_Sym = Id_Offsetof then + Res := Parse_Offsetof (N); + elsif Token_Sym = Id_Sizeof then + Res := Parse_Sizeof (N); + elsif Token_Sym = Id_Alignof then + Res := Parse_Alignof (N); + elsif Token_Sym = Id_Address + or Token_Sym = Id_Unchecked_Address + or Token_Sym = Id_Subprg_Addr + then + Res := Parse_Constant_Address (Pfx); + elsif Token_Sym = Id_Conv then + Next_Expect (Tok_Left_Paren); + Next_Token; + Res := Parse_Typed_Literal (N); + Expect (Tok_Right_Paren); + else + Parse_Error ("offsetof or sizeof attributes expected"); + end if; + else + Parse_Error ("'[' or attribute expected"); + end if; + else + if Atype.Kind /= Type_Enum + and then Atype.Kind /= Type_Boolean + then + Parse_Error ("name allowed only for enumeration"); + end if; + N := Atype.Enum_Lits; + while N /= null loop + if Is_Equal (N.Lit_Name, Token_Sym.Ident) then + Res := N.Lit_Cnode; + exit; + end if; + N := N.Lit_Next; + end loop; + if N = null then + Parse_Error ("no matching literal"); + return O_Cnode_Null; + end if; + end if; + end; + when Tok_Null => + Res := New_Null_Access (Atype.Type_Onode); + when others => + Parse_Error ("bad primary expression: " & Token_Type'Image (Tok)); + return O_Cnode_Null; + end case; + Next_Token; + return Res; + end Parse_Typed_Literal; + + -- expect: next token + -- Parse an expression starting with NAME. + procedure Parse_Named_Expression + (Atype : Node_Acc; Name : Node_Acc; Stop_At_All : Boolean; + Res : out O_Enode; + Res_Type : out Node_Acc) + is + begin + if Tok = Tok_Tick then + Next_Token; + if Tok = Tok_Left_Brack then + -- Typed literal. + Next_Token; + Res := New_Lit (Parse_Typed_Literal (Name.Decl_Dtype)); + Res_Type := Name.Decl_Dtype; + Expect (Tok_Right_Brack); + Next_Token; + elsif Tok = Tok_Left_Paren then + -- Typed expression (used for comparaison operators) + Next_Token; + Parse_Expression (Name.Decl_Dtype, Res, Res_Type); + Expect (Tok_Right_Paren); + Next_Token; + elsif Tok = Tok_Ident then + -- Attribute. + if Token_Sym = Id_Conv then + Next_Expect (Tok_Left_Paren); + Next_Token; + Parse_Expression (null, Res, Res_Type); + -- Discard Res_Type. + Expect (Tok_Right_Paren); + Next_Token; + Res_Type := Name.Decl_Dtype; + Res := New_Convert_Ov (Res, Res_Type.Type_Onode); + -- Fall-through. + elsif Token_Sym = Id_Address + or Token_Sym = Id_Unchecked_Address + or Token_Sym = Id_Subprg_Addr + then + Res_Type := Name.Decl_Dtype; + Res := Parse_Address (Name); + -- Fall-through. + elsif Token_Sym = Id_Sizeof then + Res_Type := Name.Decl_Dtype; + Res := New_Lit (Parse_Sizeof (Res_Type)); + Next_Token; + return; + elsif Token_Sym = Id_Alignof then + Res_Type := Name.Decl_Dtype; + Res := New_Lit (Parse_Alignof (Res_Type)); + Next_Token; + return; + elsif Token_Sym = Id_Alloca then + Next_Expect (Tok_Left_Paren); + Next_Token; + Parse_Expression (null, Res, Res_Type); + -- Discard Res_Type. + Res_Type := Name.Decl_Dtype; + Res := New_Alloca (Res_Type.Type_Onode, Res); + Expect (Tok_Right_Paren); + Next_Token; + return; + elsif Token_Sym = Id_Offsetof then + Res_Type := Atype; + Res := New_Lit (Parse_Offsetof (Res_Type)); + Next_Token; + return; + else + Parse_Error ("unknown attribute name"); + end if; + -- Fall-through. + else + Parse_Error ("typed expression expected"); + end if; + elsif Tok = Tok_Left_Paren then + if Name.Kind /= Node_Function then + Parse_Error ("function name expected"); + end if; + declare + Constr : O_Assoc_List; + begin + Parse_Association (Constr, Name); + Res := New_Function_Call (Constr); + Res_Type := Name.Decl_Dtype; + -- Fall-through. + end; + elsif Name.Kind = Node_Object + or else Name.Kind = Decl_Param + then + -- Name. + declare + Lval : O_Lnode; + begin + Parse_Name (Name, Lval, Res_Type); + Res := New_Value (Lval); + end; + else + Parse_Error ("bad ident expression: " + & Token_Type'Image (Tok)); + end if; + + -- Continue. + -- R_TYPE and RES must be set. + if Tok = Tok_Dot then + if Stop_At_All then + return; + end if; + Next_Token; + if Tok = Tok_All then + if Res_Type.Kind /= Type_Access then + Parse_Error ("type of prefix is not an access"); + end if; + declare + N : O_Lnode; + begin + Next_Token; + N := New_Access_Element (Res); + Res_Type := Res_Type.Access_Dtype; + Parse_Lvalue (N, Res_Type); + Res := New_Value (N); + end; + return; + else + Parse_Error ("'.all' expected"); + end if; + end if; + end Parse_Named_Expression; + + procedure Parse_Primary_Expression (Atype : Node_Acc; + Res : out O_Enode; + Res_Type : out Node_Acc) + is + begin + case Tok is + when Tok_Num + | Tok_Float_Num => + if Atype = null then + Parse_Error ("numeric literal without type context"); + end if; + Res_Type := Atype; + Res := New_Lit (Parse_Typed_Literal (Atype)); + when Tok_Ident => + declare + N : Node_Acc; + begin + N := Get_Decl (Token_Sym); + Next_Token; + Parse_Named_Expression (Atype, N, False, Res, Res_Type); + end; + when Tok_Left_Paren => + Next_Token; + Parse_Expression (Atype, Res, Res_Type); + Expect (Tok_Right_Paren); + Next_Token; + when others => + Parse_Error ("bad primary expression: " & Token_Type'Image (Tok)); + end case; + end Parse_Primary_Expression; + + -- Parse '-' EXPR, 'not' EXPR, 'abs' EXPR or EXPR. + procedure Parse_Unary_Expression (Atype : Node_Acc; + Res : out O_Enode; + Res_Type : out Node_Acc) + is + begin + case Tok is + when Tok_Minus => + Next_Token; + Parse_Primary_Expression (Atype, Res, Res_Type); + Res := New_Monadic_Op (ON_Neg_Ov, Res); + when Tok_Not => + Next_Token; + Parse_Unary_Expression (Atype, Res, Res_Type); + Res := New_Monadic_Op (ON_Not, Res); + when Tok_Abs => + Next_Token; + Parse_Unary_Expression (Atype, Res, Res_Type); + Res := New_Monadic_Op (ON_Abs_Ov, Res); + when others => + Parse_Primary_Expression (Atype, Res, Res_Type); + end case; + end Parse_Unary_Expression; + + function Check_Sharp (Op_Ov : ON_Op_Kind) return ON_Op_Kind is + begin + Next_Expect (Tok_Sharp); + Next_Token; + return Op_Ov; + end Check_Sharp; + + procedure Parse_Expression (Expr_Type : Node_Acc; + Expr : out O_Enode; + Res_Type : out Node_Acc) + is + Op_Type : Node_Acc; + L : O_Enode; + R : O_Enode; + Op : ON_Op_Kind; + begin + if Expr_Type = null or else Expr_Type.Kind = Type_Boolean then + -- The type of the expression isn't known, as this can be a + -- comparaison operator. + Op_Type := null; + else + Op_Type := Expr_Type; + end if; + Parse_Unary_Expression (Op_Type, L, Res_Type); + case Tok is + when Tok_Div => + Op := Check_Sharp (ON_Div_Ov); + when Tok_Plus => + Op := Check_Sharp (ON_Add_Ov); + when Tok_Minus => + Op := Check_Sharp (ON_Sub_Ov); + when Tok_Star => + Op := Check_Sharp (ON_Mul_Ov); + when Tok_Mod => + Op := Check_Sharp (ON_Mod_Ov); + when Tok_Rem => + Op := Check_Sharp (ON_Rem_Ov); + + when Tok_Equal => + Op := ON_Eq; + when Tok_Not_Equal => + Op := ON_Neq; + when Tok_Greater => + Op := ON_Gt; + when Tok_Greater_Eq => + Op := ON_Ge; + when Tok_Less => + Op := ON_Lt; + when Tok_Less_Eq => + Op := ON_Le; + + when Tok_Or => + Op := ON_Or; + Next_Token; + when Tok_And => + Op := ON_And; + Next_Token; + when Tok_Xor => + Op := ON_Xor; + Next_Token; + + when others => + Expr := L; + return; + end case; + if Op in ON_Compare_Op_Kind then + Next_Token; + end if; + + Parse_Unary_Expression (Res_Type, R, Res_Type); + case Op is + when ON_Dyadic_Op_Kind => + Expr := New_Dyadic_Op (Op, L, R); + when ON_Compare_Op_Kind => + if Expr_Type = null then + Parse_Error ("comparaison operator requires a type"); + end if; + Expr := New_Compare_Op (Op, L, R, Expr_Type.Type_Onode); + Res_Type := Expr_Type; + when others => + raise Program_Error; + end case; + end Parse_Expression; + + -- Expect and leave: next token + procedure Parse_Lvalue (N : in out O_Lnode; N_Type : in out Node_Acc) + is + begin + loop + case Tok is + when Tok_Dot => + Next_Token; + if Tok = Tok_All then + if N_Type.Kind /= Type_Access then + Parse_Error ("type of prefix is not an access"); + end if; + N := New_Access_Element (New_Value (N)); + N_Type := N_Type.Access_Dtype; + Next_Token; + elsif Tok = Tok_Ident then + if N_Type.Kind /= Type_Record and N_Type.Kind /= Type_Union + then + Parse_Error + ("type of prefix is neither a record nor an union"); + end if; + declare + Field : Node_Acc; + begin + Field := Find_Field_By_Name (N_Type); + N := New_Selected_Element (N, Field.Field_Fnode); + N_Type := Field.Field_Type; + Next_Token; + end; + else + Parse_Error + ("'.' must be followed by 'all' or a field name"); + end if; + when Tok_Left_Brack => + declare + V : O_Enode; + Bt : Node_Acc; + Res_Type : Node_Acc; + begin + Next_Token; + if N_Type.Kind = Type_Subarray then + Bt := N_Type.Subarray_Base; + else + Bt := N_Type; + end if; + if Bt.Kind /= Type_Array then + Parse_Error ("type of prefix is not an array"); + end if; + Parse_Expression (Bt.Array_Index, V, Res_Type); + if Tok = Tok_Elipsis then + N := New_Slice (N, Bt.Type_Onode, V); + Next_Token; + else + N := New_Indexed_Element (N, V); + N_Type := Bt.Array_Element; + end if; + Expect (Tok_Right_Brack); + Next_Token; + end; + when others => + return; + end case; + end loop; + end Parse_Lvalue; + + procedure Parse_Name (Prefix : Node_Acc; + Name : out O_Lnode; N_Type : out Node_Acc) + is + begin + case Prefix.Kind is + when Decl_Param => + Name := New_Obj (Prefix.Param_Node); + N_Type := Prefix.Decl_Dtype; + when Node_Object => + Name := New_Obj (Prefix.Obj_Node); + N_Type := Prefix.Decl_Dtype; + when Decl_Type => + declare + Val : O_Enode; + begin + Parse_Named_Expression (null, Prefix, True, Val, N_Type); + if N_Type /= Prefix.Decl_Dtype then + Parse_Error ("type doesn't match"); + end if; + if Tok = Tok_Dot then + Next_Token; + if Tok = Tok_All then + if N_Type.Kind /= Type_Access then + Parse_Error ("type of prefix is not an access"); + end if; + Name := New_Access_Element (Val); + N_Type := N_Type.Access_Dtype; + Next_Token; + else + Parse_Error ("'.all' expected"); + end if; + else + Parse_Error ("name expected"); + end if; + end; + when others => + Parse_Error ("invalid name"); + end case; + Parse_Lvalue (Name, N_Type); + end Parse_Name; + + -- Expect: '(' + -- Let: next token. + procedure Parse_Association (Constr : in out O_Assoc_List; Decl : Node_Acc) + is + Param : Node_Acc; + Expr : O_Enode; + Expr_Type : Node_Acc; + begin + Start_Association (Constr, Decl.Subprg_Node); + if Tok /= Tok_Left_Paren then + Parse_Error ("'(' expected for a subprogram call"); + end if; + Next_Token; + Param := Decl.Subprg_Params; + while Tok /= Tok_Right_Paren loop + if Param = null then + Parse_Error ("too many parameters"); + end if; + Parse_Expression (Param.Decl_Dtype, Expr, Expr_Type); + New_Association (Constr, Expr); + Param := Param.Param_Next; + exit when Tok /= Tok_Comma; + Next_Token; + end loop; + if Param /= null then + Parse_Error ("missing parameters"); + end if; + if Tok /= Tok_Right_Paren then + Parse_Error ("')' expected to finish a subprogram call, found " + & Token_Type'Image (Tok)); + end if; + Next_Token; + end Parse_Association; + + type Loop_Info; + type Loop_Info_Acc is access Loop_Info; + type Loop_Info is record + Num : Natural; + Blk : O_Snode; + Prev : Loop_Info_Acc; + end record; + procedure Free is new Ada.Unchecked_Deallocation + (Name => Loop_Info_Acc, Object => Loop_Info); + + Loop_Stack : Loop_Info_Acc := null; + + function Find_Loop (N : Natural) return Loop_Info_Acc + is + Res : Loop_Info_Acc; + begin + Res := Loop_Stack; + while Res /= null loop + if Res.Num = N then + return Res; + end if; + Res := Res.Prev; + end loop; + return null; + end Find_Loop; + + Current_Subprg : Node_Acc := null; + + procedure Parse_Statement; + + -- Expect : next token + -- Let: next token + procedure Parse_Statements is + begin + loop + exit when Tok = Tok_End; + exit when Tok = Tok_Else; + exit when Tok = Tok_When; + Parse_Statement; + end loop; + end Parse_Statements; + + -- Expect : next token + -- Let: next token + procedure Parse_Statement is + begin + if Flag_Renumber then + New_Debug_Line_Stmt (Lineno); + end if; + + case Tok is + when Tok_Comment => + Next_Token; + + when Tok_Declare => + Start_Declare_Stmt; + Parse_Compound_Statement; + Expect (Tok_Semicolon); + Next_Token; + Finish_Declare_Stmt; + + when Tok_Line_Number => + Next_Expect (Tok_Num); + if Flag_Renumber = False then + New_Debug_Line_Stmt (Natural (Token_Number)); + end if; + Next_Token; + + when Tok_If => + declare + If_Blk : O_If_Block; + Cond : O_Enode; + Cond_Type : Node_Acc; + begin + Next_Token; + Parse_Expression (null, Cond, Cond_Type); + Start_If_Stmt (If_Blk, Cond); + Expect (Tok_Then); + Next_Token; + Parse_Statements; + if Tok = Tok_Else then + Next_Token; + New_Else_Stmt (If_Blk); + Parse_Statements; + end if; + Finish_If_Stmt (If_Blk); + Expect (Tok_End); + Next_Expect (Tok_If); + Next_Expect (Tok_Semicolon); + Next_Token; + end; + + when Tok_Loop => + declare + Info : Loop_Info_Acc; + Num : Natural; + begin + Next_Expect (Tok_Num); + Num := Natural (Token_Number); + if Find_Loop (Num) /= null then + Parse_Error ("loop label already defined"); + end if; + Info := new Loop_Info; + Info.Num := Num; + Info.Prev := Loop_Stack; + Loop_Stack := Info; + Start_Loop_Stmt (Info.Blk); + Next_Expect (Tok_Colon); + Next_Token; + Parse_Statements; + Finish_Loop_Stmt (Info.Blk); + Next_Expect (Tok_Loop); + Next_Expect (Tok_Semicolon); + Loop_Stack := Info.Prev; + Free (Info); + Next_Token; + end; + + when Tok_Exit + | Tok_Next => + declare + Label : Loop_Info_Acc; + Etok : Token_Type; + begin + Etok := Tok; + Next_Expect (Tok_Loop); + Next_Expect (Tok_Num); + Label := Find_Loop (Natural (Token_Number)); + if Label = null then + Parse_Error ("no such loop"); + end if; + if Etok = Tok_Exit then + New_Exit_Stmt (Label.Blk); + else + New_Next_Stmt (Label.Blk); + end if; + Next_Expect (Tok_Semicolon); + Next_Token; + end; + + when Tok_Return => + declare + Res : O_Enode; + Res_Type : Node_Acc; + begin + Next_Token; + if Tok /= Tok_Semicolon then + Parse_Expression (Current_Subprg.Decl_Dtype, Res, Res_Type); + New_Return_Stmt (Res); + if Tok /= Tok_Semicolon then + Parse_Error ("';' expected at end of return statement"); + end if; + else + New_Return_Stmt; + end if; + Next_Token; + end; + + when Tok_Ident => + -- This is either a procedure call or an assignment. + declare + Inter : Node_Acc; + begin + Inter := Get_Decl (Token_Sym); + Next_Token; + if Tok = Tok_Left_Paren then + -- A procedure call. + declare + Constr : O_Assoc_List; + begin + Parse_Association (Constr, Inter); + New_Procedure_Call (Constr); + if Tok /= Tok_Semicolon then + Parse_Error ("';' expected after call"); + end if; + Next_Token; + return; + end; + else + -- An assignment. + declare + Name : O_Lnode; + Expr : O_Enode; + Expr_Type : Node_Acc; + N_Type : Node_Acc; + begin + Parse_Name (Inter, Name, N_Type); + if Tok /= Tok_Assign then + Parse_Error ("`:=' expected after a variable"); + end if; + Next_Token; + Parse_Expression (N_Type, Expr, Expr_Type); + New_Assign_Stmt (Name, Expr); + if Tok /= Tok_Semicolon then + Parse_Error ("';' expected at end of assignment"); + end if; + Next_Token; + return; + end; + end if; + end; + + when Tok_Case => + declare + Case_Blk : O_Case_Block; + L : O_Cnode; + Choice : O_Enode; + Choice_Type : Node_Acc; + begin + Next_Token; + Parse_Expression (null, Choice, Choice_Type); + Start_Case_Stmt (Case_Blk, Choice); + Expect (Tok_Is); + Next_Token; + loop + exit when Tok = Tok_End; + Expect (Tok_When); + Next_Token; + Start_Choice (Case_Blk); + loop + if Tok = Tok_Default then + New_Default_Choice (Case_Blk); + Next_Token; + else + L := Parse_Typed_Literal (Choice_Type); + if Tok = Tok_Elipsis then + Next_Token; + New_Range_Choice + (Case_Blk, L, Parse_Typed_Literal (Choice_Type)); + else + New_Expr_Choice (Case_Blk, L); + end if; + end if; + exit when Tok = Tok_Arrow; + Expect (Tok_Comma); + Next_Token; + end loop; + -- Skip '=>'. + Next_Token; + Finish_Choice (Case_Blk); + Parse_Statements; + end loop; + Finish_Case_Stmt (Case_Blk); + Expect (Tok_End); + Next_Expect (Tok_Case); + Next_Expect (Tok_Semicolon); + Next_Token; + end; + when others => + Parse_Error ("bad statement: " & Token_Type'Image (Tok)); + end case; + end Parse_Statement; + + procedure Parse_Compound_Statement is + begin + if Tok /= Tok_Declare then + Parse_Error ("'declare' expected to start a statements block"); + end if; + Next_Token; + + Push_Scope; + + -- Parse declarations. + while Tok /= Tok_Begin loop + Parse_Declaration; + end loop; + Next_Token; + + -- Parse statements. + Parse_Statements; + Expect (Tok_End); + Next_Token; + + Pop_Scope; + end Parse_Compound_Statement; + + -- Parse (P1 : T1; P2: T2; ...) + function Parse_Parameter_List return Node_Acc + is + First, Last : Node_Acc; + P : Node_Acc; + begin + Expect (Tok_Left_Paren); + Next_Token; + if Tok = Tok_Right_Paren then + Next_Token; + return null; + end if; + First := null; + Last := null; + loop + Expect (Tok_Ident); + P := new Node'(Kind => Decl_Param, + Decl_Dtype => null, + Decl_Storage => O_Storage_Public, + Param_Node => O_Dnode_Null, + Param_Name => Token_Sym, + Param_Next => null); + -- Link + if Last = null then + First := P; + else + Last.Param_Next := P; + end if; + Last := P; + Next_Expect (Tok_Colon); + Next_Token; + P.Decl_Dtype := Parse_Type; + exit when Tok = Tok_Right_Paren; + Expect (Tok_Semicolon); + Next_Token; + end loop; + Next_Token; + return First; + end Parse_Parameter_List; + + procedure Create_Interface_List (Constr : in out O_Inter_List; + First_Inter : Node_Acc) + is + Inter : Node_Acc; + begin + Inter := First_Inter; + while Inter /= null loop + New_Interface_Decl (Constr, Inter.Param_Node, Inter.Param_Name.Ident, + Inter.Decl_Dtype.Type_Onode); + Inter := Inter.Param_Next; + end loop; + end Create_Interface_List; + + procedure Check_Parameter_List (List : Node_Acc) + is + Param : Node_Acc; + begin + Next_Expect (Tok_Left_Paren); + Next_Token; + Param := List; + while Tok /= Tok_Right_Paren loop + if Param = null then + Parse_Error ("subprogram redefined with more parameters"); + end if; + Expect (Tok_Ident); + if Token_Sym /= Param.Param_Name then + Parse_Error ("subprogram redefined with different parameter name"); + end if; + Next_Expect (Tok_Colon); + Next_Token; + if Parse_Type /= Param.Decl_Dtype then + Parse_Error ("subprogram redefined with different parameter type"); + end if; + Param := Param.Param_Next; + exit when Tok = Tok_Right_Paren; + Expect (Tok_Semicolon); + Next_Token; + end loop; + Expect (Tok_Right_Paren); + Next_Token; + if Param /= null then + Parse_Error ("subprogram redefined with less parameters"); + end if; + end Check_Parameter_List; + + procedure Parse_Subprogram_Body (Subprg : Node_Acc) + is + Param : Node_Acc; + Prev_Subprg : Node_Acc; + begin + Prev_Subprg := Current_Subprg; + Current_Subprg := Subprg; + + Start_Subprogram_Body (Subprg.Subprg_Node); + Push_Scope; + + -- Put parameters in the current scope. + Param := Subprg.Subprg_Params; + while Param /= null loop + Add_Decl (Param.Param_Name, Param); + Param := Param.Param_Next; + end loop; + + Parse_Compound_Statement; + + Pop_Scope; + Finish_Subprogram_Body; + + Current_Subprg := Prev_Subprg; + end Parse_Subprogram_Body; + + procedure Parse_Function_Definition (Storage : O_Storage) + is + Constr : O_Inter_List; + Sym : Syment_Acc; + N : Node_Acc; + begin + Expect (Tok_Function); + Next_Expect (Tok_Ident); + Sym := Token_Sym; + if Sym.Name /= null then + N := Get_Decl (Sym); + Check_Parameter_List (N.Subprg_Params); + Expect (Tok_Return); + Next_Expect (Tok_Ident); + Next_Token; + else + N := new Node'(Kind => Node_Function, + Decl_Dtype => null, + Decl_Storage => Storage, + Subprg_Node => O_Dnode_Null, + Subprg_Name => Sym, + Subprg_Params => null); + Next_Token; + N.Subprg_Params := Parse_Parameter_List; + Expect (Tok_Return); + Next_Token; + N.Decl_Dtype := Parse_Type; + + Start_Function_Decl (Constr, N.Subprg_Name.Ident, Storage, + N.Decl_Dtype.Type_Onode); + Create_Interface_List (Constr, N.Subprg_Params); + Finish_Subprogram_Decl (Constr, N.Subprg_Node); + + Add_Decl (Sym, N); + end if; + + if Tok = Tok_Declare then + Parse_Subprogram_Body (N); + end if; + end Parse_Function_Definition; + + procedure Parse_Procedure_Definition (Storage : O_Storage) + is + Constr : O_Inter_List; + Sym : Syment_Acc; + N : Node_Acc; + begin + Expect (Tok_Procedure); + Next_Expect (Tok_Ident); + Sym := Token_Sym; + if Sym.Name /= null then + N := Get_Decl (Sym); + Check_Parameter_List (N.Subprg_Params); + else + N := new Node'(Kind => Node_Procedure, + Decl_Dtype => null, + Decl_Storage => Storage, + Subprg_Node => O_Dnode_Null, + Subprg_Name => Sym, + Subprg_Params => null); + Next_Token; + N.Subprg_Params := Parse_Parameter_List; + + Start_Procedure_Decl (Constr, N.Subprg_Name.Ident, Storage); + Create_Interface_List (Constr, N.Subprg_Params); + Finish_Subprogram_Decl (Constr, N.Subprg_Node); + + Add_Decl (Sym, N); + end if; + + if Tok = Tok_Declare then + Parse_Subprogram_Body (N); + end if; + end Parse_Procedure_Definition; + + function Parse_Address (Prefix : Node_Acc) return O_Enode + is + Pfx : Node_Acc; + N : O_Lnode; + N_Type : Node_Acc; + Res : O_Enode; + Attr : Syment_Acc; + T : O_Tnode; + begin + Attr := Token_Sym; + Next_Expect (Tok_Left_Paren); + Next_Expect (Tok_Ident); + Pfx := Get_Decl (Token_Sym); + T := Prefix.Decl_Dtype.Type_Onode; + if Attr = Id_Subprg_Addr then + Expect (Tok_Ident); + Pfx := Get_Decl (Token_Sym); + if Pfx.Kind not in Nodes_Subprogram then + Parse_Error ("subprogram identifier expected"); + end if; + Res := New_Lit (New_Subprogram_Address (Pfx.Subprg_Node, T)); + Next_Token; + else + Next_Token; + Parse_Name (Pfx, N, N_Type); + if Attr = Id_Address then + Res := New_Address (N, T); + elsif Attr = Id_Unchecked_Address then + Res := New_Unchecked_Address (N, T); + else + Parse_Error ("address attribute expected"); + end if; + end if; + Expect (Tok_Right_Paren); + Next_Token; + return Res; + end Parse_Address; + + function Parse_Constant_Address (Prefix : Node_Acc) return O_Cnode + is + Pfx : Node_Acc; + Res : O_Cnode; + Attr : Syment_Acc; + T : O_Tnode; + begin + Attr := Token_Sym; + Next_Expect (Tok_Left_Paren); + Next_Expect (Tok_Ident); + Pfx := Get_Decl (Token_Sym); + T := Prefix.Decl_Dtype.Type_Onode; + if Attr = Id_Subprg_Addr then + Expect (Tok_Ident); + Pfx := Get_Decl (Token_Sym); + if Pfx.Kind not in Nodes_Subprogram then + Parse_Error ("subprogram identifier expected"); + end if; + Res := New_Subprogram_Address (Pfx.Subprg_Node, T); + Next_Token; + else + Next_Token; + if Attr = Id_Address then + Res := New_Global_Address (Pfx.Obj_Node, T); + elsif Attr = Id_Unchecked_Address then + Res := New_Global_Unchecked_Address (Pfx.Obj_Node, T); + else + Parse_Error ("address attribute expected"); + end if; + end if; + Expect (Tok_Right_Paren); + return Res; + end Parse_Constant_Address; + + function Parse_Constant_Value (Atype : Node_Acc) return O_Cnode + is + Res : O_Cnode; + begin + case Atype.Kind is + when Type_Subarray => + declare + Constr : O_Array_Aggr_List; + El : Node_Acc; + begin + Expect (Tok_Left_Brace); + Next_Token; + Start_Array_Aggr (Constr, Atype.Type_Onode); + El := Atype.Subarray_Base.Array_Element; + for I in Natural loop + exit when Tok = Tok_Right_Brace; + if I /= 0 then + Expect (Tok_Comma); + Next_Token; + end if; + New_Array_Aggr_El (Constr, Parse_Constant_Value (El)); + end loop; + Finish_Array_Aggr (Constr, Res); + Next_Token; + return Res; + end; + when Type_Unsigned + | Type_Signed + | Type_Enum + | Type_Float + | Type_Boolean + | Type_Access => + --return Parse_Primary_Expression (Atype); + return Parse_Typed_Literal (Atype); + when Type_Record => + declare + Constr : O_Record_Aggr_List; + Field : Node_Acc; + begin + Expect (Tok_Left_Brace); + Next_Token; + Start_Record_Aggr (Constr, Atype.Type_Onode); + Field := Atype.Record_Union_Fields; + while Field /= null loop + if Tok = Tok_Dot then + Next_Expect (Tok_Ident); + if Token_Sym /= Field.Field_Ident then + Parse_Error ("bad field name"); + end if; + Next_Expect (Tok_Equal); + Next_Token; + end if; + New_Record_Aggr_El + (Constr, Parse_Constant_Value (Field.Field_Type)); + Field := Field.Field_Next; + if Field /= null then + Expect (Tok_Comma); + Next_Token; + end if; + end loop; + Finish_Record_Aggr (Constr, Res); + Expect (Tok_Right_Brace); + Next_Token; + return Res; + end; + when Type_Union => + declare + Field : Node_Acc; + begin + Expect (Tok_Left_Brace); + Next_Token; + Expect (Tok_Dot); + Next_Expect (Tok_Ident); + Field := Find_Field_By_Name (Atype); + Next_Expect (Tok_Equal); + Next_Token; + Res := New_Union_Aggr + (Atype.Type_Onode, Field.Field_Fnode, + Parse_Constant_Value (Field.Field_Type)); + Expect (Tok_Right_Brace); + Next_Token; + return Res; + end; + when others => + raise Program_Error; + end case; + end Parse_Constant_Value; + + procedure Parse_Constant_Declaration (Storage : O_Storage) + is + N : Node_Acc; + Sym : Syment_Acc; + --Val : O_Cnode; + begin + Expect (Tok_Constant); + Next_Expect (Tok_Ident); + Sym := Token_Sym; + N := new Node'(Kind => Node_Object, + Decl_Dtype => null, + Decl_Storage => Storage, + Obj_Name => Sym.Ident, + Obj_Node => O_Dnode_Null); + Next_Expect (Tok_Colon); + Next_Token; + N.Decl_Dtype := Parse_Type; + New_Const_Decl (N.Obj_Node, Sym.Ident, Storage, N.Decl_Dtype.Type_Onode); + Add_Decl (Sym, N); + +-- if Storage /= O_Storage_External then +-- Expect (Tok_Assign); +-- Next_Token; +-- Start_Const_Value (N.Obj_Node); +-- Val := Parse_Constant_Value (N.Decl_Dtype); +-- Finish_Const_Value (N.Obj_Node, Val); +-- end if; + end Parse_Constant_Declaration; + + procedure Parse_Constant_Value_Declaration + is + N : Node_Acc; + Val : O_Cnode; + begin + Next_Expect (Tok_Ident); + N := Get_Decl (Token_Sym); + if N.Kind /= Node_Object then + Parse_Error ("name of a constant expected"); + end if; + -- FIXME: should check storage, + -- should check the object is a constant, + -- should check the object has no value. + Next_Expect (Tok_Assign); + Next_Token; + Start_Const_Value (N.Obj_Node); + Val := Parse_Constant_Value (N.Decl_Dtype); + Finish_Const_Value (N.Obj_Node, Val); + end Parse_Constant_Value_Declaration; + + procedure Parse_Var_Declaration (Storage : O_Storage) + is + N : Node_Acc; + Sym : Syment_Acc; + begin + Expect (Tok_Var); + Next_Expect (Tok_Ident); + Sym := Token_Sym; + N := new Node'(Kind => Node_Object, + Decl_Dtype => null, + Decl_Storage => Storage, + Obj_Name => Sym.Ident, + Obj_Node => O_Dnode_Null); + Next_Expect (Tok_Colon); + Next_Token; + N.Decl_Dtype := Parse_Type; + New_Var_Decl (N.Obj_Node, Sym.Ident, Storage, N.Decl_Dtype.Type_Onode); + Add_Decl (Sym, N); + end Parse_Var_Declaration; + + procedure Parse_Stored_Decl (Storage : O_Storage) + is + begin + Next_Token; + if Tok = Tok_Function then + Parse_Function_Definition (Storage); + elsif Tok = Tok_Procedure then + Parse_Procedure_Definition (Storage); + elsif Tok = Tok_Constant then + Parse_Constant_Declaration (Storage); + elsif Tok = Tok_Var then + Parse_Var_Declaration (Storage); + else + Parse_Error ("function declaration expected"); + end if; + end Parse_Stored_Decl; + + procedure Parse_Declaration + is + Inter : Node_Acc; + S : Syment_Acc; + begin + if Flag_Renumber then + New_Debug_Line_Decl (Lineno); + end if; + + case Tok is + when Tok_Type => + Next_Token; + if Tok /= Tok_Ident then + Parse_Error ("identifier for type expected"); + end if; + S := Token_Sym; + Next_Expect (Tok_Is); + Next_Token; + if Is_Defined (S) then + Parse_Type_Completion (Get_Decl (S)); + else + Inter := new Node'(Kind => Decl_Type, + Decl_Storage => O_Storage_Public, + Decl_Dtype => Parse_Type); + Add_Decl (S, Inter); + New_Type_Decl (S.Ident, Inter.Decl_Dtype.Type_Onode); + end if; + when Tok_External => + Parse_Stored_Decl (O_Storage_External); + when Tok_Private => + Parse_Stored_Decl (O_Storage_Private); + when Tok_Public => + Parse_Stored_Decl (O_Storage_Public); + when Tok_Local => + Parse_Stored_Decl (O_Storage_Local); + when Tok_Constant => + Parse_Constant_Value_Declaration; + when Tok_Comment => + New_Debug_Comment_Decl (Token_Ident (1 .. Token_Idlen)); + Next_Token; + return; + when Tok_File_Name => + if Flag_Renumber = False then + New_Debug_Filename_Decl (Token_Ident (1 .. Token_Idlen)); + end if; + Next_Token; + return; + when others => + Parse_Error ("declaration expected"); + end case; + Expect (Tok_Semicolon); + Next_Token; + end Parse_Declaration; + +-- procedure Put (Str : String) +-- is +-- L : Integer; +-- begin +-- L := Write (Standout, Str'Address, Str'Length); +-- end Put; + + function Parse (Filename : String_Acc) return Boolean + is + begin + -- Initialize symbol table. + Add_Keyword ("type", Tok_Type); + Add_Keyword ("return", Tok_Return); + Add_Keyword ("if", Tok_If); + Add_Keyword ("then", Tok_Then); + Add_Keyword ("else", Tok_Else); + Add_Keyword ("elsif", Tok_Elsif); + Add_Keyword ("loop", Tok_Loop); + Add_Keyword ("exit", Tok_Exit); + Add_Keyword ("next", Tok_Next); + Add_Keyword ("signed", Tok_Signed); + Add_Keyword ("unsigned", Tok_Unsigned); + Add_Keyword ("float", Tok_Float); + Add_Keyword ("is", Tok_Is); + Add_Keyword ("of", Tok_Of); + Add_Keyword ("all", Tok_All); + Add_Keyword ("not", Tok_Not); + Add_Keyword ("abs", Tok_Abs); + Add_Keyword ("or", Tok_Or); + Add_Keyword ("and", Tok_And); + Add_Keyword ("xor", Tok_Xor); + Add_Keyword ("mod", Tok_Mod); + Add_Keyword ("rem", Tok_Rem); + Add_Keyword ("array", Tok_Array); + Add_Keyword ("access", Tok_Access); + Add_Keyword ("record", Tok_Record); + Add_Keyword ("union", Tok_Union); + Add_Keyword ("end", Tok_End); + Add_Keyword ("boolean", Tok_Boolean); + Add_Keyword ("enum", Tok_Enum); + Add_Keyword ("external", Tok_External); + Add_Keyword ("private", Tok_Private); + Add_Keyword ("public", Tok_Public); + Add_Keyword ("local", Tok_Local); + Add_Keyword ("procedure", Tok_Procedure); + Add_Keyword ("function", Tok_Function); + Add_Keyword ("constant", Tok_Constant); + Add_Keyword ("var", Tok_Var); + Add_Keyword ("subarray", Tok_Subarray); + Add_Keyword ("declare", Tok_Declare); + Add_Keyword ("begin", Tok_Begin); + Add_Keyword ("end", Tok_End); + Add_Keyword ("null", Tok_Null); + Add_Keyword ("case", Tok_Case); + Add_Keyword ("when", Tok_When); + Add_Keyword ("default", Tok_Default); + + Id_Address := New_Symbol ("address"); + Id_Unchecked_Address := New_Symbol ("unchecked_address"); + Id_Subprg_Addr := New_Symbol ("subprg_addr"); + Id_Conv := New_Symbol ("conv"); + Id_Sizeof := New_Symbol ("sizeof"); + Id_Alignof := New_Symbol ("alignof"); + Id_Alloca := New_Symbol ("alloca"); + Id_Offsetof := New_Symbol ("offsetof"); + + -- Initialize the scanner. + Buf (1) := NUL; + Pos := 1; + Lineno := 1; + if Filename = null then + Fd := Standin; + File_Name := new String'("*stdin*"); + else + declare + Name : String (1 .. Filename'Length + 1); + --("C:\cygwin\home\tgingold\src\ortho\x86\tests\olang\ex2.ol", + begin + Name (1 .. Filename'Length) := Filename.all; + Name (Name'Last) := NUL; + File_Name := Filename; + Fd := Open_Read (Name'Address, Text); + if Fd = Invalid_FD then + Puterr ("cannot open '" & Filename.all & '''); + Newline_Err; + return False; + end if; + end; + end if; + + New_Debug_Filename_Decl (File_Name.all); + + Push_Scope; + Next_Token; + while Tok /= Tok_Eof loop + Parse_Declaration; + end loop; + Pop_Scope; + + if Fd /= Standin then + Close (Fd); + end if; + return True; + exception + when E : others => + Puterr (Ada.Exceptions.Exception_Information (E)); + raise; + end Parse; +end Ortho_Front; diff --git a/src/ortho/ortho_front.ads b/src/ortho/ortho_front.ads new file mode 100644 index 000000000..1d20e15d7 --- /dev/null +++ b/src/ortho/ortho_front.ads @@ -0,0 +1,41 @@ +-- Ortho front-end specifications. +-- Copyright (C) 2002, 2003, 2004, 2005 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. + +package Ortho_Front is + type String_Acc is access String; + + -- Called before decode_option. + -- This procedure can only do internal initializations. It cannot call + -- ortho subprograms. + procedure Init; + + -- An ortho back-end decodes the command line. Unknown options may + -- be decoded by the user, with this function. + -- When an ortho back-end encounter an unknown option, it sets OPT with + -- this option and ARG with the next one, if any. + -- + -- DECODE_OPTION must return the number of argument used, ie: + -- 0 if OPT is unknown. + -- 1 if OPT is known but ARG is unused. + -- 2 if OPT is known and ARG used. + function Decode_Option (Opt : String_Acc; Arg : String_Acc) return Natural; + + -- Start to parse file FILENAME. + -- Return False in case of error. + function Parse (Filename : String_Acc) return Boolean; +end Ortho_Front; diff --git a/src/ortho/ortho_jit.ads b/src/ortho/ortho_jit.ads new file mode 100644 index 000000000..89c3663f3 --- /dev/null +++ b/src/ortho/ortho_jit.ads @@ -0,0 +1,43 @@ +-- Ortho JIT specifications. +-- Copyright (C) 2009 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 System; use System; +with Ortho_Nodes; use Ortho_Nodes; + +package Ortho_Jit is + -- Initialize the whole engine. + procedure Init; + + -- Set address of non-defined global variables or functions. + procedure Set_Address (Decl : O_Dnode; Addr : Address); + -- Get address of a global. + function Get_Address (Decl : O_Dnode) return Address; + + -- Do link. + procedure Link (Status : out Boolean); + + -- Release memory (but the generated code). + procedure Finish; + + function Decode_Option (Option : String) return Boolean; + procedure Disp_Help; + + -- Return the name of the code generator, to be displayed by --version. + function Get_Jit_Name return String; +end Ortho_Jit; + diff --git a/src/ortho/ortho_nodes.common.ads b/src/ortho/ortho_nodes.common.ads new file mode 100644 index 000000000..178187482 --- /dev/null +++ b/src/ortho/ortho_nodes.common.ads @@ -0,0 +1,453 @@ +-- Ortho specifications. +-- Copyright (C) 2002, 2003, 2004, 2005 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 Interfaces; use Interfaces; +with Ortho_Ident; +use Ortho_Ident; + +-- Interface to create nodes. +package ORTHO_NODES is + + type O_Enode is private; + type O_Cnode is private; + type O_Lnode is private; + type O_Tnode is private; + type O_Snode is private; + type O_Dnode is private; + type O_Fnode is private; + + O_Cnode_Null : constant O_Cnode; + O_Dnode_Null : constant O_Dnode; + O_Enode_Null : constant O_Enode; + O_Fnode_Null : constant O_Fnode; + O_Lnode_Null : constant O_Lnode; + O_Snode_Null : constant O_Snode; + O_Tnode_Null : constant O_Tnode; + + -- True if the code generated supports nested subprograms. + Has_Nested_Subprograms : constant Boolean; + + ------------------------ + -- Type definitions -- + ------------------------ + + type O_Element_List is limited private; + + -- Build a record type. + procedure Start_Record_Type (Elements : out O_Element_List); + -- Add a field in the record; not constrained array are prohibited, since + -- its size is unlimited. + procedure New_Record_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; Etype : O_Tnode); + -- Finish the record type. + procedure Finish_Record_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an uncomplete record type: + -- First call NEW_UNCOMPLETE_RECORD_TYPE, which returns a record type. + -- This type can be declared or used to define access types on it. + -- Then, complete (if necessary) the record type, by calling + -- START_UNCOMPLETE_RECORD_TYPE, NEW_RECORD_FIELD and FINISH_RECORD_TYPE. + procedure New_Uncomplete_Record_Type (Res : out O_Tnode); + procedure Start_Uncomplete_Record_Type (Res : O_Tnode; + Elements : out O_Element_List); + + -- Build an union type. + procedure Start_Union_Type (Elements : out O_Element_List); + procedure New_Union_Field + (Elements : in out O_Element_List; + El : out O_Fnode; + Ident : O_Ident; + Etype : O_Tnode); + procedure Finish_Union_Type + (Elements : in out O_Element_List; Res : out O_Tnode); + + -- Build an access type. + -- DTYPE may be O_tnode_null in order to build an incomplete access type. + -- It is completed with finish_access_type. + function New_Access_Type (Dtype : O_Tnode) return O_Tnode; + procedure Finish_Access_Type (Atype : O_Tnode; Dtype : O_Tnode); + + -- Build an array type. + -- The array is not constrained and unidimensional. + function New_Array_Type (El_Type : O_Tnode; Index_Type : O_Tnode) + return O_Tnode; + + -- Build a constrained array type. + function New_Constrained_Array_Type (Atype : O_Tnode; Length : O_Cnode) + return O_Tnode; + + -- Build a scalar type; size may be 8, 16, 32 or 64. + function New_Unsigned_Type (Size : Natural) return O_Tnode; + function New_Signed_Type (Size : Natural) return O_Tnode; + + -- Build a float type. + function New_Float_Type return O_Tnode; + + -- Build a boolean type. + procedure New_Boolean_Type (Res : out O_Tnode; + False_Id : O_Ident; + False_E : out O_Cnode; + True_Id : O_Ident; + True_E : out O_Cnode); + + -- Create an enumeration + type O_Enum_List is limited private; + + -- Elements are declared in order, the first is ordered from 0. + procedure Start_Enum_Type (List : out O_Enum_List; Size : Natural); + procedure New_Enum_Literal (List : in out O_Enum_List; + Ident : O_Ident; Res : out O_Cnode); + procedure Finish_Enum_Type (List : in out O_Enum_List; Res : out O_Tnode); + + ---------------- + -- Literals -- + ---------------- + + -- Create a literal from an integer. + function New_Signed_Literal (Ltype : O_Tnode; Value : Integer_64) + return O_Cnode; + function New_Unsigned_Literal (Ltype : O_Tnode; Value : Unsigned_64) + return O_Cnode; + + function New_Float_Literal (Ltype : O_Tnode; Value : IEEE_Float_64) + return O_Cnode; + + -- Create a null access literal. + function New_Null_Access (Ltype : O_Tnode) return O_Cnode; + + -- Build a record/array aggregate. + -- The aggregate is constant, and therefore can be only used to initialize + -- constant declaration. + -- ATYPE must be either a record type or an array subtype. + -- Elements must be added in the order, and must be literals or aggregates. + type O_Record_Aggr_List is limited private; + type O_Array_Aggr_List is limited private; + + procedure Start_Record_Aggr (List : out O_Record_Aggr_List; + Atype : O_Tnode); + procedure New_Record_Aggr_El (List : in out O_Record_Aggr_List; + Value : O_Cnode); + procedure Finish_Record_Aggr (List : in out O_Record_Aggr_List; + Res : out O_Cnode); + + procedure Start_Array_Aggr (List : out O_Array_Aggr_List; Atype : O_Tnode); + procedure New_Array_Aggr_El (List : in out O_Array_Aggr_List; + Value : O_Cnode); + procedure Finish_Array_Aggr (List : in out O_Array_Aggr_List; + Res : out O_Cnode); + + -- Build an union aggregate. + function New_Union_Aggr (Atype : O_Tnode; Field : O_Fnode; Value : O_Cnode) + return O_Cnode; + + -- Returns the size in bytes of ATYPE. The result is a literal of + -- unsigned type RTYPE + -- ATYPE cannot be an unconstrained array type. + function New_Sizeof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the alignment in bytes for ATYPE. The result is a literal of + -- unsgined type RTYPE. + function New_Alignof (Atype : O_Tnode; Rtype : O_Tnode) return O_Cnode; + + -- Returns the offset of FIELD in its record ATYPE. The result is a + -- literal of unsigned type or access type RTYPE. + function New_Offsetof (Atype : O_Tnode; Field : O_Fnode; Rtype : O_Tnode) + return O_Cnode; + + -- Get the address of a subprogram. + function New_Subprogram_Address (Subprg : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Global_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + -- Same as New_Address but without any restriction. + function New_Global_Unchecked_Address (Decl : O_Dnode; Atype : O_Tnode) + return O_Cnode; + + ------------------- + -- Expressions -- + ------------------- + + type ON_Op_Kind is + ( + -- Not an operation; invalid. + ON_Nil, + + -- Dyadic operations. + ON_Add_Ov, -- ON_Dyadic_Op_Kind + ON_Sub_Ov, -- ON_Dyadic_Op_Kind + ON_Mul_Ov, -- ON_Dyadic_Op_Kind + ON_Div_Ov, -- ON_Dyadic_Op_Kind + ON_Rem_Ov, -- ON_Dyadic_Op_Kind + ON_Mod_Ov, -- ON_Dyadic_Op_Kind + + -- Binary operations. + ON_And, -- ON_Dyadic_Op_Kind + ON_Or, -- ON_Dyadic_Op_Kind + ON_Xor, -- ON_Dyadic_Op_Kind + + -- Monadic operations. + ON_Not, -- ON_Monadic_Op_Kind + ON_Neg_Ov, -- ON_Monadic_Op_Kind + ON_Abs_Ov, -- ON_Monadic_Op_Kind + + -- Comparaisons + ON_Eq, -- ON_Compare_Op_Kind + ON_Neq, -- ON_Compare_Op_Kind + ON_Le, -- ON_Compare_Op_Kind + ON_Lt, -- ON_Compare_Op_Kind + ON_Ge, -- ON_Compare_Op_Kind + ON_Gt -- ON_Compare_Op_Kind + ); + + subtype ON_Dyadic_Op_Kind is ON_Op_Kind range ON_Add_Ov .. ON_Xor; + subtype ON_Monadic_Op_Kind is ON_Op_Kind range ON_Not .. ON_Abs_Ov; + subtype ON_Compare_Op_Kind is ON_Op_Kind range ON_Eq .. ON_Gt; + + type O_Storage is (O_Storage_External, + O_Storage_Public, + O_Storage_Private, + O_Storage_Local); + -- Specifies the storage kind of a declaration. + -- O_STORAGE_EXTERNAL: + -- The declaration do not either reserve memory nor generate code, and + -- is imported either from an other file or from a later place in the + -- current file. + -- O_STORAGE_PUBLIC, O_STORAGE_PRIVATE: + -- The declaration reserves memory or generates code. + -- With O_STORAGE_PUBLIC, the declaration is exported outside of the + -- file while with O_STORAGE_PRIVATE, the declaration is local to the + -- file. + + Type_Error : exception; + Syntax_Error : exception; + + -- Create a value from a literal. + function New_Lit (Lit : O_Cnode) return O_Enode; + + -- Create a dyadic operation. + -- Left and right nodes must have the same type. + -- Binary operation is allowed only on boolean types. + -- The result is of the type of the operands. + function New_Dyadic_Op (Kind : ON_Dyadic_Op_Kind; Left, Right : O_Enode) + return O_Enode; + + -- Create a monadic operation. + -- Result is of the type of operand. + function New_Monadic_Op (Kind : ON_Monadic_Op_Kind; Operand : O_Enode) + return O_Enode; + + -- Create a comparaison operator. + -- NTYPE is the type of the result and must be a boolean type. + function New_Compare_Op + (Kind : ON_Compare_Op_Kind; Left, Right : O_Enode; Ntype : O_Tnode) + return O_Enode; + + + type O_Inter_List is limited private; + type O_Assoc_List is limited private; + type O_If_Block is limited private; + type O_Case_Block is limited private; + + + -- 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; + + -- 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; + + -- Get an element of a record. + -- Type of REC must be a record type. + function New_Selected_Element (Rec : O_Lnode; El : O_Fnode) + return O_Lnode; + + -- Reference an access. + -- Type of ACC must be an access type. + function New_Access_Element (Acc : O_Enode) return O_Lnode; + + -- Do a conversion. + -- Allowed conversions are: + -- FIXME: to write. + function New_Convert_Ov (Val : O_Enode; Rtype : O_Tnode) return O_Enode; + + -- Get the address of LVALUE. + -- ATYPE must be a type access whose designated type is the type of LVALUE. + -- FIXME: what about arrays. + function New_Address (Lvalue : O_Lnode; Atype : O_Tnode) return O_Enode; + + -- Same as New_Address but without any restriction. + function New_Unchecked_Address (Lvalue : O_Lnode; Atype : O_Tnode) + return O_Enode; + + -- Get the value of an Lvalue. + function New_Value (Lvalue : O_Lnode) return O_Enode; + function New_Obj_Value (Obj : O_Dnode) return O_Enode; + + -- Get an lvalue from a declaration. + function New_Obj (Obj : O_Dnode) return O_Lnode; + + -- Return a pointer of type RTPE to SIZE bytes allocated on the stack. + function New_Alloca (Rtype : O_Tnode; Size : O_Enode) return O_Enode; + + -- Declare a type. + -- This simply gives a name to a type. + procedure New_Type_Decl (Ident : O_Ident; Atype : O_Tnode); + + --------------------- + -- Declarations. -- + --------------------- + + -- Filename of the next declaration. + procedure New_Debug_Filename_Decl (Filename : String); + + -- Line number of the next declaration. + procedure New_Debug_Line_Decl (Line : Natural); + + -- Add a comment in the declarative region. + procedure New_Debug_Comment_Decl (Comment : String); + + -- Declare a constant. + -- This simply gives a name to a constant value or aggregate. + -- A constant cannot be modified and its storage cannot be local. + -- ATYPE must be constrained. + procedure New_Const_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Set the value of a non-external constant. + procedure Start_Const_Value (Const : in out O_Dnode); + procedure Finish_Const_Value (Const : in out O_Dnode; Val : O_Cnode); + + -- Create a variable declaration. + -- A variable can be local only inside a function. + -- ATYPE must be constrained. + procedure New_Var_Decl + (Res : out O_Dnode; + Ident : O_Ident; + Storage : O_Storage; + Atype : O_Tnode); + + -- Start a subprogram declaration. + -- Note: nested subprograms are allowed, ie o_storage_local subprograms can + -- be declared inside a subprograms. It is not allowed to declare + -- o_storage_external subprograms inside a subprograms. + -- Return type and interfaces cannot be a composite type. + procedure Start_Function_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage; + Rtype : O_Tnode); + -- For a subprogram without return value. + procedure Start_Procedure_Decl + (Interfaces : out O_Inter_List; + Ident : O_Ident; + Storage : O_Storage); + + -- Add an interface declaration to INTERFACES. + procedure New_Interface_Decl + (Interfaces : in out O_Inter_List; + Res : out O_Dnode; + Ident : O_Ident; + Atype : O_Tnode); + -- Finish the function declaration, get the node and a statement list. + procedure Finish_Subprogram_Decl + (Interfaces : in out O_Inter_List; Res : out O_Dnode); + -- Start a subprogram body. + -- Note: the declaration may have an external storage, in this case it + -- becomes public. + procedure Start_Subprogram_Body (Func : O_Dnode); + -- Finish a subprogram body. + procedure Finish_Subprogram_Body; + + + ------------------- + -- Statements. -- + ------------------- + + -- Add a line number as a statement. + procedure New_Debug_Line_Stmt (Line : Natural); + + -- Add a comment as a statement. + procedure New_Debug_Comment_Stmt (Comment : String); + + -- Start a declarative region. + procedure Start_Declare_Stmt; + procedure Finish_Declare_Stmt; + + -- Create a function call or a procedure call. + procedure Start_Association (Assocs : out O_Assoc_List; Subprg : O_Dnode); + procedure New_Association (Assocs : in out O_Assoc_List; Val : O_Enode); + function New_Function_Call (Assocs : O_Assoc_List) return O_Enode; + procedure New_Procedure_Call (Assocs : in out O_Assoc_List); + + -- Assign VALUE to TARGET, type must be the same or compatible. + -- FIXME: what about slice assignment? + procedure New_Assign_Stmt (Target : O_Lnode; Value : O_Enode); + + -- Exit from the subprogram and return VALUE. + procedure New_Return_Stmt (Value : O_Enode); + -- Exit from the subprogram, which doesn't return value. + procedure New_Return_Stmt; + + -- Build an IF statement. + procedure Start_If_Stmt (Block : in out O_If_Block; Cond : O_Enode); + procedure New_Else_Stmt (Block : in out O_If_Block); + procedure Finish_If_Stmt (Block : in out O_If_Block); + + -- Create a infinite loop statement. + procedure Start_Loop_Stmt (Label : out O_Snode); + procedure Finish_Loop_Stmt (Label : in out O_Snode); + + -- Exit from a loop stmt or from a for stmt. + procedure New_Exit_Stmt (L : O_Snode); + -- Go to the start of a loop stmt or of a for stmt. + -- Loops/Fors between L and the current points are exited. + procedure New_Next_Stmt (L : O_Snode); + + -- Case statement. + -- VALUE is the selector and must be a discrete type. + procedure Start_Case_Stmt (Block : in out O_Case_Block; Value : O_Enode); + -- A choice branch is composed of expr, range or default choices. + -- A choice branch is enclosed between a Start_Choice and a Finish_Choice. + -- The statements are after the finish_choice. + procedure Start_Choice (Block : in out O_Case_Block); + procedure New_Expr_Choice (Block : in out O_Case_Block; Expr : O_Cnode); + procedure New_Range_Choice (Block : in out O_Case_Block; + Low, High : O_Cnode); + procedure New_Default_Choice (Block : in out O_Case_Block); + procedure Finish_Choice (Block : in out O_Case_Block); + procedure Finish_Case_Stmt (Block : in out O_Case_Block); + +private + --- PRIVATE PART is defined by ortho_nodes.ads in one of the subdirectory. +end ORTHO_NODES; |
