diff options
Diffstat (limited to 'src/synth/synth-expr.adb')
-rw-r--r-- | src/synth/synth-expr.adb | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/src/synth/synth-expr.adb b/src/synth/synth-expr.adb new file mode 100644 index 000000000..009af9cf7 --- /dev/null +++ b/src/synth/synth-expr.adb @@ -0,0 +1,726 @@ +-- Expressions synthesis. +-- Copyright (C) 2017 Tristan Gingold +-- +-- This file is part of GHDL. +-- +-- This program 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 of the License, or +-- (at your option) any later version. +-- +-- This program 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 this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +-- MA 02110-1301, USA. + +with Ada.Unchecked_Conversion; +with Ada.Unchecked_Deallocation; +with Std_Names; +with Ieee.Std_Logic_1164; +with Std_Package; +with Errorout; use Errorout; +with Execution; +with Grt.Types; use Grt.Types; + +with Synth.Errors; use Synth.Errors; +with Synth.Context; use Synth.Context; +with Synth.Types; use Synth.Types; + +with Netlists; use Netlists; +with Netlists.Gates; use Netlists.Gates; +with Netlists.Builders; use Netlists.Builders; + +package body Synth.Expr is + function Is_Const (Val : Value_Acc) return Boolean is + begin + return Val.Kind = Value_Lit; + end Is_Const; + + function Get_Width (Val : Value_Acc) return Uns32 is + begin + case Val.Kind is + when Value_Lit => + if Is_Bit_Type (Val.Lit_Type) then + return 1; + else + raise Internal_Error; + end if; + when Value_Wire + | Value_Net => + return Get_Width (Get_Net (Val)); + when others => + raise Internal_Error; -- TODO + end case; + end Get_Width; + + procedure To_Logic (Lit : Iir_Value_Literal_Acc; + Val : out Uns32; + Xz : out Uns32) is + begin + case Lit.Kind is + when Iir_Value_B1 => + Xz := 0; + Val := Ghdl_B1'Pos (Lit.B1); + when Iir_Value_E8 => + -- Std_logic. + case Lit.E8 is + when Ieee.Std_Logic_1164.Std_Logic_0_Pos + | Ieee.Std_Logic_1164.Std_Logic_L_Pos => + Val := 0; + Xz := 0; + when Ieee.Std_Logic_1164.Std_Logic_1_Pos + | Ieee.Std_Logic_1164.Std_Logic_H_Pos => + Val := 1; + Xz := 0; + when Ieee.Std_Logic_1164.Std_Logic_U_Pos + | Ieee.Std_Logic_1164.Std_Logic_X_Pos + | Ieee.Std_Logic_1164.Std_Logic_D_Pos => + Val := 0; + Xz := 1; + when Ieee.Std_Logic_1164.Std_Logic_Z_Pos + | Ieee.Std_Logic_1164.Std_Logic_W_Pos => + Val := 1; + Xz := 1; + when others => + -- Only 9 values. + raise Internal_Error; + end case; + when others => + raise Internal_Error; + end case; + end To_Logic; + + function Bit_Extract (Val : Value_Acc; Off : Uns32) return Value_Acc is + begin + case Val.Kind is + when Value_Lit => + declare + Lit : constant Iir_Value_Literal_Acc := Val.Lit; + begin + pragma Assert (Lit.Kind = Iir_Value_Array); + pragma Assert (Lit.Bounds.Nbr_Dims = 1); + pragma Assert (Lit.Bounds.D (1).Length >= Iir_Index32 (Off)); + return Create_Value_Lit + (Lit.Val_Array.V (Lit.Val_Array.Len - Iir_Index32 (Off)), + Get_Element_Subtype (Val.Lit_Type)); + end; + when Value_Net + | Value_Wire => + return Create_Value_Net + (Build_Extract_Bit (Build_Context, Get_Net (Val), Off), + No_Range); + when others => + raise Internal_Error; + end case; + end Bit_Extract; + + function Synth_Uresize (Val : Value_Acc; W : Width) return Net + is + N : constant Net := Get_Net (Val); + Wn : constant Width := Get_Width (N); + begin + if Wn > W then + return Build_Trunc (Build_Context, Id_Utrunc, N, W); + elsif Wn < W then + return Build_Extend (Build_Context, Id_Uextend, N, W); + else + return N; + end if; + end Synth_Uresize; + + procedure Fill_Array_Aggregate + (Syn_Inst : Synth_Instance_Acc; + Aggr : Iir; + Res : Value_Acc; + Dim : Iir_Index32; + Orig : Iir_Index32; + Stride : Iir_Index32) + is + Bound : constant Iir_Value_Literal_Acc := Res.Bounds.D (Dim); + Value : Iir; + Assoc : Iir; + Pos : Iir_Index32; + + procedure Set_Elem (Pos : Iir_Index32) + is + Val : Value_Acc; + begin + if Dim = Res.Bounds.Nbr_Dims then + Val := Synth_Expression_With_Type + (Syn_Inst, Value, Get_Element_Subtype (Get_Type (Aggr))); + Res.Arr.V (Orig + Stride * Pos) := Val; + else + Error_Msg_Synth (+Assoc, "multi-dim aggregate not handled"); + end if; + end Set_Elem; + begin + Assoc := Get_Association_Choices_Chain (Aggr); + Pos := 0; + while Is_Valid (Assoc) loop + Value := Get_Associated_Expr (Assoc); + loop + case Get_Kind (Assoc) is + when Iir_Kind_Choice_By_None => + if Pos >= Bound.Length then + Error_Msg_Synth (+Assoc, "element out of array bound"); + else + Set_Elem (Pos); + end if; + Pos := Pos + 1; + when others => + Error_Msg_Synth + (+Assoc, "unhandled association form"); + end case; + Assoc := Get_Chain (Assoc); + exit when Is_Null (Assoc); + exit when not Get_Same_Alternative_Flag (Assoc); + end loop; + end loop; + end Fill_Array_Aggregate; + + type Net_Array is array (Iir_Index32 range <>) of Net; + type Net_Array_Acc is access Net_Array; + procedure Free_Net_Array is new Ada.Unchecked_Deallocation + (Net_Array, Net_Array_Acc); + + -- Convert the one-dimension VAL to a net. + function Vectorize_Array (Val : Value_Acc) return Value_Acc + is + Arr : Net_Array_Acc; + Len : Iir_Index32; + Idx, New_Idx : Iir_Index32; + Res : Value_Acc; + begin + Len := Val.Arr.Len; + + -- Dynamically allocate ARR to handle large arrays. + Arr := new Net_Array (1 .. Len); + for I in Arr'Range loop + Arr (I) := Get_Net (Val.Arr.V (I)); + end loop; + + while Len > 1 loop + Idx := 1; + New_Idx := 0; + while Idx <= Len loop + -- Gather at most 4 nets. + New_Idx := New_Idx + 1; + + if Idx = Len then + Arr (New_Idx) := Arr (Idx); + Idx := Idx + 1; + elsif Idx + 1 = Len then + Arr (New_Idx) := Build_Concat2 + (Build_Context, Arr (Idx), Arr (Idx + 1)); + Idx := Idx + 2; + elsif Idx + 2 = Len then + Arr (New_Idx) := Build_Concat3 + (Build_Context, Arr (Idx), Arr (Idx + 1), Arr (Idx + 2)); + Idx := Idx + 3; + else + Arr (New_Idx) := Build_Concat4 + (Build_Context, + Arr (Idx), Arr (Idx + 1), Arr (Idx + 2), Arr (Idx + 3)); + Idx := Idx + 4; + end if; + end loop; + Len := New_Idx; + end loop; + + Res := Create_Value_Net (Arr (1), Bounds_To_Range (Val.Bounds.D (1))); + + Free_Net_Array (Arr); + + return Res; + end Vectorize_Array; + + function Synth_Aggregate (Syn_Inst : Synth_Instance_Acc; + Aggr : Iir; + Aggr_Type : Iir) return Value_Acc is + begin + case Get_Kind (Aggr_Type) is + when Iir_Kind_Array_Type_Definition + | Iir_Kind_Array_Subtype_Definition => + declare + Bnd : Iir_Value_Literal_Acc; + Res : Value_Acc; + begin + -- Create bounds. + Bnd := Execution.Create_Array_Bounds_From_Type + (Syn_Inst.Sim, Aggr_Type, False); + -- Allocate result + Res := Create_Array_Value (Bnd.Bounds); + Create_Array_Data (Res); + Fill_Array_Aggregate + (Syn_Inst, Aggr, Res, + 1, 1, Res.Arr.Len / Res.Bounds.D (1).Length); + if Is_Vector_Type (Aggr_Type) then + -- Vectorize + Res := Vectorize_Array (Res); + end if; + return Res; + end; + when Iir_Kind_Record_Type_Definition + | Iir_Kind_Record_Subtype_Definition => + raise Internal_Error; + when others => + Error_Kind ("synth_aggregate", Aggr_Type); + end case; + end Synth_Aggregate; + + function Synth_Bit_Eq_Const (Cst : Value_Acc; Expr : Value_Acc; Loc : Iir) + return Value_Acc + is + pragma Unreferenced (Loc); + Val : Uns32; + Xz : Uns32; + begin + To_Logic (Cst.Lit, Val, Xz); + if Xz /= 0 then + return Create_Value_Net + (Build_Const_UL32 (Build_Context, 0, 1, 1), No_Range); + elsif Val = 1 then + return Expr; + else + pragma Assert (Val = 0); + return Create_Value_Net + (Build_Monadic (Build_Context, Id_Not, Get_Net (Expr)), No_Range); + end if; + end Synth_Bit_Eq_Const; + + function Extract_Range (Val : Value_Acc) return Value_Range_Acc is + begin + case Val.Kind is + when Value_Net => + return Val.N_Range; + when Value_Wire => + return Val.W_Range; + when others => + raise Internal_Error; + end case; + end Extract_Range; + + -- Create the result range of an operator. According to the ieee standard, + -- the range is LEN-1 downto 0. + function Create_Res_Range (Prev : Value_Acc; N : Net) + return Value_Range_Acc + is + Res : Value_Range_Acc; + Wd : Width; + begin + case Prev.Kind is + when Value_Net + | Value_Wire => + Res := Extract_Range (Prev); + when Value_Lit => + Res := No_Range; + when others => + raise Internal_Error; + end case; + + if Res /= No_Range + and then Res.Dir = Iir_Downto + and then Res.Right = 0 + then + -- Normalized range + return Res; + end if; + + Wd := Get_Width (N); + return Create_Range_Value ((Iir_Downto, Wd, Int32 (Wd - 1), 0)); + end Create_Res_Range; + + function Synth_Dyadic_Operation (Def : Iir_Predefined_Functions; + Left : Value_Acc; + Right : Value_Acc; + Loc : Iir) return Value_Acc + is + function Synth_Bit_Dyadic (Id : Dyadic_Module_Id) return Value_Acc is + begin + return Create_Value_Net + (Build_Dyadic (Build_Context, Id, Get_Net (Left), Get_Net (Right)), + No_Range); + end Synth_Bit_Dyadic; + + -- function Synth_Vec_Dyadic (Id : Dyadic_Module_Id) return Value_Acc + -- is + -- L : constant Net := Get_Net (Left); + -- begin + -- return Create_Value_Net + -- (Build_Dyadic (Build_Context, Id, L, Get_Net (Right)), + -- Create_Res_Range (Left, L)); + -- end Synth_Vec_Dyadic; + begin + case Def is + when Iir_Predefined_Error => + return null; + when Iir_Predefined_Bit_And + | Iir_Predefined_Boolean_And + | Iir_Predefined_Ieee_1164_Scalar_And => + return Synth_Bit_Dyadic (Id_And); + when Iir_Predefined_Bit_Xor + | Iir_Predefined_Ieee_1164_Scalar_Xor => + return Synth_Bit_Dyadic (Id_Xor); + when Iir_Predefined_Bit_Or + | Iir_Predefined_Ieee_1164_Scalar_Or => + return Synth_Bit_Dyadic (Id_Or); + when Iir_Predefined_Enum_Equality => + if Get_Width (Left) = 1 then + if Is_Const (Left) then + return Synth_Bit_Eq_Const (Left, Right, Loc); + elsif Is_Const (Right) then + return Synth_Bit_Eq_Const (Right, Left, Loc); + end if; + end if; + -- TODO + Error_Msg_Synth (+Loc, "unsupported enum equality"); + raise Internal_Error; + when Iir_Predefined_Ieee_Numeric_Std_Add_Uns_Nat => + -- "+" (Unsigned, Natural) + declare + L : constant Net := Get_Net (Left); + begin + return Create_Value_Net + (Build_Dyadic (Build_Context, Id_Add, + L, + Synth_Uresize (Right, Get_Width (Left))), + Create_Res_Range (Left, L)); + end; + when Iir_Predefined_Ieee_Numeric_Std_Eq_Uns_Nat => + -- "=" (Unsigned, Natural) + return Create_Value_Net + (Build_Compare (Build_Context, Id_Eq, + Get_Net (Left), + Synth_Uresize (Right, Get_Width (Left))), + No_Range); + when others => + Error_Msg_Synth + (+Loc, + "unhandled dyadic: " & Iir_Predefined_Functions'Image (Def)); + raise Internal_Error; + end case; + end Synth_Dyadic_Operation; + + function Synth_Monadic_Operation (Def : Iir_Predefined_Functions; + Operand : Value_Acc; + Loc : Iir) return Value_Acc + is + function Synth_Bit_Monadic (Id : Monadic_Module_Id) return Value_Acc is + begin + return Create_Value_Net + (Build_Monadic (Build_Context, Id, Get_Net (Operand)), + No_Range); + end Synth_Bit_Monadic; + begin + case Def is + when Iir_Predefined_Error => + return null; + when Iir_Predefined_Ieee_1164_Scalar_Not => + return Synth_Bit_Monadic (Id_Not); + when others => + Error_Msg_Synth + (+Loc, + "unhandled monadic: " & Iir_Predefined_Functions'Image (Def)); + raise Internal_Error; + end case; + end Synth_Monadic_Operation; + + function Synth_Name (Syn_Inst : Synth_Instance_Acc; Name : Iir) + return Value_Acc is + begin + case Get_Kind (Name) is + when Iir_Kind_Simple_Name => + return Synth_Name (Syn_Inst, Get_Named_Entity (Name)); + when Iir_Kind_Interface_Signal_Declaration + | Iir_Kind_Variable_Declaration + | Iir_Kind_Signal_Declaration => + return Get_Value (Syn_Inst, Name); + when others => + Error_Kind ("synth_name", Name); + end case; + end Synth_Name; + + function In_Range (Rng : Value_Range_Acc; V : Int32) return Boolean is + begin + case Rng.Dir is + when Iir_To => + return V >= Rng.Left and then V <= Rng.Right; + when Iir_Downto => + return V <= Rng.Left and then V >= Rng.Right; + end case; + end In_Range; + + function Synth_Indexed_Name (Syn_Inst : Synth_Instance_Acc; Name : Iir) + return Value_Acc + is + Pfx : constant Value_Acc := + Synth_Expression (Syn_Inst, Get_Prefix (Name)); + Indexes : constant Iir_List := Get_Index_List (Name); + Idx_Val : constant Value_Acc := + Synth_Expression (Syn_Inst, Get_Nth_Element (Indexes, 0)); + Rng : Value_Range_Acc; + Idx : Int32; + begin + if Get_Nbr_Elements (Indexes) /= 1 then + Error_Msg_Synth (+Name, "multi-dim arrays not supported"); + return null; + end if; + + if Idx_Val.Kind /= Value_Lit + or else Idx_Val.Lit.Kind /= Iir_Value_I64 + then + Error_Msg_Synth (+Name, "non constant integer index not supported"); + return null; + end if; + + Rng := Extract_Range (Pfx); + Idx := Int32 (Idx_Val.Lit.I64); + if not In_Range (Rng, Idx) then + Error_Msg_Synth (+Name, "index not within bounds"); + return null; + end if; + + case Rng.Dir is + when Iir_To => + return Bit_Extract (Pfx, Uns32 (Rng.Right - Idx)); + when Iir_Downto => + return Bit_Extract (Pfx, Uns32 (Idx - Rng.Left)); + end case; + end Synth_Indexed_Name; + + -- Match: clk_signal_name'event + -- and return clk_signal_name. + function Extract_Event_Expr_Prefix (Expr : Iir) return Iir is + begin + if Get_Kind (Expr) = Iir_Kind_Event_Attribute then + return Get_Prefix (Expr); + else + return Null_Iir; + end if; + end Extract_Event_Expr_Prefix; + + function Is_Same_Node (Left, Right : Iir) return Boolean is + begin + if Get_Kind (Left) /= Get_Kind (Right) then + return False; + end if; + case Get_Kind (Left) is + when Iir_Kind_Simple_Name => + return Get_Named_Entity (Left) = Get_Named_Entity (Right); + when others => + Error_Kind ("is_same_node", Left); + end case; + end Is_Same_Node; + + -- Match: clk_signal_name = '1' | clk_signal_name = '0' + function Extract_Clock_Level + (Syn_Inst : Synth_Instance_Acc; Expr : Iir; Prefix : Iir) return Net + is + Clk : Net; + Imp : Iir; + Left, Right : Iir; + Lit : Iir; + Posedge : Boolean; + begin + Clk := Get_Net (Synth_Name (Syn_Inst, Prefix)); + if Get_Kind (Expr) /= Iir_Kind_Equality_Operator then + Error_Msg_Synth (+Expr, "ill-formed clock-level, '=' expected"); + return Build_Edge (Build_Context, True, Clk); + end if; + Imp := Get_Implementation (Expr); + if Get_Implicit_Definition (Imp) /= Iir_Predefined_Enum_Equality then + Error_Msg_Synth (+Expr, "ill-formed clock-level, '=' expected"); + return Build_Edge (Build_Context, True, Clk); + end if; + Left := Get_Left (Expr); + Right := Get_Right (Expr); + if Get_Kind (Right) /= Iir_Kind_Character_Literal then + Error_Msg_Synth + (+Expr, "ill-formed clock-level, '0' or '1' expected"); + return Build_Edge (Build_Context, True, Clk); + end if; + Lit := Get_Named_Entity (Right); + if Lit = Std_Package.Bit_0 + or else Lit = Ieee.Std_Logic_1164.Std_Ulogic_0 + then + Posedge := False; + elsif Lit = Std_Package.Bit_1 + or else Lit = Ieee.Std_Logic_1164.Std_Ulogic_1 + then + Posedge := True; + else + Error_Msg_Synth + (+Lit, "ill-formed clock-level, '0' or '1' expected"); + Posedge := True; + end if; + if not Is_Same_Node (Prefix, Left) then + Error_Msg_Synth + (+Left, "clock signal name doesn't match"); + end if; + return Build_Edge (Build_Context, Posedge, Clk); + end Extract_Clock_Level; + + function Synth_Clock_Edge (Syn_Inst : Synth_Instance_Acc; Expr : Iir) + return Value_Acc + is + pragma Assert (Get_Kind (Expr) = Iir_Kind_And_Operator); + Left : constant Iir := Get_Left (Expr); + Right : constant Iir := Get_Right (Expr); + Prefix : Iir; + begin + -- Try with left. + Prefix := Extract_Event_Expr_Prefix (Left); + if Is_Valid (Prefix) then + return Create_Value_Net + (Extract_Clock_Level (Syn_Inst, Right, Prefix), No_Range); + end if; + + -- Try with right. + Prefix := Extract_Event_Expr_Prefix (Right); + if Is_Valid (Prefix) then + return Create_Value_Net + (Extract_Clock_Level (Syn_Inst, Left, Prefix), No_Range); + end if; + + return null; + end Synth_Clock_Edge; + + function Synth_Type_Conversion (Syn_Inst : Synth_Instance_Acc; Conv : Iir) + return Value_Acc + is + Expr : constant Iir := Get_Expression (Conv); + Val : Value_Acc; + begin + Val := Synth_Expression (Syn_Inst, Expr); + if Is_Vector_Type (Get_Type (Conv)) then + return Val; + else + Error_Msg_Synth (+Conv, "unhandled type conversion"); + return Val; + end if; + end Synth_Type_Conversion; + + function Synth_Assoc_In (Syn_Inst : Synth_Instance_Acc; + Assoc : Iir) return Value_Acc is + begin + if Get_Kind (Assoc) = Iir_Kind_Association_Element_By_Expression then + return Synth_Expression (Syn_Inst, Get_Actual (Assoc)); + else + Error_Kind ("synth_assoc_in", Assoc); + end if; + end Synth_Assoc_In; + + procedure Error_Unknown_Operator (Imp : Iir; Loc : Iir) is + begin + if Get_Kind (Get_Parent (Imp)) = Iir_Kind_Package_Declaration + and then (Get_Identifier + (Get_Library + (Get_Design_File (Get_Design_Unit (Get_Parent (Imp))))) + = Std_Names.Name_Ieee) + then + Error_Msg_Synth (+Loc, "unhandled predefined IEEE operator %i", +Imp); + Error_Msg_Synth (+Imp, " declared here"); + else + Error_Msg_Synth (+Loc, "user defined operator %i not handled", +Imp); + end if; + end Error_Unknown_Operator; + + function Synth_Expression_With_Type + (Syn_Inst : Synth_Instance_Acc; Expr : Iir; Expr_Type : Iir) + return Value_Acc is + begin + case Get_Kind (Expr) is + when Iir_Kinds_Dyadic_Operator => + declare + Imp : constant Iir := Get_Implementation (Expr); + Def : constant Iir_Predefined_Functions := + Get_Implicit_Definition (Imp); + Left : Value_Acc; + Right : Value_Acc; + begin + -- Match clock-edge + if Def = Iir_Predefined_Boolean_And then + Left := Synth_Clock_Edge (Syn_Inst, Expr); + if Left /= null then + return Left; + end if; + end if; + + Left := Synth_Expression (Syn_Inst, Get_Left (Expr)); + Right := Synth_Expression (Syn_Inst, Get_Right (Expr)); + if Def in Iir_Predefined_Implicit + or else Def in Iir_Predefined_IEEE_Explicit + then + return Synth_Dyadic_Operation (Def, Left, Right, Expr); + else + Error_Unknown_Operator (Imp, Expr); + return Left; + end if; + end; + when Iir_Kinds_Monadic_Operator => + declare + Imp : constant Iir := Get_Implementation (Expr); + Def : constant Iir_Predefined_Functions := + Get_Implicit_Definition (Imp); + Operand : Value_Acc; + begin + Operand := Synth_Expression (Syn_Inst, Get_Operand (Expr)); + if Def in Iir_Predefined_Implicit + or else Def in Iir_Predefined_IEEE_Explicit + then + return Synth_Monadic_Operation (Def, Operand, Expr); + else + Error_Unknown_Operator (Imp, Expr); + return Operand; + end if; + end; + when Iir_Kind_Simple_Name => + return Synth_Name (Syn_Inst, Expr); + when Iir_Kind_Indexed_Name => + return Synth_Indexed_Name (Syn_Inst, Expr); + when Iir_Kind_Character_Literal + | Iir_Kind_Integer_Literal + | Iir_Kind_String_Literal8 => + return Create_Value_Lit + (Execution.Execute_Expression (Syn_Inst.Sim, Expr), + Get_Base_Type (Get_Type (Expr))); + when Iir_Kind_Type_Conversion => + return Synth_Type_Conversion (Syn_Inst, Expr); + when Iir_Kind_Qualified_Expression => + return Synth_Expression_With_Type + (Syn_Inst, Get_Expression (Expr), Get_Type (Expr)); + when Iir_Kind_Function_Call => + declare + Imp : constant Iir := Get_Implementation (Expr); + Clk : Net; + begin + if Imp = Ieee.Std_Logic_1164.Rising_Edge then + Clk := Get_Net + (Synth_Assoc_In + (Syn_Inst, Get_Parameter_Association_Chain (Expr))); + return Create_Value_Net + (Build_Edge (Build_Context, True, Clk), No_Range); + end if; + Error_Msg_Synth + (+Expr, "user function call to %i is not handled", +Imp); + end; + when Iir_Kind_Aggregate => + return Synth_Aggregate (Syn_Inst, Expr, Expr_Type); + when others => + Error_Kind ("synth_expression", Expr); + end case; + return null; + end Synth_Expression_With_Type; + + function Synth_Expression (Syn_Inst : Synth_Instance_Acc; Expr : Iir) + return Value_Acc is + begin + return Synth_Expression_With_Type (Syn_Inst, Expr, Get_Type (Expr)); + end Synth_Expression; + +end Synth.Expr; |