aboutsummaryrefslogtreecommitdiffstats
path: root/src/evaluation.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/evaluation.adb')
-rw-r--r--src/evaluation.adb3047
1 files changed, 3047 insertions, 0 deletions
diff --git a/src/evaluation.adb b/src/evaluation.adb
new file mode 100644
index 000000000..8279e140c
--- /dev/null
+++ b/src/evaluation.adb
@@ -0,0 +1,3047 @@
+-- Evaluation of static expressions.
+-- 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 GHDL; 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 Errorout; use Errorout;
+with Name_Table; use Name_Table;
+with Str_Table;
+with Iirs_Utils; use Iirs_Utils;
+with Std_Package; use Std_Package;
+with Flags; use Flags;
+with Std_Names;
+with Ada.Characters.Handling;
+
+package body Evaluation is
+ function Get_Physical_Value (Expr : Iir) return Iir_Int64
+ is
+ pragma Unsuppress (Overflow_Check);
+ Kind : constant Iir_Kind := Get_Kind (Expr);
+ Unit : Iir;
+ begin
+ case Kind is
+ when Iir_Kind_Physical_Int_Literal
+ | Iir_Kind_Physical_Fp_Literal =>
+ -- Extract Unit.
+ Unit := Get_Physical_Unit_Value
+ (Get_Named_Entity (Get_Unit_Name (Expr)));
+ case Kind is
+ when Iir_Kind_Physical_Int_Literal =>
+ return Get_Value (Expr) * Get_Value (Unit);
+ when Iir_Kind_Physical_Fp_Literal =>
+ return Iir_Int64
+ (Get_Fp_Value (Expr) * Iir_Fp64 (Get_Value (Unit)));
+ when others =>
+ raise Program_Error;
+ end case;
+ when Iir_Kind_Unit_Declaration =>
+ return Get_Value (Get_Physical_Unit_Value (Expr));
+ when others =>
+ Error_Kind ("get_physical_value", Expr);
+ end case;
+ exception
+ when Constraint_Error =>
+ Error_Msg_Sem ("arithmetic overflow in physical expression", Expr);
+ return Get_Value (Expr);
+ end Get_Physical_Value;
+
+ function Build_Integer (Val : Iir_Int64; Origin : Iir)
+ return Iir_Integer_Literal
+ is
+ Res : Iir_Integer_Literal;
+ begin
+ Res := Create_Iir (Iir_Kind_Integer_Literal);
+ Location_Copy (Res, Origin);
+ Set_Value (Res, Val);
+ Set_Type (Res, Get_Type (Origin));
+ Set_Literal_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Build_Integer;
+
+ function Build_Floating (Val : Iir_Fp64; Origin : Iir)
+ return Iir_Floating_Point_Literal
+ is
+ Res : Iir_Floating_Point_Literal;
+ begin
+ Res := Create_Iir (Iir_Kind_Floating_Point_Literal);
+ Location_Copy (Res, Origin);
+ Set_Fp_Value (Res, Val);
+ Set_Type (Res, Get_Type (Origin));
+ Set_Literal_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Build_Floating;
+
+ function Build_Enumeration_Constant (Val : Iir_Index32; Origin : Iir)
+ return Iir_Enumeration_Literal
+ is
+ Enum_Type : constant Iir := Get_Base_Type (Get_Type (Origin));
+ Enum_List : constant Iir_List :=
+ Get_Enumeration_Literal_List (Enum_Type);
+ Lit : constant Iir_Enumeration_Literal :=
+ Get_Nth_Element (Enum_List, Integer (Val));
+ Res : Iir_Enumeration_Literal;
+ begin
+ Res := Copy_Enumeration_Literal (Lit);
+ Location_Copy (Res, Origin);
+ Set_Literal_Origin (Res, Origin);
+ return Res;
+ end Build_Enumeration_Constant;
+
+ function Build_Physical (Val : Iir_Int64; Origin : Iir)
+ return Iir_Physical_Int_Literal
+ is
+ Res : Iir_Physical_Int_Literal;
+ Unit_Name : Iir;
+ begin
+ Res := Create_Iir (Iir_Kind_Physical_Int_Literal);
+ Location_Copy (Res, Origin);
+ Unit_Name := Get_Primary_Unit_Name (Get_Base_Type (Get_Type (Origin)));
+ Set_Unit_Name (Res, Unit_Name);
+ Set_Value (Res, Val);
+ Set_Type (Res, Get_Type (Origin));
+ Set_Literal_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Build_Physical;
+
+ function Build_Discrete (Val : Iir_Int64; Origin : Iir) return Iir is
+ begin
+ case Get_Kind (Get_Type (Origin)) is
+ when Iir_Kind_Enumeration_Type_Definition
+ | Iir_Kind_Enumeration_Subtype_Definition =>
+ return Build_Enumeration_Constant (Iir_Index32 (Val), Origin);
+ when Iir_Kind_Integer_Type_Definition
+ | Iir_Kind_Integer_Subtype_Definition =>
+ return Build_Integer (Val, Origin);
+ when others =>
+ Error_Kind ("build_discrete", Get_Type (Origin));
+ end case;
+ end Build_Discrete;
+
+ function Build_String (Val : String_Id; Len : Nat32; Origin : Iir)
+ return Iir_String_Literal
+ is
+ Res : Iir_String_Literal;
+ begin
+ Res := Create_Iir (Iir_Kind_String_Literal);
+ Location_Copy (Res, Origin);
+ Set_String_Id (Res, Val);
+ Set_String_Length (Res, Len);
+ Set_Type (Res, Get_Type (Origin));
+ Set_Literal_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Build_String;
+
+ function Build_Simple_Aggregate
+ (El_List : Iir_List; Origin : Iir; Stype : Iir)
+ return Iir_Simple_Aggregate
+ is
+ Res : Iir_Simple_Aggregate;
+ begin
+ Res := Create_Iir (Iir_Kind_Simple_Aggregate);
+ Location_Copy (Res, Origin);
+ Set_Simple_Aggregate_List (Res, El_List);
+ Set_Type (Res, Stype);
+ Set_Literal_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ Set_Literal_Subtype (Res, Stype);
+ return Res;
+ end Build_Simple_Aggregate;
+
+ function Build_Overflow (Origin : Iir) return Iir
+ is
+ Res : Iir;
+ begin
+ Res := Create_Iir (Iir_Kind_Overflow_Literal);
+ Location_Copy (Res, Origin);
+ Set_Type (Res, Get_Type (Origin));
+ Set_Literal_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Build_Overflow;
+
+ function Build_Constant (Val : Iir; Origin : Iir) return Iir
+ is
+ Res : Iir;
+ begin
+ -- Note: this must work for any literals, because it may be used to
+ -- replace a locally static constant by its initial value.
+ case Get_Kind (Val) is
+ when Iir_Kind_Integer_Literal =>
+ Res := Create_Iir (Iir_Kind_Integer_Literal);
+ Set_Value (Res, Get_Value (Val));
+
+ when Iir_Kind_Floating_Point_Literal =>
+ Res := Create_Iir (Iir_Kind_Floating_Point_Literal);
+ Set_Fp_Value (Res, Get_Fp_Value (Val));
+
+ when Iir_Kind_Enumeration_Literal =>
+ return Build_Enumeration_Constant
+ (Iir_Index32 (Get_Enum_Pos (Val)), Origin);
+
+ when Iir_Kind_Physical_Int_Literal =>
+ Res := Create_Iir (Iir_Kind_Physical_Int_Literal);
+ Set_Unit_Name (Res, Get_Primary_Unit_Name
+ (Get_Base_Type (Get_Type (Origin))));
+ Set_Value (Res, Get_Physical_Value (Val));
+
+ when Iir_Kind_Unit_Declaration =>
+ Res := Create_Iir (Iir_Kind_Physical_Int_Literal);
+ Set_Value (Res, Get_Physical_Value (Val));
+ Set_Unit_Name (Res, Get_Primary_Unit_Name (Get_Type (Val)));
+
+ when Iir_Kind_String_Literal =>
+ Res := Create_Iir (Iir_Kind_String_Literal);
+ Set_String_Id (Res, Get_String_Id (Val));
+ Set_String_Length (Res, Get_String_Length (Val));
+
+ when Iir_Kind_Bit_String_Literal =>
+ Res := Create_Iir (Iir_Kind_Bit_String_Literal);
+ Set_String_Id (Res, Get_String_Id (Val));
+ Set_String_Length (Res, Get_String_Length (Val));
+ Set_Bit_String_Base (Res, Get_Bit_String_Base (Val));
+ Set_Bit_String_0 (Res, Get_Bit_String_0 (Val));
+ Set_Bit_String_1 (Res, Get_Bit_String_1 (Val));
+
+ when Iir_Kind_Simple_Aggregate =>
+ Res := Create_Iir (Iir_Kind_Simple_Aggregate);
+ Set_Simple_Aggregate_List (Res, Get_Simple_Aggregate_List (Val));
+ Set_Literal_Subtype (Res, Get_Type (Origin));
+
+ when Iir_Kind_Overflow_Literal =>
+ Res := Create_Iir (Iir_Kind_Overflow_Literal);
+
+ when others =>
+ Error_Kind ("build_constant", Val);
+ end case;
+ Location_Copy (Res, Origin);
+ Set_Type (Res, Get_Type (Origin));
+ Set_Literal_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Build_Constant;
+
+ function Build_Boolean (Cond : Boolean) return Iir is
+ begin
+ if Cond then
+ return Boolean_True;
+ else
+ return Boolean_False;
+ end if;
+ end Build_Boolean;
+
+ function Build_Enumeration (Val : Iir_Index32; Origin : Iir)
+ return Iir_Enumeration_Literal
+ is
+ Enum_Type : constant Iir := Get_Base_Type (Get_Type (Origin));
+ Enum_List : constant Iir_List :=
+ Get_Enumeration_Literal_List (Enum_Type);
+ begin
+ return Get_Nth_Element (Enum_List, Integer (Val));
+ end Build_Enumeration;
+
+ function Build_Enumeration (Val : Boolean; Origin : Iir)
+ return Iir_Enumeration_Literal
+ is
+ Enum_Type : constant Iir := Get_Base_Type (Get_Type (Origin));
+ Enum_List : constant Iir_List :=
+ Get_Enumeration_Literal_List (Enum_Type);
+ begin
+ return Get_Nth_Element (Enum_List, Boolean'Pos (Val));
+ end Build_Enumeration;
+
+ function Build_Constant_Range (Range_Expr : Iir; Origin : Iir) return Iir
+ is
+ Res : Iir;
+ begin
+ Res := Create_Iir (Iir_Kind_Range_Expression);
+ Location_Copy (Res, Origin);
+ Set_Type (Res, Get_Type (Range_Expr));
+ Set_Left_Limit (Res, Get_Left_Limit (Range_Expr));
+ Set_Right_Limit (Res, Get_Right_Limit (Range_Expr));
+ Set_Direction (Res, Get_Direction (Range_Expr));
+ Set_Range_Origin (Res, Origin);
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Build_Constant_Range;
+
+ function Build_Extreme_Value (Is_Pos : Boolean; Origin : Iir) return Iir
+ is
+ Orig_Type : constant Iir := Get_Base_Type (Get_Type (Origin));
+ begin
+ case Get_Kind (Orig_Type) is
+ when Iir_Kind_Integer_Type_Definition =>
+ if Is_Pos then
+ return Build_Integer (Iir_Int64'Last, Origin);
+ else
+ return Build_Integer (Iir_Int64'First, Origin);
+ end if;
+ when others =>
+ Error_Kind ("build_extreme_value", Orig_Type);
+ end case;
+ end Build_Extreme_Value;
+
+ -- A_RANGE is a range expression, whose type, location, expr_staticness,
+ -- left_limit and direction are set.
+ -- Type of A_RANGE must have a range_constraint.
+ -- Set the right limit of A_RANGE from LEN.
+ procedure Set_Right_Limit_By_Length (A_Range : Iir; Len : Iir_Int64)
+ is
+ Left, Right : Iir;
+ Pos : Iir_Int64;
+ A_Type : Iir;
+ begin
+ if Get_Expr_Staticness (A_Range) /= Locally then
+ raise Internal_Error;
+ end if;
+ A_Type := Get_Type (A_Range);
+
+ Left := Get_Left_Limit (A_Range);
+
+ Pos := Eval_Pos (Left);
+ case Get_Direction (A_Range) is
+ when Iir_To =>
+ Pos := Pos + Len -1;
+ when Iir_Downto =>
+ Pos := Pos - Len + 1;
+ end case;
+ if Len > 0
+ and then not Eval_Int_In_Range (Pos, Get_Range_Constraint (A_Type))
+ then
+ Error_Msg_Sem ("range length is beyond subtype length", A_Range);
+ Right := Left;
+ else
+ -- FIXME: what about nul range?
+ Right := Build_Discrete (Pos, A_Range);
+ Set_Literal_Origin (Right, Null_Iir);
+ end if;
+ Set_Right_Limit (A_Range, Right);
+ end Set_Right_Limit_By_Length;
+
+ -- Create a range of type A_TYPE whose length is LEN.
+ -- Note: only two nodes are created:
+ -- * the range_expression (node returned)
+ -- * the right bound
+ -- The left bound *IS NOT* created, but points to the left bound of A_TYPE.
+ function Create_Range_By_Length
+ (A_Type : Iir; Len : Iir_Int64; Loc : Location_Type)
+ return Iir
+ is
+ Index_Constraint : Iir;
+ Constraint : Iir;
+ begin
+ -- The left limit must be locally static in order to compute the right
+ -- limit.
+ pragma Assert (Get_Type_Staticness (A_Type) = Locally);
+
+ Index_Constraint := Get_Range_Constraint (A_Type);
+ Constraint := Create_Iir (Iir_Kind_Range_Expression);
+ Set_Location (Constraint, Loc);
+ Set_Expr_Staticness (Constraint, Locally);
+ Set_Type (Constraint, A_Type);
+ Set_Left_Limit (Constraint, Get_Left_Limit (Index_Constraint));
+ Set_Direction (Constraint, Get_Direction (Index_Constraint));
+ Set_Right_Limit_By_Length (Constraint, Len);
+ return Constraint;
+ end Create_Range_By_Length;
+
+ function Create_Range_Subtype_From_Type (A_Type : Iir; Loc : Location_Type)
+ return Iir
+ is
+ Res : Iir;
+ begin
+ pragma Assert (Get_Type_Staticness (A_Type) = Locally);
+
+ case Get_Kind (A_Type) is
+ when Iir_Kind_Enumeration_Type_Definition =>
+ Res := Create_Iir (Iir_Kind_Enumeration_Subtype_Definition);
+ when Iir_Kind_Integer_Subtype_Definition
+ | Iir_Kind_Enumeration_Subtype_Definition =>
+ Res := Create_Iir (Get_Kind (A_Type));
+ when others =>
+ Error_Kind ("create_range_subtype_by_length", A_Type);
+ end case;
+ Set_Location (Res, Loc);
+ Set_Base_Type (Res, Get_Base_Type (A_Type));
+ Set_Type_Staticness (Res, Locally);
+
+ return Res;
+ end Create_Range_Subtype_From_Type;
+
+ -- Create a subtype of A_TYPE whose length is LEN.
+ -- This is used to create subtypes for strings or aggregates.
+ function Create_Range_Subtype_By_Length
+ (A_Type : Iir; Len : Iir_Int64; Loc : Location_Type)
+ return Iir
+ is
+ Res : Iir;
+ begin
+ Res := Create_Range_Subtype_From_Type (A_Type, Loc);
+
+ Set_Range_Constraint (Res, Create_Range_By_Length (A_Type, Len, Loc));
+ return Res;
+ end Create_Range_Subtype_By_Length;
+
+ function Create_Unidim_Array_From_Index
+ (Base_Type : Iir; Index_Type : Iir; Loc : Iir)
+ return Iir_Array_Subtype_Definition
+ is
+ Res : Iir_Array_Subtype_Definition;
+ begin
+ Res := Create_Array_Subtype (Base_Type, Get_Location (Loc));
+ Append_Element (Get_Index_Subtype_List (Res), Index_Type);
+ Set_Type_Staticness (Res, Min (Get_Type_Staticness (Res),
+ Get_Type_Staticness (Index_Type)));
+ Set_Constraint_State (Res, Fully_Constrained);
+ Set_Index_Constraint_Flag (Res, True);
+ return Res;
+ end Create_Unidim_Array_From_Index;
+
+ function Create_Unidim_Array_By_Length
+ (Base_Type : Iir; Len : Iir_Int64; Loc : Iir)
+ return Iir_Array_Subtype_Definition
+ is
+ Index_Type : constant Iir := Get_Index_Type (Base_Type, 0);
+ N_Index_Type : Iir;
+ begin
+ N_Index_Type := Create_Range_Subtype_By_Length
+ (Index_Type, Len, Get_Location (Loc));
+ return Create_Unidim_Array_From_Index (Base_Type, N_Index_Type, Loc);
+ end Create_Unidim_Array_By_Length;
+
+ procedure Free_Eval_Static_Expr (Res : Iir; Orig : Iir) is
+ begin
+ if Res /= Orig and then Get_Literal_Origin (Res) = Orig then
+ Free_Iir (Res);
+ end if;
+ end Free_Eval_Static_Expr;
+
+ -- Free the result RES of Eval_String_Literal called with ORIG, if created.
+ procedure Free_Eval_String_Literal (Res : Iir; Orig : Iir)
+ is
+ L : Iir_List;
+ begin
+ if Res /= Orig then
+ L := Get_Simple_Aggregate_List (Res);
+ Destroy_Iir_List (L);
+ Free_Iir (Res);
+ end if;
+ end Free_Eval_String_Literal;
+
+ function Eval_String_Literal (Str : Iir) return Iir
+ is
+ Ptr : String_Fat_Acc;
+ Len : Nat32;
+ begin
+ case Get_Kind (Str) is
+ when Iir_Kind_String_Literal =>
+ declare
+ Element_Type : Iir;
+ Literal_List : Iir_List;
+ Lit : Iir;
+
+ List : Iir_List;
+ begin
+ Element_Type := Get_Base_Type
+ (Get_Element_Subtype (Get_Base_Type (Get_Type (Str))));
+ Literal_List := Get_Enumeration_Literal_List (Element_Type);
+ List := Create_Iir_List;
+
+ Ptr := Get_String_Fat_Acc (Str);
+ Len := Get_String_Length (Str);
+
+ for I in 1 .. Len loop
+ Lit := Find_Name_In_List
+ (Literal_List,
+ Name_Table.Get_Identifier (Ptr (I)));
+ Append_Element (List, Lit);
+ end loop;
+ return Build_Simple_Aggregate (List, Str, Get_Type (Str));
+ end;
+
+ when Iir_Kind_Bit_String_Literal =>
+ declare
+ Str_Type : constant Iir := Get_Type (Str);
+ List : Iir_List;
+ Lit_0 : constant Iir := Get_Bit_String_0 (Str);
+ Lit_1 : constant Iir := Get_Bit_String_1 (Str);
+ begin
+ List := Create_Iir_List;
+
+ Ptr := Get_String_Fat_Acc (Str);
+ Len := Get_String_Length (Str);
+
+ for I in 1 .. Len loop
+ case Ptr (I) is
+ when '0' =>
+ Append_Element (List, Lit_0);
+ when '1' =>
+ Append_Element (List, Lit_1);
+ when others =>
+ raise Internal_Error;
+ end case;
+ end loop;
+ return Build_Simple_Aggregate (List, Str, Str_Type);
+ end;
+
+ when Iir_Kind_Simple_Aggregate =>
+ return Str;
+
+ when others =>
+ Error_Kind ("eval_string_literal", Str);
+ end case;
+ end Eval_String_Literal;
+
+ function Eval_Monadic_Operator (Orig : Iir; Operand : Iir) return Iir
+ is
+ pragma Unsuppress (Overflow_Check);
+
+ Func : Iir_Predefined_Functions;
+ begin
+ if Get_Kind (Operand) = Iir_Kind_Overflow_Literal then
+ -- Propagate overflow.
+ return Build_Overflow (Orig);
+ end if;
+
+ Func := Get_Implicit_Definition (Get_Implementation (Orig));
+ case Func is
+ when Iir_Predefined_Integer_Negation =>
+ return Build_Integer (-Get_Value (Operand), Orig);
+ when Iir_Predefined_Integer_Identity =>
+ return Build_Integer (Get_Value (Operand), Orig);
+ when Iir_Predefined_Integer_Absolute =>
+ return Build_Integer (abs Get_Value (Operand), Orig);
+
+ when Iir_Predefined_Floating_Negation =>
+ return Build_Floating (-Get_Fp_Value (Operand), Orig);
+ when Iir_Predefined_Floating_Identity =>
+ return Build_Floating (Get_Fp_Value (Operand), Orig);
+ when Iir_Predefined_Floating_Absolute =>
+ return Build_Floating (abs Get_Fp_Value (Operand), Orig);
+
+ when Iir_Predefined_Physical_Negation =>
+ return Build_Physical (-Get_Physical_Value (Operand), Orig);
+ when Iir_Predefined_Physical_Identity =>
+ return Build_Physical (Get_Physical_Value (Operand), Orig);
+ when Iir_Predefined_Physical_Absolute =>
+ return Build_Physical (abs Get_Physical_Value (Operand), Orig);
+
+ when Iir_Predefined_Boolean_Not
+ | Iir_Predefined_Bit_Not =>
+ return Build_Enumeration (Get_Enum_Pos (Operand) = 0, Orig);
+
+ when Iir_Predefined_TF_Array_Not =>
+ declare
+ O_List : Iir_List;
+ R_List : Iir_List;
+ El : Iir;
+ Lit : Iir;
+ begin
+ O_List := Get_Simple_Aggregate_List
+ (Eval_String_Literal (Operand));
+ R_List := Create_Iir_List;
+
+ for I in Natural loop
+ El := Get_Nth_Element (O_List, I);
+ exit when El = Null_Iir;
+ case Get_Enum_Pos (El) is
+ when 0 =>
+ Lit := Bit_1;
+ when 1 =>
+ Lit := Bit_0;
+ when others =>
+ raise Internal_Error;
+ end case;
+ Append_Element (R_List, Lit);
+ end loop;
+ return Build_Simple_Aggregate
+ (R_List, Orig, Get_Type (Operand));
+ end;
+ when others =>
+ Error_Internal (Orig, "eval_monadic_operator: " &
+ Iir_Predefined_Functions'Image (Func));
+ end case;
+ exception
+ when Constraint_Error =>
+ -- Can happen for absolute.
+ Warning_Msg_Sem ("arithmetic overflow in static expression", Orig);
+ return Build_Overflow (Orig);
+ end Eval_Monadic_Operator;
+
+ function Eval_Dyadic_Bit_Array_Operator
+ (Expr : Iir;
+ Left, Right : Iir;
+ Func : Iir_Predefined_Dyadic_TF_Array_Functions)
+ return Iir
+ is
+ use Str_Table;
+ L_Str : constant String_Fat_Acc := Get_String_Fat_Acc (Left);
+ R_Str : constant String_Fat_Acc := Get_String_Fat_Acc (Right);
+ Len : Nat32;
+ Id : String_Id;
+ Res : Iir;
+ begin
+ Len := Get_String_Length (Left);
+ if Len /= Get_String_Length (Right) then
+ Warning_Msg_Sem ("length of left and right operands mismatch", Expr);
+ return Build_Overflow (Expr);
+ else
+ Id := Start;
+ case Func is
+ when Iir_Predefined_TF_Array_And =>
+ for I in 1 .. Len loop
+ case L_Str (I) is
+ when '0' =>
+ Append ('0');
+ when '1' =>
+ Append (R_Str (I));
+ when others =>
+ raise Internal_Error;
+ end case;
+ end loop;
+ when Iir_Predefined_TF_Array_Nand =>
+ for I in 1 .. Len loop
+ case L_Str (I) is
+ when '0' =>
+ Append ('1');
+ when '1' =>
+ case R_Str (I) is
+ when '0' =>
+ Append ('1');
+ when '1' =>
+ Append ('0');
+ when others =>
+ raise Internal_Error;
+ end case;
+ when others =>
+ raise Internal_Error;
+ end case;
+ end loop;
+ when Iir_Predefined_TF_Array_Or =>
+ for I in 1 .. Len loop
+ case L_Str (I) is
+ when '1' =>
+ Append ('1');
+ when '0' =>
+ Append (R_Str (I));
+ when others =>
+ raise Internal_Error;
+ end case;
+ end loop;
+ when Iir_Predefined_TF_Array_Nor =>
+ for I in 1 .. Len loop
+ case L_Str (I) is
+ when '1' =>
+ Append ('0');
+ when '0' =>
+ case R_Str (I) is
+ when '0' =>
+ Append ('1');
+ when '1' =>
+ Append ('0');
+ when others =>
+ raise Internal_Error;
+ end case;
+ when others =>
+ raise Internal_Error;
+ end case;
+ end loop;
+ when Iir_Predefined_TF_Array_Xor =>
+ for I in 1 .. Len loop
+ case L_Str (I) is
+ when '1' =>
+ case R_Str (I) is
+ when '0' =>
+ Append ('1');
+ when '1' =>
+ Append ('0');
+ when others =>
+ raise Internal_Error;
+ end case;
+ when '0' =>
+ case R_Str (I) is
+ when '0' =>
+ Append ('0');
+ when '1' =>
+ Append ('1');
+ when others =>
+ raise Internal_Error;
+ end case;
+ when others =>
+ raise Internal_Error;
+ end case;
+ end loop;
+ when others =>
+ Error_Internal (Expr, "eval_dyadic_bit_array_functions: " &
+ Iir_Predefined_Functions'Image (Func));
+ end case;
+ Finish;
+ Res := Build_String (Id, Len, Expr);
+
+ -- The unconstrained type is replaced by the constrained one.
+ Set_Type (Res, Get_Type (Left));
+ return Res;
+ end if;
+ end Eval_Dyadic_Bit_Array_Operator;
+
+ -- Return TRUE if VAL /= 0.
+ function Check_Integer_Division_By_Zero (Expr : Iir; Val : Iir)
+ return Boolean
+ is
+ begin
+ if Get_Value (Val) = 0 then
+ Warning_Msg_Sem ("division by 0", Expr);
+ return False;
+ else
+ return True;
+ end if;
+ end Check_Integer_Division_By_Zero;
+
+ function Eval_Shift_Operator
+ (Left, Right : Iir; Origin : Iir; Func : Iir_Predefined_Shift_Functions)
+ return Iir
+ is
+ Count : Iir_Int64;
+ Cnt : Natural;
+ Len : Natural;
+ Arr_List : Iir_List;
+ Res_List : Iir_List;
+ Dir_Left : Boolean;
+ E : Iir;
+ begin
+ Count := Get_Value (Right);
+ Arr_List := Get_Simple_Aggregate_List (Left);
+ Len := Get_Nbr_Elements (Arr_List);
+ -- LRM93 7.2.3
+ -- That is, if R is 0 or if L is a null array, the return value is L.
+ if Count = 0 or Len = 0 then
+ return Build_Simple_Aggregate (Arr_List, Origin, Get_Type (Left));
+ end if;
+ case Func is
+ when Iir_Predefined_Array_Sll
+ | Iir_Predefined_Array_Sla
+ | Iir_Predefined_Array_Rol =>
+ Dir_Left := True;
+ when Iir_Predefined_Array_Srl
+ | Iir_Predefined_Array_Sra
+ | Iir_Predefined_Array_Ror =>
+ Dir_Left := False;
+ end case;
+ if Count < 0 then
+ Cnt := Natural (-Count);
+ Dir_Left := not Dir_Left;
+ else
+ Cnt := Natural (Count);
+ end if;
+
+ case Func is
+ when Iir_Predefined_Array_Sll
+ | Iir_Predefined_Array_Srl =>
+ declare
+ Enum_List : Iir_List;
+ begin
+ Enum_List := Get_Enumeration_Literal_List
+ (Get_Base_Type (Get_Element_Subtype (Get_Type (Left))));
+ E := Get_Nth_Element (Enum_List, 0);
+ end;
+ when Iir_Predefined_Array_Sla
+ | Iir_Predefined_Array_Sra =>
+ if Dir_Left then
+ E := Get_Nth_Element (Arr_List, Len - 1);
+ else
+ E := Get_Nth_Element (Arr_List, 0);
+ end if;
+ when Iir_Predefined_Array_Rol
+ | Iir_Predefined_Array_Ror =>
+ Cnt := Cnt mod Len;
+ if not Dir_Left then
+ Cnt := (Len - Cnt) mod Len;
+ end if;
+ end case;
+
+ Res_List := Create_Iir_List;
+
+ case Func is
+ when Iir_Predefined_Array_Sll
+ | Iir_Predefined_Array_Srl
+ | Iir_Predefined_Array_Sla
+ | Iir_Predefined_Array_Sra =>
+ if Dir_Left then
+ if Cnt < Len then
+ for I in Cnt .. Len - 1 loop
+ Append_Element
+ (Res_List, Get_Nth_Element (Arr_List, I));
+ end loop;
+ else
+ Cnt := Len;
+ end if;
+ for I in 0 .. Cnt - 1 loop
+ Append_Element (Res_List, E);
+ end loop;
+ else
+ if Cnt > Len then
+ Cnt := Len;
+ end if;
+ for I in 0 .. Cnt - 1 loop
+ Append_Element (Res_List, E);
+ end loop;
+ for I in Cnt .. Len - 1 loop
+ Append_Element
+ (Res_List, Get_Nth_Element (Arr_List, I - Cnt));
+ end loop;
+ end if;
+ when Iir_Predefined_Array_Rol
+ | Iir_Predefined_Array_Ror =>
+ for I in 1 .. Len loop
+ Append_Element
+ (Res_List, Get_Nth_Element (Arr_List, Cnt));
+ Cnt := Cnt + 1;
+ if Cnt = Len then
+ Cnt := 0;
+ end if;
+ end loop;
+ end case;
+ return Build_Simple_Aggregate (Res_List, Origin, Get_Type (Left));
+ end Eval_Shift_Operator;
+
+ -- Note: operands must be locally static.
+ function Eval_Concatenation
+ (Left, Right : Iir; Orig : Iir; Func : Iir_Predefined_Concat_Functions)
+ return Iir
+ is
+ Res_List : Iir_List;
+ L : Natural;
+ Res_Type : Iir;
+ Origin_Type : Iir;
+ Left_Aggr, Right_Aggr : Iir;
+ Left_List, Right_List : Iir_List;
+ Left_Len : Natural;
+ begin
+ Res_List := Create_Iir_List;
+ -- Do the concatenation.
+ -- Left:
+ case Func is
+ when Iir_Predefined_Element_Array_Concat
+ | Iir_Predefined_Element_Element_Concat =>
+ Append_Element (Res_List, Left);
+ Left_Len := 1;
+ when Iir_Predefined_Array_Element_Concat
+ | Iir_Predefined_Array_Array_Concat =>
+ Left_Aggr := Eval_String_Literal (Left);
+ Left_List := Get_Simple_Aggregate_List (Left_Aggr);
+ Left_Len := Get_Nbr_Elements (Left_List);
+ for I in 0 .. Left_Len - 1 loop
+ Append_Element (Res_List, Get_Nth_Element (Left_List, I));
+ end loop;
+ Free_Eval_String_Literal (Left_Aggr, Left);
+ end case;
+ -- Right:
+ case Func is
+ when Iir_Predefined_Array_Element_Concat
+ | Iir_Predefined_Element_Element_Concat =>
+ Append_Element (Res_List, Right);
+ when Iir_Predefined_Element_Array_Concat
+ | Iir_Predefined_Array_Array_Concat =>
+ Right_Aggr := Eval_String_Literal (Right);
+ Right_List := Get_Simple_Aggregate_List (Right_Aggr);
+ L := Get_Nbr_Elements (Right_List);
+ for I in 0 .. L - 1 loop
+ Append_Element (Res_List, Get_Nth_Element (Right_List, I));
+ end loop;
+ Free_Eval_String_Literal (Right_Aggr, Right);
+ end case;
+ L := Get_Nbr_Elements (Res_List);
+
+ -- Compute subtype...
+ Origin_Type := Get_Type (Orig);
+ Res_Type := Null_Iir;
+ if Func = Iir_Predefined_Array_Array_Concat
+ and then Left_Len = 0
+ then
+ if Flags.Vhdl_Std = Vhdl_87 then
+ -- LRM87 7.2.4
+ -- [...], unless the left operand is a null array, in which case
+ -- the result of the concatenation is the right operand.
+ Res_Type := Get_Type (Right);
+ else
+ -- LRM93 7.2.4
+ -- If both operands are null arrays, then the result of the
+ -- concatenation is the right operand.
+ if Get_Nbr_Elements (Right_List) = 0 then
+ Res_Type := Get_Type (Right);
+ end if;
+ end if;
+ end if;
+ if Res_Type = Null_Iir then
+ if Flags.Vhdl_Std = Vhdl_87
+ and then (Func = Iir_Predefined_Array_Array_Concat
+ or Func = Iir_Predefined_Array_Element_Concat)
+ then
+ -- LRM87 7.2.4
+ -- The left bound of the result is the left operand, [...]
+ --
+ -- LRM87 7.2.4
+ -- The direction of the result is the direction of the left
+ -- operand, [...]
+ declare
+ Left_Index : constant Iir :=
+ Get_Index_Type (Get_Type (Left), 0);
+ Left_Range : constant Iir :=
+ Get_Range_Constraint (Left_Index);
+ Ret_Type : constant Iir :=
+ Get_Return_Type (Get_Implementation (Orig));
+ A_Range : Iir;
+ Index_Type : Iir;
+ begin
+ A_Range := Create_Iir (Iir_Kind_Range_Expression);
+ Set_Type (A_Range, Get_Index_Type (Ret_Type, 0));
+ Set_Expr_Staticness (A_Range, Locally);
+ Set_Left_Limit (A_Range, Get_Left_Limit (Left_Range));
+ Set_Direction (A_Range, Get_Direction (Left_Range));
+ Location_Copy (A_Range, Orig);
+ Set_Right_Limit_By_Length (A_Range, Iir_Int64 (L));
+ Index_Type := Create_Range_Subtype_From_Type
+ (Left_Index, Get_Location (Orig));
+ Set_Range_Constraint (Index_Type, A_Range);
+ Res_Type := Create_Unidim_Array_From_Index
+ (Origin_Type, Index_Type, Orig);
+ end;
+ else
+ -- LRM93 7.2.4
+ -- Otherwise, the direction and bounds of the result are
+ -- determined as follows: let S be the index subtype of the base
+ -- type of the result. The direction of the result of the
+ -- concatenation is the direction of S, and the left bound of the
+ -- result is S'LEFT.
+ Res_Type := Create_Unidim_Array_By_Length
+ (Origin_Type, Iir_Int64 (L), Orig);
+ end if;
+ end if;
+ -- FIXME: this is not necessarily a string, it may be an aggregate if
+ -- element type is not a character type.
+ return Build_Simple_Aggregate (Res_List, Orig, Res_Type);
+ end Eval_Concatenation;
+
+ function Eval_Array_Equality (Left, Right : Iir) return Boolean
+ is
+ Left_Val, Right_Val : Iir;
+ L_List : Iir_List;
+ R_List : Iir_List;
+ N : Natural;
+ Res : Boolean;
+ begin
+ Left_Val := Eval_String_Literal (Left);
+ Right_Val := Eval_String_Literal (Right);
+
+ L_List := Get_Simple_Aggregate_List (Left_Val);
+ R_List := Get_Simple_Aggregate_List (Right_Val);
+ N := Get_Nbr_Elements (L_List);
+ if N /= Get_Nbr_Elements (R_List) then
+ -- Cannot be equal if not the same length.
+ Res := False;
+ else
+ Res := True;
+ for I in 0 .. N - 1 loop
+ -- FIXME: this is wrong: (eg: evaluated lit)
+ if Get_Nth_Element (L_List, I) /= Get_Nth_Element (R_List, I) then
+ Res := False;
+ exit;
+ end if;
+ end loop;
+ end if;
+
+ Free_Eval_Static_Expr (Left_Val, Left);
+ Free_Eval_Static_Expr (Right_Val, Right);
+
+ return Res;
+ end Eval_Array_Equality;
+
+ -- ORIG is either a dyadic operator or a function call.
+ function Eval_Dyadic_Operator (Orig : Iir; Imp : Iir; Left, Right : Iir)
+ return Iir
+ is
+ pragma Unsuppress (Overflow_Check);
+ Func : constant Iir_Predefined_Functions :=
+ Get_Implicit_Definition (Imp);
+ begin
+ if Get_Kind (Left) = Iir_Kind_Overflow_Literal
+ or else Get_Kind (Right) = Iir_Kind_Overflow_Literal
+ then
+ return Build_Overflow (Orig);
+ end if;
+
+ case Func is
+ when Iir_Predefined_Integer_Plus =>
+ return Build_Integer (Get_Value (Left) + Get_Value (Right), Orig);
+ when Iir_Predefined_Integer_Minus =>
+ return Build_Integer (Get_Value (Left) - Get_Value (Right), Orig);
+ when Iir_Predefined_Integer_Mul =>
+ return Build_Integer (Get_Value (Left) * Get_Value (Right), Orig);
+ when Iir_Predefined_Integer_Div =>
+ if Check_Integer_Division_By_Zero (Orig, Right) then
+ return Build_Integer
+ (Get_Value (Left) / Get_Value (Right), Orig);
+ else
+ return Build_Overflow (Orig);
+ end if;
+ when Iir_Predefined_Integer_Mod =>
+ if Check_Integer_Division_By_Zero (Orig, Right) then
+ return Build_Integer
+ (Get_Value (Left) mod Get_Value (Right), Orig);
+ else
+ return Build_Overflow (Orig);
+ end if;
+ when Iir_Predefined_Integer_Rem =>
+ if Check_Integer_Division_By_Zero (Orig, Right) then
+ return Build_Integer
+ (Get_Value (Left) rem Get_Value (Right), Orig);
+ else
+ return Build_Overflow (Orig);
+ end if;
+ when Iir_Predefined_Integer_Exp =>
+ return Build_Integer
+ (Get_Value (Left) ** Integer (Get_Value (Right)), Orig);
+
+ when Iir_Predefined_Integer_Equality =>
+ return Build_Boolean (Get_Value (Left) = Get_Value (Right));
+ when Iir_Predefined_Integer_Inequality =>
+ return Build_Boolean (Get_Value (Left) /= Get_Value (Right));
+ when Iir_Predefined_Integer_Greater_Equal =>
+ return Build_Boolean (Get_Value (Left) >= Get_Value (Right));
+ when Iir_Predefined_Integer_Greater =>
+ return Build_Boolean (Get_Value (Left) > Get_Value (Right));
+ when Iir_Predefined_Integer_Less_Equal =>
+ return Build_Boolean (Get_Value (Left) <= Get_Value (Right));
+ when Iir_Predefined_Integer_Less =>
+ return Build_Boolean (Get_Value (Left) < Get_Value (Right));
+
+ when Iir_Predefined_Integer_Minimum =>
+ if Get_Value (Left) < Get_Value (Right) then
+ return Left;
+ else
+ return Right;
+ end if;
+ when Iir_Predefined_Integer_Maximum =>
+ if Get_Value (Left) > Get_Value (Right) then
+ return Left;
+ else
+ return Right;
+ end if;
+
+ when Iir_Predefined_Floating_Equality =>
+ return Build_Boolean (Get_Fp_Value (Left) = Get_Fp_Value (Right));
+ when Iir_Predefined_Floating_Inequality =>
+ return Build_Boolean (Get_Fp_Value (Left) /= Get_Fp_Value (Right));
+ when Iir_Predefined_Floating_Greater =>
+ return Build_Boolean (Get_Fp_Value (Left) > Get_Fp_Value (Right));
+ when Iir_Predefined_Floating_Greater_Equal =>
+ return Build_Boolean (Get_Fp_Value (Left) >= Get_Fp_Value (Right));
+ when Iir_Predefined_Floating_Less =>
+ return Build_Boolean (Get_Fp_Value (Left) < Get_Fp_Value (Right));
+ when Iir_Predefined_Floating_Less_Equal =>
+ return Build_Boolean (Get_Fp_Value (Left) <= Get_Fp_Value (Right));
+
+ when Iir_Predefined_Floating_Minus =>
+ return Build_Floating
+ (Get_Fp_Value (Left) - Get_Fp_Value (Right), Orig);
+ when Iir_Predefined_Floating_Plus =>
+ return Build_Floating
+ (Get_Fp_Value (Left) + Get_Fp_Value (Right), Orig);
+ when Iir_Predefined_Floating_Mul =>
+ return Build_Floating
+ (Get_Fp_Value (Left) * Get_Fp_Value (Right), Orig);
+ when Iir_Predefined_Floating_Div =>
+ if Get_Fp_Value (Right) = 0.0 then
+ Warning_Msg_Sem ("right operand of division is 0", Orig);
+ return Build_Overflow (Orig);
+ else
+ return Build_Floating
+ (Get_Fp_Value (Left) / Get_Fp_Value (Right), Orig);
+ end if;
+ when Iir_Predefined_Floating_Exp =>
+ declare
+ Exp : Iir_Int64;
+ Res : Iir_Fp64;
+ Val : Iir_Fp64;
+ begin
+ Res := 1.0;
+ Val := Get_Fp_Value (Left);
+ Exp := abs Get_Value (Right);
+ while Exp /= 0 loop
+ if Exp mod 2 = 1 then
+ Res := Res * Val;
+ end if;
+ Exp := Exp / 2;
+ Val := Val * Val;
+ end loop;
+ if Get_Value (Right) < 0 then
+ Res := 1.0 / Res;
+ end if;
+ return Build_Floating (Res, Orig);
+ end;
+
+ when Iir_Predefined_Floating_Minimum =>
+ if Get_Fp_Value (Left) < Get_Fp_Value (Right) then
+ return Left;
+ else
+ return Right;
+ end if;
+ when Iir_Predefined_Floating_Maximum =>
+ if Get_Fp_Value (Left) > Get_Fp_Value (Right) then
+ return Left;
+ else
+ return Right;
+ end if;
+
+ when Iir_Predefined_Physical_Equality =>
+ return Build_Boolean
+ (Get_Physical_Value (Left) = Get_Physical_Value (Right));
+ when Iir_Predefined_Physical_Inequality =>
+ return Build_Boolean
+ (Get_Physical_Value (Left) /= Get_Physical_Value (Right));
+ when Iir_Predefined_Physical_Greater_Equal =>
+ return Build_Boolean
+ (Get_Physical_Value (Left) >= Get_Physical_Value (Right));
+ when Iir_Predefined_Physical_Greater =>
+ return Build_Boolean
+ (Get_Physical_Value (Left) > Get_Physical_Value (Right));
+ when Iir_Predefined_Physical_Less_Equal =>
+ return Build_Boolean
+ (Get_Physical_Value (Left) <= Get_Physical_Value (Right));
+ when Iir_Predefined_Physical_Less =>
+ return Build_Boolean
+ (Get_Physical_Value (Left) < Get_Physical_Value (Right));
+
+ when Iir_Predefined_Physical_Physical_Div =>
+ return Build_Integer
+ (Get_Physical_Value (Left) / Get_Physical_Value (Right), Orig);
+ when Iir_Predefined_Physical_Integer_Div =>
+ return Build_Physical
+ (Get_Physical_Value (Left) / Get_Value (Right), Orig);
+ when Iir_Predefined_Physical_Minus =>
+ return Build_Physical
+ (Get_Physical_Value (Left) - Get_Physical_Value (Right), Orig);
+ when Iir_Predefined_Physical_Plus =>
+ return Build_Physical
+ (Get_Physical_Value (Left) + Get_Physical_Value (Right), Orig);
+ when Iir_Predefined_Integer_Physical_Mul =>
+ return Build_Physical
+ (Get_Value (Left) * Get_Physical_Value (Right), Orig);
+ when Iir_Predefined_Physical_Integer_Mul =>
+ return Build_Physical
+ (Get_Physical_Value (Left) * Get_Value (Right), Orig);
+ when Iir_Predefined_Real_Physical_Mul =>
+ -- FIXME: overflow??
+ return Build_Physical
+ (Iir_Int64 (Get_Fp_Value (Left)
+ * Iir_Fp64 (Get_Physical_Value (Right))), Orig);
+ when Iir_Predefined_Physical_Real_Mul =>
+ -- FIXME: overflow??
+ return Build_Physical
+ (Iir_Int64 (Iir_Fp64 (Get_Physical_Value (Left))
+ * Get_Fp_Value (Right)), Orig);
+ when Iir_Predefined_Physical_Real_Div =>
+ -- FIXME: overflow??
+ return Build_Physical
+ (Iir_Int64 (Iir_Fp64 (Get_Physical_Value (Left))
+ / Get_Fp_Value (Right)), Orig);
+
+ when Iir_Predefined_Physical_Minimum =>
+ return Build_Physical (Iir_Int64'Min (Get_Physical_Value (Left),
+ Get_Physical_Value (Right)),
+ Orig);
+ when Iir_Predefined_Physical_Maximum =>
+ return Build_Physical (Iir_Int64'Max (Get_Physical_Value (Left),
+ Get_Physical_Value (Right)),
+ Orig);
+
+ when Iir_Predefined_Element_Array_Concat
+ | Iir_Predefined_Array_Element_Concat
+ | Iir_Predefined_Array_Array_Concat
+ | Iir_Predefined_Element_Element_Concat =>
+ return Eval_Concatenation (Left, Right, Orig, Func);
+
+ when Iir_Predefined_Enum_Equality
+ | Iir_Predefined_Bit_Match_Equality =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) = Get_Enum_Pos (Right), Orig);
+ when Iir_Predefined_Enum_Inequality
+ | Iir_Predefined_Bit_Match_Inequality =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) /= Get_Enum_Pos (Right), Orig);
+ when Iir_Predefined_Enum_Greater_Equal
+ | Iir_Predefined_Bit_Match_Greater_Equal =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) >= Get_Enum_Pos (Right), Orig);
+ when Iir_Predefined_Enum_Greater
+ | Iir_Predefined_Bit_Match_Greater =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) > Get_Enum_Pos (Right), Orig);
+ when Iir_Predefined_Enum_Less_Equal
+ | Iir_Predefined_Bit_Match_Less_Equal =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) <= Get_Enum_Pos (Right), Orig);
+ when Iir_Predefined_Enum_Less
+ | Iir_Predefined_Bit_Match_Less =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) < Get_Enum_Pos (Right), Orig);
+
+ when Iir_Predefined_Enum_Minimum =>
+ if Get_Enum_Pos (Left) < Get_Enum_Pos (Right) then
+ return Left;
+ else
+ return Right;
+ end if;
+ when Iir_Predefined_Enum_Maximum =>
+ if Get_Enum_Pos (Left) > Get_Enum_Pos (Right) then
+ return Left;
+ else
+ return Right;
+ end if;
+
+ when Iir_Predefined_Boolean_And
+ | Iir_Predefined_Bit_And =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) = 1 and Get_Enum_Pos (Right) = 1, Orig);
+ when Iir_Predefined_Boolean_Nand
+ | Iir_Predefined_Bit_Nand =>
+ return Build_Enumeration
+ (not (Get_Enum_Pos (Left) = 1 and Get_Enum_Pos (Right) = 1),
+ Orig);
+ when Iir_Predefined_Boolean_Or
+ | Iir_Predefined_Bit_Or =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) = 1 or Get_Enum_Pos (Right) = 1, Orig);
+ when Iir_Predefined_Boolean_Nor
+ | Iir_Predefined_Bit_Nor =>
+ return Build_Enumeration
+ (not (Get_Enum_Pos (Left) = 1 or Get_Enum_Pos (Right) = 1),
+ Orig);
+ when Iir_Predefined_Boolean_Xor
+ | Iir_Predefined_Bit_Xor =>
+ return Build_Enumeration
+ (Get_Enum_Pos (Left) = 1 xor Get_Enum_Pos (Right) = 1, Orig);
+ when Iir_Predefined_Boolean_Xnor
+ | Iir_Predefined_Bit_Xnor =>
+ return Build_Enumeration
+ (not (Get_Enum_Pos (Left) = 1 xor Get_Enum_Pos (Right) = 1),
+ Orig);
+
+ when Iir_Predefined_Dyadic_TF_Array_Functions =>
+ -- FIXME: only for bit ?
+ return Eval_Dyadic_Bit_Array_Operator (Orig, Left, Right, Func);
+
+ when Iir_Predefined_Universal_R_I_Mul =>
+ return Build_Floating
+ (Get_Fp_Value (Left) * Iir_Fp64 (Get_Value (Right)), Orig);
+ when Iir_Predefined_Universal_I_R_Mul =>
+ return Build_Floating
+ (Iir_Fp64 (Get_Value (Left)) * Get_Fp_Value (Right), Orig);
+ when Iir_Predefined_Universal_R_I_Div =>
+ return Build_Floating
+ (Get_Fp_Value (Left) / Iir_Fp64 (Get_Value (Right)), Orig);
+
+ when Iir_Predefined_Array_Equality =>
+ return Build_Boolean (Eval_Array_Equality (Left, Right));
+
+ when Iir_Predefined_Array_Inequality =>
+ return Build_Boolean (not Eval_Array_Equality (Left, Right));
+
+ when Iir_Predefined_Array_Sll
+ | Iir_Predefined_Array_Srl
+ | Iir_Predefined_Array_Sla
+ | Iir_Predefined_Array_Sra
+ | Iir_Predefined_Array_Rol
+ | Iir_Predefined_Array_Ror =>
+ declare
+ Left_Aggr : Iir;
+ Res : Iir;
+ begin
+ Left_Aggr := Eval_String_Literal (Left);
+ Res := Eval_Shift_Operator (Left_Aggr, Right, Orig, Func);
+ Free_Eval_String_Literal (Left_Aggr, Left);
+ return Res;
+ end;
+
+ when Iir_Predefined_Array_Less
+ | Iir_Predefined_Array_Less_Equal
+ | Iir_Predefined_Array_Greater
+ | Iir_Predefined_Array_Greater_Equal =>
+ -- FIXME: todo.
+ Error_Internal (Orig, "eval_dyadic_operator: " &
+ Iir_Predefined_Functions'Image (Func));
+
+ when Iir_Predefined_Boolean_Not
+ | Iir_Predefined_Boolean_Rising_Edge
+ | Iir_Predefined_Boolean_Falling_Edge
+ | Iir_Predefined_Bit_Not
+ | Iir_Predefined_Bit_Rising_Edge
+ | Iir_Predefined_Bit_Falling_Edge
+ | Iir_Predefined_Integer_Absolute
+ | Iir_Predefined_Integer_Identity
+ | Iir_Predefined_Integer_Negation
+ | Iir_Predefined_Floating_Absolute
+ | Iir_Predefined_Floating_Negation
+ | Iir_Predefined_Floating_Identity
+ | Iir_Predefined_Physical_Absolute
+ | Iir_Predefined_Physical_Identity
+ | Iir_Predefined_Physical_Negation
+ | Iir_Predefined_Error
+ | Iir_Predefined_Record_Equality
+ | Iir_Predefined_Record_Inequality
+ | Iir_Predefined_Access_Equality
+ | Iir_Predefined_Access_Inequality
+ | Iir_Predefined_TF_Array_Not
+ | Iir_Predefined_Now_Function
+ | Iir_Predefined_Deallocate
+ | Iir_Predefined_Write
+ | Iir_Predefined_Read
+ | Iir_Predefined_Read_Length
+ | Iir_Predefined_Flush
+ | Iir_Predefined_File_Open
+ | Iir_Predefined_File_Open_Status
+ | Iir_Predefined_File_Close
+ | Iir_Predefined_Endfile
+ | Iir_Predefined_Attribute_Image
+ | Iir_Predefined_Attribute_Value
+ | Iir_Predefined_Attribute_Pos
+ | Iir_Predefined_Attribute_Val
+ | Iir_Predefined_Attribute_Succ
+ | Iir_Predefined_Attribute_Pred
+ | Iir_Predefined_Attribute_Rightof
+ | Iir_Predefined_Attribute_Leftof
+ | Iir_Predefined_Attribute_Left
+ | Iir_Predefined_Attribute_Right
+ | Iir_Predefined_Attribute_Event
+ | Iir_Predefined_Attribute_Active
+ | Iir_Predefined_Attribute_Last_Value
+ | Iir_Predefined_Attribute_Last_Event
+ | Iir_Predefined_Attribute_Last_Active
+ | Iir_Predefined_Attribute_Driving
+ | Iir_Predefined_Attribute_Driving_Value
+ | Iir_Predefined_Array_Char_To_String
+ | Iir_Predefined_Bit_Vector_To_Ostring
+ | Iir_Predefined_Bit_Vector_To_Hstring =>
+ -- Not binary or never locally static.
+ Error_Internal (Orig, "eval_dyadic_operator: " &
+ Iir_Predefined_Functions'Image (Func));
+
+ when Iir_Predefined_Bit_Condition =>
+ raise Internal_Error;
+
+ when Iir_Predefined_Array_Minimum
+ | Iir_Predefined_Array_Maximum
+ | Iir_Predefined_Vector_Minimum
+ | Iir_Predefined_Vector_Maximum =>
+ raise Internal_Error;
+
+ when Iir_Predefined_Std_Ulogic_Match_Equality
+ | Iir_Predefined_Std_Ulogic_Match_Inequality
+ | Iir_Predefined_Std_Ulogic_Match_Less
+ | Iir_Predefined_Std_Ulogic_Match_Less_Equal
+ | Iir_Predefined_Std_Ulogic_Match_Greater
+ | Iir_Predefined_Std_Ulogic_Match_Greater_Equal =>
+ -- TODO
+ raise Internal_Error;
+
+ when Iir_Predefined_Enum_To_String
+ | Iir_Predefined_Integer_To_String
+ | Iir_Predefined_Floating_To_String
+ | Iir_Predefined_Real_To_String_Digits
+ | Iir_Predefined_Real_To_String_Format
+ | Iir_Predefined_Physical_To_String
+ | Iir_Predefined_Time_To_String_Unit =>
+ -- TODO
+ raise Internal_Error;
+
+ when Iir_Predefined_TF_Array_Element_And
+ | Iir_Predefined_TF_Element_Array_And
+ | Iir_Predefined_TF_Array_Element_Or
+ | Iir_Predefined_TF_Element_Array_Or
+ | Iir_Predefined_TF_Array_Element_Nand
+ | Iir_Predefined_TF_Element_Array_Nand
+ | Iir_Predefined_TF_Array_Element_Nor
+ | Iir_Predefined_TF_Element_Array_Nor
+ | Iir_Predefined_TF_Array_Element_Xor
+ | Iir_Predefined_TF_Element_Array_Xor
+ | Iir_Predefined_TF_Array_Element_Xnor
+ | Iir_Predefined_TF_Element_Array_Xnor =>
+ -- TODO
+ raise Internal_Error;
+
+ when Iir_Predefined_TF_Reduction_And
+ | Iir_Predefined_TF_Reduction_Or
+ | Iir_Predefined_TF_Reduction_Nand
+ | Iir_Predefined_TF_Reduction_Nor
+ | Iir_Predefined_TF_Reduction_Xor
+ | Iir_Predefined_TF_Reduction_Xnor
+ | Iir_Predefined_TF_Reduction_Not =>
+ -- TODO
+ raise Internal_Error;
+
+ when Iir_Predefined_Bit_Array_Match_Equality
+ | Iir_Predefined_Bit_Array_Match_Inequality
+ | Iir_Predefined_Std_Ulogic_Array_Match_Equality
+ | Iir_Predefined_Std_Ulogic_Array_Match_Inequality =>
+ -- TODO
+ raise Internal_Error;
+ end case;
+ exception
+ when Constraint_Error =>
+ Warning_Msg_Sem ("arithmetic overflow in static expression", Orig);
+ return Build_Overflow (Orig);
+ end Eval_Dyadic_Operator;
+
+ -- Evaluate any array attribute, return the type for the prefix.
+ function Eval_Array_Attribute (Attr : Iir) return Iir
+ is
+ Prefix : Iir;
+ Prefix_Type : Iir;
+ begin
+ Prefix := Get_Prefix (Attr);
+ case Get_Kind (Prefix) is
+ when Iir_Kinds_Object_Declaration -- FIXME: remove
+ | Iir_Kind_Selected_Element
+ | Iir_Kind_Indexed_Name
+ | Iir_Kind_Slice_Name
+ | Iir_Kind_Subtype_Declaration
+ | Iir_Kind_Type_Declaration
+ | Iir_Kind_Implicit_Dereference =>
+ Prefix_Type := Get_Type (Prefix);
+ when Iir_Kind_Attribute_Value =>
+ -- The type of the attribute declaration may be unconstrained.
+ Prefix_Type := Get_Type
+ (Get_Expression (Get_Attribute_Specification (Prefix)));
+ when Iir_Kinds_Subtype_Definition =>
+ Prefix_Type := Prefix;
+ when Iir_Kinds_Denoting_Name =>
+ Prefix_Type := Get_Type (Prefix);
+ when others =>
+ Error_Kind ("eval_array_attribute", Prefix);
+ end case;
+ if Get_Kind (Prefix_Type) /= Iir_Kind_Array_Subtype_Definition then
+ Error_Kind ("eval_array_attribute(2)", Prefix_Type);
+ end if;
+ return Get_Nth_Element (Get_Index_Subtype_List (Prefix_Type),
+ Natural (Get_Value (Get_Parameter (Attr)) - 1));
+ end Eval_Array_Attribute;
+
+ function Eval_Integer_Image (Val : Iir_Int64; Orig : Iir) return Iir
+ is
+ use Str_Table;
+ Img : String (1 .. 24); -- 23 is enough, 24 is rounded.
+ L : Natural;
+ V : Iir_Int64;
+ Id : String_Id;
+ begin
+ V := Val;
+ L := Img'Last;
+ loop
+ Img (L) := Character'Val (Character'Pos ('0') + abs (V rem 10));
+ V := V / 10;
+ L := L - 1;
+ exit when V = 0;
+ end loop;
+ if Val < 0 then
+ Img (L) := '-';
+ L := L - 1;
+ end if;
+ Id := Start;
+ for I in L + 1 .. Img'Last loop
+ Append (Img (I));
+ end loop;
+ Finish;
+ return Build_String (Id, Int32 (Img'Last - L), Orig);
+ end Eval_Integer_Image;
+
+ function Eval_Floating_Image (Val : Iir_Fp64; Orig : Iir) return Iir
+ is
+ use Str_Table;
+ Id : String_Id;
+
+ -- Sign (1) + digit (1) + dot (1) + digits (15) + exp (1) + sign (1)
+ -- + exp_digits (4) -> 24.
+ Str : String (1 .. 25);
+ P : Natural;
+ V : Iir_Fp64;
+ Vd : Iir_Fp64;
+ Exp : Integer;
+ D : Integer;
+ B : Boolean;
+
+ Res : Iir;
+ begin
+ -- Handle sign.
+ if Val < 0.0 then
+ Str (1) := '-';
+ P := 1;
+ V := -Val;
+ else
+ P := 0;
+ V := Val;
+ end if;
+
+ -- Compute the mantissa.
+ -- FIXME: should do a dichotomy.
+ if V = 0.0 then
+ Exp := 0;
+ elsif V < 1.0 then
+ Exp := -1;
+ while V * (10.0 ** (-Exp)) < 1.0 loop
+ Exp := Exp - 1;
+ end loop;
+ else
+ Exp := 0;
+ while V / (10.0 ** Exp) >= 10.0 loop
+ Exp := Exp + 1;
+ end loop;
+ end if;
+
+ -- Normalize VAL: in [0; 10[
+ if Exp >= 0 then
+ V := V / (10.0 ** Exp);
+ else
+ V := V * 10.0 ** (-Exp);
+ end if;
+
+ for I in 0 .. 15 loop
+ Vd := Iir_Fp64'Truncation (V);
+ P := P + 1;
+ Str (P) := Character'Val (48 + Integer (Vd));
+ V := (V - Vd) * 10.0;
+
+ if I = 0 then
+ P := P + 1;
+ Str (P) := '.';
+ end if;
+ exit when I > 0 and V < 10.0 ** (I + 1 - 15);
+ end loop;
+
+ if Exp /= 0 then
+ -- LRM93 14.3
+ -- if the exponent is present, the `e' is written as a lower case
+ -- character.
+ P := P + 1;
+ Str (P) := 'e';
+
+ if Exp < 0 then
+ P := P + 1;
+ Str (P) := '-';
+ Exp := -Exp;
+ end if;
+ B := False;
+ for I in 0 .. 4 loop
+ D := (Exp / 10000) mod 10;
+ if D /= 0 or B or I = 4 then
+ P := P + 1;
+ Str (P) := Character'Val (48 + D);
+ B := True;
+ end if;
+ Exp := (Exp - D * 10000) * 10;
+ end loop;
+ end if;
+
+ Id := Start;
+ for I in 1 .. P loop
+ Append (Str (I));
+ end loop;
+ Finish;
+ Res := Build_String (Id, Int32 (P), Orig);
+ -- FIXME: this is not correct since the type is *not* constrained.
+ Set_Type (Res, Create_Unidim_Array_By_Length
+ (Get_Type (Orig), Iir_Int64 (P), Orig));
+ return Res;
+ end Eval_Floating_Image;
+
+ function Eval_Enumeration_Image (Enum, Expr : Iir) return Iir
+ is
+ Name : constant String := Image_Identifier (Enum);
+ Image_Id : constant String_Id := Str_Table.Start;
+ begin
+ for i in Name'range loop
+ Str_Table.Append(Name(i));
+ end loop;
+ Str_Table.Finish;
+ return Build_String (Image_Id, Nat32(Name'Length), Expr);
+ end Eval_Enumeration_Image;
+
+ function Build_Enumeration_Value (Val : String; Enum, Expr : Iir) return Iir
+ is
+ Value : String (Val'range);
+ List : constant Iir_List := Get_Enumeration_Literal_List (Enum);
+ begin
+ for I in Val'range loop
+ Value (I) := Ada.Characters.Handling.To_Lower (Val (I));
+ end loop;
+ for I in 0 .. Get_Nbr_Elements (List) - 1 loop
+ if Value = Image_Identifier (Get_Nth_Element (List, I)) then
+ return Build_Enumeration (Iir_Index32 (I), Expr);
+ end if;
+ end loop;
+ Warning_Msg_Sem ("value """ & Value & """ not in enumeration", Expr);
+ return Build_Overflow (Expr);
+ end Build_Enumeration_Value;
+
+ function Eval_Physical_Image (Phys, Expr: Iir) return Iir
+ is
+ -- Reduces to the base unit (e.g. femtoseconds).
+ Value : constant String := Iir_Int64'Image (Get_Physical_Value (Phys));
+ Unit : constant Iir :=
+ Get_Primary_Unit (Get_Base_Type (Get_Type (Phys)));
+ UnitName : constant String := Image_Identifier (Unit);
+ Image_Id : constant String_Id := Str_Table.Start;
+ Length : Nat32 := Value'Length + UnitName'Length + 1;
+ begin
+ for I in Value'range loop
+ -- Suppress the Ada +ve integer'image leading space
+ if I > Value'first or else Value (I) /= ' ' then
+ Str_Table.Append (Value (I));
+ else
+ Length := Length - 1;
+ end if;
+ end loop;
+ Str_Table.Append (' ');
+ for I in UnitName'range loop
+ Str_Table.Append (UnitName (I));
+ end loop;
+ Str_Table.Finish;
+
+ return Build_String (Image_Id, Length, Expr);
+ end Eval_Physical_Image;
+
+ function Build_Physical_Value (Val: String; Phys_Type, Expr: Iir) return Iir
+ is
+ function White (C : in Character) return Boolean is
+ NBSP : constant Character := Character'Val (160);
+ HT : constant Character := Character'Val (9);
+ begin
+ return C = ' ' or C = NBSP or C = HT;
+ end White;
+
+ UnitName : String (Val'range);
+ Mult : Iir_Int64;
+ Sep : Natural;
+ Found_Unit : Boolean := false;
+ Found_Real : Boolean := false;
+ Unit : Iir := Get_Primary_Unit (Phys_Type);
+ begin
+ -- Separate string into numeric value and make lowercase unit.
+ for I in reverse Val'range loop
+ UnitName (I) := Ada.Characters.Handling.To_Lower (Val (I));
+ if White (Val (I)) and Found_Unit then
+ Sep := I;
+ exit;
+ else
+ Found_Unit := true;
+ end if;
+ end loop;
+
+ -- Unit name is UnitName(Sep+1..Unit'Last)
+ for I in Val'First .. Sep loop
+ if Val (I) = '.' then
+ Found_Real := true;
+ end if;
+ end loop;
+
+ -- Chain down the units looking for matching one
+ Unit := Get_Primary_Unit (Phys_Type);
+ while Unit /= Null_Iir loop
+ exit when (UnitName (Sep + 1 .. UnitName'Last)
+ = Image_Identifier (Unit));
+ Unit := Get_Chain (Unit);
+ end loop;
+ if Unit = Null_Iir then
+ Warning_Msg_Sem ("Unit """ & UnitName (Sep + 1 .. UnitName'Last)
+ & """ not in physical type", Expr);
+ return Build_Overflow (Expr);
+ end if;
+
+ Mult := Get_Value (Get_Physical_Unit_Value (Unit));
+ if Found_Real then
+ return Build_Physical
+ (Iir_Int64 (Iir_Fp64'Value (Val (Val'First .. Sep))
+ * Iir_Fp64 (Mult)),
+ Expr);
+ else
+ return Build_Physical
+ (Iir_Int64'Value (Val (Val'First .. Sep)) * Mult, Expr);
+ end if;
+ end Build_Physical_Value;
+
+ function Eval_Incdec (Expr : Iir; N : Iir_Int64; Origin : Iir) return Iir
+ is
+ P : Iir_Int64;
+ begin
+ case Get_Kind (Expr) is
+ when Iir_Kind_Integer_Literal =>
+ return Build_Integer (Get_Value (Expr) + N, Origin);
+ when Iir_Kind_Enumeration_Literal =>
+ P := Iir_Int64 (Get_Enum_Pos (Expr)) + N;
+ if P < 0 then
+ Warning_Msg_Sem ("static constant violates bounds", Expr);
+ return Build_Overflow (Origin);
+ else
+ return Build_Enumeration (Iir_Index32 (P), Origin);
+ end if;
+ when Iir_Kind_Physical_Int_Literal
+ | Iir_Kind_Unit_Declaration =>
+ return Build_Physical (Get_Physical_Value (Expr) + N, Origin);
+ when others =>
+ Error_Kind ("eval_incdec", Expr);
+ end case;
+ end Eval_Incdec;
+
+ function Convert_Range (Rng : Iir; Res_Type : Iir; Loc : Iir) return Iir
+ is
+ Res_Btype : Iir;
+
+ function Create_Bound (Val : Iir) return Iir
+ is
+ R : Iir;
+ begin
+ R := Create_Iir (Iir_Kind_Integer_Literal);
+ Location_Copy (R, Loc);
+ Set_Value (R, Get_Value (Val));
+ Set_Type (R, Res_Btype);
+ Set_Expr_Staticness (R, Locally);
+ return R;
+ end Create_Bound;
+
+ Res : Iir;
+ begin
+ Res_Btype := Get_Base_Type (Res_Type);
+ Res := Create_Iir (Iir_Kind_Range_Expression);
+ Location_Copy (Res, Loc);
+ Set_Type (Res, Res_Btype);
+ Set_Left_Limit (Res, Create_Bound (Get_Left_Limit (Rng)));
+ Set_Right_Limit (Res, Create_Bound (Get_Right_Limit (Rng)));
+ Set_Direction (Res, Get_Direction (Rng));
+ Set_Expr_Staticness (Res, Locally);
+ return Res;
+ end Convert_Range;
+
+ function Eval_Array_Type_Conversion (Conv : Iir; Val : Iir) return Iir
+ is
+ Conv_Type : constant Iir := Get_Type (Conv);
+ Val_Type : constant Iir := Get_Type (Val);
+ Conv_Index_Type : constant Iir := Get_Index_Type (Conv_Type, 0);
+ Val_Index_Type : constant Iir := Get_Index_Type (Val_Type, 0);
+ Index_Type : Iir;
+ Res_Type : Iir;
+ Res : Iir;
+ Rng : Iir;
+ begin
+ -- The expression is either a simple aggregate or a (bit) string.
+ Res := Build_Constant (Val, Conv);
+ case Get_Kind (Conv_Type) is
+ when Iir_Kind_Array_Subtype_Definition =>
+ Set_Type (Res, Conv_Type);
+ if Eval_Discrete_Type_Length (Conv_Index_Type)
+ /= Eval_Discrete_Type_Length (Val_Index_Type)
+ then
+ Warning_Msg_Sem
+ ("non matching length in type conversion", Conv);
+ return Build_Overflow (Conv);
+ end if;
+ return Res;
+ when Iir_Kind_Array_Type_Definition =>
+ if Get_Base_Type (Conv_Index_Type) = Get_Base_Type (Val_Index_Type)
+ then
+ Index_Type := Val_Index_Type;
+ else
+ -- Convert the index range.
+ -- It is an integer type.
+ Rng := Convert_Range (Get_Range_Constraint (Val_Index_Type),
+ Conv_Index_Type, Conv);
+ Index_Type := Create_Iir (Iir_Kind_Integer_Subtype_Definition);
+ Location_Copy (Index_Type, Conv);
+ Set_Range_Constraint (Index_Type, Rng);
+ Set_Base_Type (Index_Type, Get_Base_Type (Conv_Index_Type));
+ Set_Type_Staticness (Index_Type, Locally);
+ end if;
+ Res_Type := Create_Unidim_Array_From_Index
+ (Get_Base_Type (Conv_Type), Index_Type, Conv);
+ Set_Type (Res, Res_Type);
+ Set_Type_Conversion_Subtype (Conv, Res_Type);
+ return Res;
+ when others =>
+ Error_Kind ("eval_array_type_conversion", Conv_Type);
+ end case;
+ end Eval_Array_Type_Conversion;
+
+ function Eval_Type_Conversion (Expr : Iir) return Iir
+ is
+ Val : Iir;
+ Val_Type : Iir;
+ Conv_Type : Iir;
+ begin
+ Val := Eval_Static_Expr (Get_Expression (Expr));
+ Val_Type := Get_Base_Type (Get_Type (Val));
+ Conv_Type := Get_Base_Type (Get_Type (Expr));
+ if Conv_Type = Val_Type then
+ return Build_Constant (Val, Expr);
+ end if;
+ case Get_Kind (Conv_Type) is
+ when Iir_Kind_Integer_Type_Definition =>
+ case Get_Kind (Val_Type) is
+ when Iir_Kind_Integer_Type_Definition =>
+ return Build_Integer (Get_Value (Val), Expr);
+ when Iir_Kind_Floating_Type_Definition =>
+ return Build_Integer (Iir_Int64 (Get_Fp_Value (Val)), Expr);
+ when others =>
+ Error_Kind ("eval_type_conversion(1)", Val_Type);
+ end case;
+ when Iir_Kind_Floating_Type_Definition =>
+ case Get_Kind (Val_Type) is
+ when Iir_Kind_Integer_Type_Definition =>
+ return Build_Floating (Iir_Fp64 (Get_Value (Val)), Expr);
+ when Iir_Kind_Floating_Type_Definition =>
+ return Build_Floating (Get_Fp_Value (Val), Expr);
+ when others =>
+ Error_Kind ("eval_type_conversion(2)", Val_Type);
+ end case;
+ when Iir_Kind_Array_Type_Definition =>
+ return Eval_Array_Type_Conversion (Expr, Val);
+ when others =>
+ Error_Kind ("eval_type_conversion(3)", Conv_Type);
+ end case;
+ end Eval_Type_Conversion;
+
+ function Eval_Physical_Literal (Expr : Iir) return Iir
+ is
+ Val : Iir;
+ begin
+ case Get_Kind (Expr) is
+ when Iir_Kind_Physical_Fp_Literal =>
+ Val := Expr;
+ when Iir_Kind_Physical_Int_Literal =>
+ if Get_Named_Entity (Get_Unit_Name (Expr))
+ = Get_Primary_Unit (Get_Base_Type (Get_Type (Expr)))
+ then
+ return Expr;
+ else
+ Val := Expr;
+ end if;
+ when Iir_Kind_Unit_Declaration =>
+ Val := Expr;
+ when Iir_Kinds_Denoting_Name =>
+ Val := Get_Named_Entity (Expr);
+ pragma Assert (Get_Kind (Val) = Iir_Kind_Unit_Declaration);
+ when others =>
+ Error_Kind ("eval_physical_literal", Expr);
+ end case;
+ return Build_Physical (Get_Physical_Value (Val), Expr);
+ end Eval_Physical_Literal;
+
+ function Eval_Static_Expr (Expr: Iir) return Iir
+ is
+ Res : Iir;
+ Val : Iir;
+ begin
+ case Get_Kind (Expr) is
+ when Iir_Kinds_Denoting_Name =>
+ return Eval_Static_Expr (Get_Named_Entity (Expr));
+
+ when Iir_Kind_Integer_Literal
+ | Iir_Kind_Enumeration_Literal
+ | Iir_Kind_Floating_Point_Literal
+ | Iir_Kind_String_Literal
+ | Iir_Kind_Bit_String_Literal
+ | Iir_Kind_Overflow_Literal
+ | Iir_Kind_Physical_Int_Literal
+ | Iir_Kind_Physical_Fp_Literal =>
+ return Expr;
+ when Iir_Kind_Constant_Declaration =>
+ Val := Eval_Static_Expr (Get_Default_Value (Expr));
+ -- Type of the expression should be type of the constant
+ -- declaration at least in case of array subtype.
+ -- If the constant is declared as an unconstrained array, get type
+ -- from the default value.
+ -- FIXME: handle this during semantisation of the declaration:
+ -- add an implicit subtype conversion node ?
+ -- FIXME: this currently creates a node at each evalation.
+ if Get_Kind (Get_Type (Val)) = Iir_Kind_Array_Type_Definition then
+ Res := Build_Constant (Val, Expr);
+ Set_Type (Res, Get_Type (Val));
+ return Res;
+ else
+ return Val;
+ end if;
+ when Iir_Kind_Object_Alias_Declaration =>
+ return Eval_Static_Expr (Get_Name (Expr));
+ when Iir_Kind_Unit_Declaration =>
+ return Get_Physical_Unit_Value (Expr);
+ when Iir_Kind_Simple_Aggregate =>
+ return Expr;
+
+ when Iir_Kind_Parenthesis_Expression =>
+ return Eval_Static_Expr (Get_Expression (Expr));
+ when Iir_Kind_Qualified_Expression =>
+ return Eval_Static_Expr (Get_Expression (Expr));
+ when Iir_Kind_Type_Conversion =>
+ return Eval_Type_Conversion (Expr);
+
+ when Iir_Kinds_Monadic_Operator =>
+ declare
+ Operand : Iir;
+ begin
+ Operand := Eval_Static_Expr (Get_Operand (Expr));
+ return Eval_Monadic_Operator (Expr, Operand);
+ end;
+ when Iir_Kinds_Dyadic_Operator =>
+ declare
+ Left : constant Iir := Get_Left (Expr);
+ Right : constant Iir := Get_Right (Expr);
+ Left_Val, Right_Val : Iir;
+ Res : Iir;
+ begin
+ Left_Val := Eval_Static_Expr (Left);
+ Right_Val := Eval_Static_Expr (Right);
+
+ Res := Eval_Dyadic_Operator
+ (Expr, Get_Implementation (Expr), Left_Val, Right_Val);
+
+ Free_Eval_Static_Expr (Left_Val, Left);
+ Free_Eval_Static_Expr (Right_Val, Right);
+
+ return Res;
+ end;
+
+ when Iir_Kind_Attribute_Name =>
+ -- An attribute name designates an attribute value.
+ declare
+ Attr_Val : constant Iir := Get_Named_Entity (Expr);
+ Attr_Expr : constant Iir :=
+ Get_Expression (Get_Attribute_Specification (Attr_Val));
+ Val : Iir;
+ begin
+ Val := Eval_Static_Expr (Attr_Expr);
+ -- FIXME: see constant_declaration.
+ -- Currently, this avoids weird nodes, such as a string literal
+ -- whose type is an unconstrained array type.
+ Res := Build_Constant (Val, Expr);
+ Set_Type (Res, Get_Type (Val));
+ return Res;
+ end;
+
+ when Iir_Kind_Pos_Attribute =>
+ declare
+ Param : constant Iir := Get_Parameter (Expr);
+ Val : Iir;
+ Res : Iir;
+ begin
+ Val := Eval_Static_Expr (Param);
+ -- FIXME: check bounds, handle overflow.
+ Res := Build_Integer (Eval_Pos (Val), Expr);
+ Free_Eval_Static_Expr (Val, Param);
+ return Res;
+ end;
+ when Iir_Kind_Val_Attribute =>
+ declare
+ Expr_Type : constant Iir := Get_Type (Expr);
+ Val_Expr : Iir;
+ Val : Iir_Int64;
+ begin
+ Val_Expr := Eval_Static_Expr (Get_Parameter (Expr));
+ Val := Eval_Pos (Val_Expr);
+ -- Note: the type of 'val is a base type.
+ -- FIXME: handle VHDL93 restrictions.
+ if Get_Kind (Expr_Type) = Iir_Kind_Enumeration_Type_Definition
+ and then
+ not Eval_Int_In_Range (Val, Get_Range_Constraint (Expr_Type))
+ then
+ Warning_Msg_Sem
+ ("static argument out of the type range", Expr);
+ return Build_Overflow (Expr);
+ end if;
+ if Get_Kind (Get_Base_Type (Get_Type (Expr)))
+ = Iir_Kind_Physical_Type_Definition
+ then
+ return Build_Physical (Val, Expr);
+ else
+ return Build_Discrete (Val, Expr);
+ end if;
+ end;
+ when Iir_Kind_Image_Attribute =>
+ declare
+ Param : Iir;
+ Param_Type : Iir;
+ begin
+ Param := Get_Parameter (Expr);
+ Param := Eval_Static_Expr (Param);
+ Set_Parameter (Expr, Param);
+ Param_Type := Get_Base_Type (Get_Type (Param));
+ case Get_Kind (Param_Type) is
+ when Iir_Kind_Integer_Type_Definition =>
+ return Eval_Integer_Image (Get_Value (Param), Expr);
+ when Iir_Kind_Floating_Type_Definition =>
+ return Eval_Floating_Image (Get_Fp_Value (Param), Expr);
+ when Iir_Kind_Enumeration_Type_Definition =>
+ return Eval_Enumeration_Image (Param, Expr);
+ when Iir_Kind_Physical_Type_Definition =>
+ return Eval_Physical_Image (Param, Expr);
+ when others =>
+ Error_Kind ("eval_static_expr('image)", Param);
+ end case;
+ end;
+ when Iir_Kind_Value_Attribute =>
+ declare
+ Param : Iir;
+ Param_Type : Iir;
+ begin
+ Param := Get_Parameter (Expr);
+ Param := Eval_Static_Expr (Param);
+ Set_Parameter (Expr, Param);
+ if Get_Kind (Param) /= Iir_Kind_String_Literal then
+ -- FIXME: Isn't it an implementation restriction.
+ Warning_Msg_Sem ("'value argument not a string", Expr);
+ return Build_Overflow (Expr);
+ else
+ -- what type are we converting the string to?
+ Param_Type := Get_Base_Type (Get_Type (Expr));
+ declare
+ Value : constant String := Image_String_Lit (Param);
+ begin
+ case Get_Kind (Param_Type) is
+ when Iir_Kind_Integer_Type_Definition =>
+ return Build_Discrete (Iir_Int64'Value (Value), Expr);
+ when Iir_Kind_Enumeration_Type_Definition =>
+ return Build_Enumeration_Value (Value, Param_Type,
+ Expr);
+ when Iir_Kind_Floating_Type_Definition =>
+ return Build_Floating (Iir_Fp64'value (Value), Expr);
+ when Iir_Kind_Physical_Type_Definition =>
+ return Build_Physical_Value (Value, Param_Type, Expr);
+ when others =>
+ Error_Kind ("eval_static_expr('value)", Param);
+ end case;
+ end;
+ end if;
+ end;
+
+ when Iir_Kind_Left_Type_Attribute =>
+ return Eval_Static_Expr
+ (Get_Left_Limit (Eval_Static_Range (Get_Prefix (Expr))));
+ when Iir_Kind_Right_Type_Attribute =>
+ return Eval_Static_Expr
+ (Get_Right_Limit (Eval_Static_Range (Get_Prefix (Expr))));
+ when Iir_Kind_High_Type_Attribute =>
+ return Eval_Static_Expr
+ (Get_High_Limit (Eval_Static_Range (Get_Prefix (Expr))));
+ when Iir_Kind_Low_Type_Attribute =>
+ return Eval_Static_Expr
+ (Get_Low_Limit (Eval_Static_Range (Get_Prefix (Expr))));
+ when Iir_Kind_Ascending_Type_Attribute =>
+ return Build_Boolean
+ (Get_Direction (Eval_Static_Range (Get_Prefix (Expr))) = Iir_To);
+
+ when Iir_Kind_Length_Array_Attribute =>
+ declare
+ Index : Iir;
+ begin
+ Index := Eval_Array_Attribute (Expr);
+ return Build_Discrete (Eval_Discrete_Type_Length (Index), Expr);
+ end;
+ when Iir_Kind_Left_Array_Attribute =>
+ declare
+ Index : Iir;
+ begin
+ Index := Eval_Array_Attribute (Expr);
+ return Eval_Static_Expr
+ (Get_Left_Limit (Get_Range_Constraint (Index)));
+ end;
+ when Iir_Kind_Right_Array_Attribute =>
+ declare
+ Index : Iir;
+ begin
+ Index := Eval_Array_Attribute (Expr);
+ return Eval_Static_Expr
+ (Get_Right_Limit (Get_Range_Constraint (Index)));
+ end;
+ when Iir_Kind_Low_Array_Attribute =>
+ declare
+ Index : Iir;
+ begin
+ Index := Eval_Array_Attribute (Expr);
+ return Eval_Static_Expr
+ (Get_Low_Limit (Get_Range_Constraint (Index)));
+ end;
+ when Iir_Kind_High_Array_Attribute =>
+ declare
+ Index : Iir;
+ begin
+ Index := Eval_Array_Attribute (Expr);
+ return Eval_Static_Expr
+ (Get_High_Limit (Get_Range_Constraint (Index)));
+ end;
+ when Iir_Kind_Ascending_Array_Attribute =>
+ declare
+ Index : Iir;
+ begin
+ Index := Eval_Array_Attribute (Expr);
+ return Build_Boolean
+ (Get_Direction (Get_Range_Constraint (Index)) = Iir_To);
+ end;
+
+ when Iir_Kind_Pred_Attribute =>
+ Res := Eval_Incdec
+ (Eval_Static_Expr (Get_Parameter (Expr)), -1, Expr);
+ Eval_Check_Bound (Res, Get_Type (Get_Prefix (Expr)));
+ return Res;
+ when Iir_Kind_Succ_Attribute =>
+ Res := Eval_Incdec
+ (Eval_Static_Expr (Get_Parameter (Expr)), +1, Expr);
+ Eval_Check_Bound (Res, Get_Type (Get_Prefix (Expr)));
+ return Res;
+ when Iir_Kind_Leftof_Attribute
+ | Iir_Kind_Rightof_Attribute =>
+ declare
+ Rng : Iir;
+ N : Iir_Int64;
+ Prefix_Type : Iir;
+ Res : Iir;
+ begin
+ Prefix_Type := Get_Type (Get_Prefix (Expr));
+ Rng := Eval_Static_Range (Prefix_Type);
+ case Get_Direction (Rng) is
+ when Iir_To =>
+ N := 1;
+ when Iir_Downto =>
+ N := -1;
+ end case;
+ case Get_Kind (Expr) is
+ when Iir_Kind_Leftof_Attribute =>
+ N := -N;
+ when Iir_Kind_Rightof_Attribute =>
+ null;
+ when others =>
+ raise Internal_Error;
+ end case;
+ Res := Eval_Incdec
+ (Eval_Static_Expr (Get_Parameter (Expr)), N, Expr);
+ Eval_Check_Bound (Res, Prefix_Type);
+ return Res;
+ end;
+
+ when Iir_Kind_Simple_Name_Attribute =>
+ declare
+ use Str_Table;
+ Id : String_Id;
+ begin
+ Id := Start;
+ Image (Get_Simple_Name_Identifier (Expr));
+ for I in 1 .. Name_Length loop
+ Append (Name_Buffer (I));
+ end loop;
+ Finish;
+ return Build_String (Id, Nat32 (Name_Length), Expr);
+ end;
+
+ when Iir_Kind_Null_Literal =>
+ return Expr;
+
+ when Iir_Kind_Function_Call =>
+ declare
+ Imp : constant Iir := Get_Implementation (Expr);
+ Left, Right : Iir;
+ begin
+ -- Note: there can't be association by name.
+ Left := Get_Parameter_Association_Chain (Expr);
+ Right := Get_Chain (Left);
+
+ Left := Eval_Static_Expr (Get_Actual (Left));
+ if Right = Null_Iir then
+ return Eval_Monadic_Operator (Expr, Left);
+ else
+ Right := Eval_Static_Expr (Get_Actual (Right));
+ return Eval_Dyadic_Operator (Expr, Imp, Left, Right);
+ end if;
+ end;
+
+ when Iir_Kind_Error =>
+ return Expr;
+ when others =>
+ Error_Kind ("eval_static_expr", Expr);
+ end case;
+ end Eval_Static_Expr;
+
+ -- If FORCE is true, always return a literal.
+ function Eval_Expr_Keep_Orig (Expr : Iir; Force : Boolean) return Iir
+ is
+ Res : Iir;
+ begin
+ case Get_Kind (Expr) is
+ when Iir_Kinds_Denoting_Name =>
+ declare
+ Orig : constant Iir := Get_Named_Entity (Expr);
+ begin
+ Res := Eval_Static_Expr (Orig);
+ if Res /= Orig or else Force then
+ return Build_Constant (Res, Expr);
+ else
+ return Expr;
+ end if;
+ end;
+ when others =>
+ Res := Eval_Static_Expr (Expr);
+ if Res /= Expr
+ and then Get_Literal_Origin (Res) /= Expr
+ then
+ -- Need to build a constant if the result is a different
+ -- literal not tied to EXPR.
+ return Build_Constant (Res, Expr);
+ else
+ return Res;
+ end if;
+ end case;
+ end Eval_Expr_Keep_Orig;
+
+ function Eval_Expr (Expr: Iir) return Iir is
+ begin
+ if Get_Expr_Staticness (Expr) /= Locally then
+ Error_Msg_Sem ("expression must be locally static", Expr);
+ return Expr;
+ else
+ return Eval_Expr_Keep_Orig (Expr, False);
+ end if;
+ end Eval_Expr;
+
+ function Eval_Expr_If_Static (Expr : Iir) return Iir is
+ begin
+ if Expr /= Null_Iir and then Get_Expr_Staticness (Expr) = Locally then
+ return Eval_Expr_Keep_Orig (Expr, False);
+ else
+ return Expr;
+ end if;
+ end Eval_Expr_If_Static;
+
+ function Eval_Expr_Check (Expr : Iir; Sub_Type : Iir) return Iir
+ is
+ Res : Iir;
+ begin
+ Res := Eval_Expr_Keep_Orig (Expr, False);
+ Eval_Check_Bound (Res, Sub_Type);
+ return Res;
+ end Eval_Expr_Check;
+
+ function Eval_Expr_Check_If_Static (Expr : Iir; Atype : Iir) return Iir
+ is
+ Res : Iir;
+ begin
+ if Expr /= Null_Iir and then Get_Expr_Staticness (Expr) = Locally then
+ -- Expression is static and can be evaluated.
+ Res := Eval_Expr_Keep_Orig (Expr, False);
+
+ if Res /= Null_Iir
+ and then Get_Type_Staticness (Atype) = Locally
+ and then Get_Kind (Atype) in Iir_Kinds_Range_Type_Definition
+ then
+ -- Check bounds (as this can be done).
+ -- FIXME: create overflow_expr ?
+ Eval_Check_Bound (Res, Atype);
+ end if;
+
+ return Res;
+ else
+ return Expr;
+ end if;
+ end Eval_Expr_Check_If_Static;
+
+ function Eval_Int_In_Range (Val : Iir_Int64; Bound : Iir) return Boolean is
+ begin
+ case Get_Kind (Bound) is
+ when Iir_Kind_Range_Expression =>
+ case Get_Direction (Bound) is
+ when Iir_To =>
+ if Val < Eval_Pos (Get_Left_Limit (Bound))
+ or else Val > Eval_Pos (Get_Right_Limit (Bound))
+ then
+ return False;
+ end if;
+ when Iir_Downto =>
+ if Val > Eval_Pos (Get_Left_Limit (Bound))
+ or else Val < Eval_Pos (Get_Right_Limit (Bound))
+ then
+ return False;
+ end if;
+ end case;
+ when others =>
+ Error_Kind ("eval_int_in_range", Bound);
+ end case;
+ return True;
+ end Eval_Int_In_Range;
+
+ function Eval_Phys_In_Range (Val : Iir_Int64; Bound : Iir) return Boolean
+ is
+ Left, Right : Iir_Int64;
+ begin
+ case Get_Kind (Bound) is
+ when Iir_Kind_Range_Expression =>
+ case Get_Kind (Get_Type (Get_Left_Limit (Bound))) is
+ when Iir_Kind_Integer_Type_Definition
+ | Iir_Kind_Integer_Subtype_Definition =>
+ Left := Get_Value (Get_Left_Limit (Bound));
+ Right := Get_Value (Get_Right_Limit (Bound));
+ when Iir_Kind_Physical_Type_Definition
+ | Iir_Kind_Physical_Subtype_Definition =>
+ Left := Get_Physical_Value (Get_Left_Limit (Bound));
+ Right := Get_Physical_Value (Get_Right_Limit (Bound));
+ when others =>
+ Error_Kind ("eval_phys_in_range(1)", Get_Type (Bound));
+ end case;
+ case Get_Direction (Bound) is
+ when Iir_To =>
+ if Val < Left or else Val > Right then
+ return False;
+ end if;
+ when Iir_Downto =>
+ if Val > Left or else Val < Right then
+ return False;
+ end if;
+ end case;
+ when others =>
+ Error_Kind ("eval_phys_in_range", Bound);
+ end case;
+ return True;
+ end Eval_Phys_In_Range;
+
+ function Eval_Fp_In_Range (Val : Iir_Fp64; Bound : Iir) return Boolean is
+ begin
+ case Get_Kind (Bound) is
+ when Iir_Kind_Range_Expression =>
+ case Get_Direction (Bound) is
+ when Iir_To =>
+ if Val < Get_Fp_Value (Get_Left_Limit (Bound))
+ or else Val > Get_Fp_Value (Get_Right_Limit (Bound))
+ then
+ return False;
+ end if;
+ when Iir_Downto =>
+ if Val > Get_Fp_Value (Get_Left_Limit (Bound))
+ or else Val < Get_Fp_Value (Get_Right_Limit (Bound))
+ then
+ return False;
+ end if;
+ end case;
+ when others =>
+ Error_Kind ("eval_fp_in_range", Bound);
+ end case;
+ return True;
+ end Eval_Fp_In_Range;
+
+ -- Return TRUE if literal EXPR is in SUB_TYPE bounds.
+ function Eval_Is_In_Bound (Expr : Iir; Sub_Type : Iir) return Boolean
+ is
+ Type_Range : Iir;
+ Val : Iir;
+ begin
+ case Get_Kind (Expr) is
+ when Iir_Kind_Error =>
+ -- Ignore errors.
+ return True;
+ when Iir_Kind_Overflow_Literal =>
+ -- Never within bounds
+ return False;
+ when Iir_Kind_Simple_Name
+ | Iir_Kind_Character_Literal
+ | Iir_Kind_Selected_Name =>
+ Val := Get_Named_Entity (Expr);
+ when others =>
+ Val := Expr;
+ end case;
+
+ case Get_Kind (Sub_Type) is
+ when Iir_Kind_Integer_Subtype_Definition =>
+ Type_Range := Get_Range_Constraint (Sub_Type);
+ return Eval_Int_In_Range (Get_Value (Val), Type_Range);
+ when Iir_Kind_Floating_Subtype_Definition =>
+ Type_Range := Get_Range_Constraint (Sub_Type);
+ return Eval_Fp_In_Range (Get_Fp_Value (Val), Type_Range);
+ when Iir_Kind_Enumeration_Subtype_Definition
+ | Iir_Kind_Enumeration_Type_Definition =>
+ -- A check is required for an enumeration type definition for
+ -- 'val attribute.
+ Type_Range := Get_Range_Constraint (Sub_Type);
+ return Eval_Int_In_Range
+ (Iir_Int64 (Get_Enum_Pos (Val)), Type_Range);
+ when Iir_Kind_Physical_Subtype_Definition =>
+ Type_Range := Get_Range_Constraint (Sub_Type);
+ return Eval_Phys_In_Range (Get_Physical_Value (Val), Type_Range);
+
+ when Iir_Kind_Base_Attribute =>
+ return Eval_Is_In_Bound (Val, Get_Type (Sub_Type));
+
+ when Iir_Kind_Array_Subtype_Definition
+ | Iir_Kind_Array_Type_Definition
+ | Iir_Kind_Record_Type_Definition =>
+ -- FIXME: do it.
+ return True;
+
+ when others =>
+ Error_Kind ("eval_is_in_bound", Sub_Type);
+ end case;
+ end Eval_Is_In_Bound;
+
+ procedure Eval_Check_Bound (Expr : Iir; Sub_Type : Iir) is
+ begin
+ if Get_Kind (Expr) = Iir_Kind_Overflow_Literal then
+ -- Nothing to check, and a message was already generated.
+ return;
+ end if;
+
+ if not Eval_Is_In_Bound (Expr, Sub_Type) then
+ Error_Msg_Sem ("static constant violates bounds", Expr);
+ end if;
+ end Eval_Check_Bound;
+
+ function Eval_Is_Range_In_Bound
+ (A_Range : Iir; Sub_Type : Iir; Any_Dir : Boolean)
+ return Boolean
+ is
+ Type_Range : Iir;
+ Range_Constraint : constant Iir := Eval_Static_Range (A_Range);
+ begin
+ Type_Range := Get_Range_Constraint (Sub_Type);
+ if not Any_Dir
+ and then Get_Direction (Type_Range) /= Get_Direction (Range_Constraint)
+ then
+ return True;
+ end if;
+
+ case Get_Kind (Sub_Type) is
+ when Iir_Kind_Integer_Subtype_Definition
+ | Iir_Kind_Physical_Subtype_Definition
+ | Iir_Kind_Enumeration_Subtype_Definition
+ | Iir_Kind_Enumeration_Type_Definition =>
+ declare
+ L, R : Iir_Int64;
+ begin
+ -- Check for null range.
+ L := Eval_Pos (Get_Left_Limit (Range_Constraint));
+ R := Eval_Pos (Get_Right_Limit (Range_Constraint));
+ case Get_Direction (Range_Constraint) is
+ when Iir_To =>
+ if L > R then
+ return True;
+ end if;
+ when Iir_Downto =>
+ if L < R then
+ return True;
+ end if;
+ end case;
+ return Eval_Int_In_Range (L, Type_Range)
+ and then Eval_Int_In_Range (R, Type_Range);
+ end;
+ when Iir_Kind_Floating_Subtype_Definition =>
+ declare
+ L, R : Iir_Fp64;
+ begin
+ -- Check for null range.
+ L := Get_Fp_Value (Get_Left_Limit (Range_Constraint));
+ R := Get_Fp_Value (Get_Right_Limit (Range_Constraint));
+ case Get_Direction (Range_Constraint) is
+ when Iir_To =>
+ if L > R then
+ return True;
+ end if;
+ when Iir_Downto =>
+ if L < R then
+ return True;
+ end if;
+ end case;
+ return Eval_Fp_In_Range (L, Type_Range)
+ and then Eval_Fp_In_Range (R, Type_Range);
+ end;
+ when others =>
+ Error_Kind ("eval_is_range_in_bound", Sub_Type);
+ end case;
+
+ -- Should check L <= R or L >= R according to direction.
+ --return Eval_Is_In_Bound (Get_Left_Limit (A_Range), Sub_Type)
+ -- and then Eval_Is_In_Bound (Get_Right_Limit (A_Range), Sub_Type);
+ end Eval_Is_Range_In_Bound;
+
+ procedure Eval_Check_Range
+ (A_Range : Iir; Sub_Type : Iir; Any_Dir : Boolean)
+ is
+ begin
+ if not Eval_Is_Range_In_Bound (A_Range, Sub_Type, Any_Dir) then
+ Error_Msg_Sem ("static range violates bounds", A_Range);
+ end if;
+ end Eval_Check_Range;
+
+ function Eval_Discrete_Range_Length (Constraint : Iir) return Iir_Int64
+ is
+ Res : Iir_Int64;
+ Left, Right : Iir_Int64;
+ begin
+ Left := Eval_Pos (Get_Left_Limit (Constraint));
+ Right := Eval_Pos (Get_Right_Limit (Constraint));
+ case Get_Direction (Constraint) is
+ when Iir_To =>
+ if Right < Left then
+ -- Null range.
+ return 0;
+ else
+ Res := Right - Left + 1;
+ end if;
+ when Iir_Downto =>
+ if Left < Right then
+ -- Null range
+ return 0;
+ else
+ Res := Left - Right + 1;
+ end if;
+ end case;
+ return Res;
+ end Eval_Discrete_Range_Length;
+
+ function Eval_Discrete_Type_Length (Sub_Type : Iir) return Iir_Int64
+ is
+ begin
+ case Get_Kind (Sub_Type) is
+ when Iir_Kind_Enumeration_Subtype_Definition
+ | Iir_Kind_Enumeration_Type_Definition
+ | Iir_Kind_Integer_Subtype_Definition =>
+ return Eval_Discrete_Range_Length
+ (Get_Range_Constraint (Sub_Type));
+ when others =>
+ Error_Kind ("eval_discrete_type_length", Sub_Type);
+ end case;
+ end Eval_Discrete_Type_Length;
+
+ function Eval_Pos (Expr : Iir) return Iir_Int64 is
+ begin
+ case Get_Kind (Expr) is
+ when Iir_Kind_Integer_Literal =>
+ return Get_Value (Expr);
+ when Iir_Kind_Enumeration_Literal =>
+ return Iir_Int64 (Get_Enum_Pos (Expr));
+ when Iir_Kind_Physical_Int_Literal
+ | Iir_Kind_Physical_Fp_Literal
+ | Iir_Kind_Unit_Declaration =>
+ return Get_Physical_Value (Expr);
+ when Iir_Kinds_Denoting_Name =>
+ return Eval_Pos (Get_Named_Entity (Expr));
+ when others =>
+ Error_Kind ("eval_pos", Expr);
+ end case;
+ end Eval_Pos;
+
+ function Eval_Static_Range (Rng : Iir) return Iir
+ is
+ Expr : Iir;
+ Kind : Iir_Kind;
+ begin
+ Expr := Rng;
+ loop
+ Kind := Get_Kind (Expr);
+ case Kind is
+ when Iir_Kind_Range_Expression =>
+ if Get_Expr_Staticness (Expr) /= Locally then
+ return Null_Iir;
+ end if;
+
+ -- Normalize the range expression.
+ Set_Left_Limit
+ (Expr, Eval_Expr_Keep_Orig (Get_Left_Limit (Expr), True));
+ Set_Right_Limit
+ (Expr, Eval_Expr_Keep_Orig (Get_Right_Limit (Expr), True));
+ return Expr;
+ when Iir_Kind_Integer_Subtype_Definition
+ | Iir_Kind_Floating_Subtype_Definition
+ | Iir_Kind_Enumeration_Type_Definition
+ | Iir_Kind_Enumeration_Subtype_Definition
+ | Iir_Kind_Physical_Subtype_Definition =>
+ Expr := Get_Range_Constraint (Expr);
+ when Iir_Kind_Range_Array_Attribute
+ | Iir_Kind_Reverse_Range_Array_Attribute =>
+ declare
+ Prefix : Iir;
+ Res : Iir;
+ begin
+ Prefix := Get_Prefix (Expr);
+ if Get_Kind (Prefix) /= Iir_Kind_Array_Subtype_Definition
+ then
+ Prefix := Get_Type (Prefix);
+ end if;
+ if Get_Kind (Prefix) /= Iir_Kind_Array_Subtype_Definition
+ then
+ -- Unconstrained object.
+ return Null_Iir;
+ end if;
+ Expr := Get_Nth_Element
+ (Get_Index_Subtype_List (Prefix),
+ Natural (Eval_Pos (Get_Parameter (Expr))) - 1);
+ if Kind = Iir_Kind_Reverse_Range_Array_Attribute then
+ Expr := Eval_Static_Range (Expr);
+
+ Res := Create_Iir (Iir_Kind_Range_Expression);
+ Location_Copy (Res, Expr);
+ Set_Type (Res, Get_Type (Expr));
+ case Get_Direction (Expr) is
+ when Iir_To =>
+ Set_Direction (Res, Iir_Downto);
+ when Iir_Downto =>
+ Set_Direction (Res, Iir_To);
+ end case;
+ Set_Left_Limit (Res, Get_Right_Limit (Expr));
+ Set_Right_Limit (Res, Get_Left_Limit (Expr));
+ Set_Range_Origin (Res, Rng);
+ Set_Expr_Staticness (Res, Get_Expr_Staticness (Expr));
+ return Res;
+ end if;
+ end;
+
+ when Iir_Kind_Subtype_Declaration
+ | Iir_Kind_Base_Attribute =>
+ Expr := Get_Type (Expr);
+ when Iir_Kind_Type_Declaration =>
+ Expr := Get_Type_Definition (Expr);
+ when Iir_Kind_Simple_Name
+ | Iir_Kind_Selected_Name =>
+ Expr := Get_Named_Entity (Expr);
+ when others =>
+ Error_Kind ("eval_static_range", Expr);
+ end case;
+ end loop;
+ end Eval_Static_Range;
+
+ function Eval_Range (Arange : Iir) return Iir is
+ Res : Iir;
+ begin
+ Res := Eval_Static_Range (Arange);
+ if Res /= Arange
+ and then Get_Range_Origin (Res) /= Arange
+ then
+ return Build_Constant_Range (Res, Arange);
+ else
+ return Res;
+ end if;
+ end Eval_Range;
+
+ function Eval_Range_If_Static (Arange : Iir) return Iir is
+ begin
+ if Get_Expr_Staticness (Arange) /= Locally then
+ return Arange;
+ else
+ return Eval_Range (Arange);
+ end if;
+ end Eval_Range_If_Static;
+
+ -- Return the range constraint of a discrete range.
+ function Eval_Discrete_Range_Expression (Constraint : Iir) return Iir
+ is
+ Res : Iir;
+ begin
+ Res := Eval_Static_Range (Constraint);
+ if Res = Null_Iir then
+ Error_Kind ("eval_discrete_range_expression", Constraint);
+ else
+ return Res;
+ end if;
+ end Eval_Discrete_Range_Expression;
+
+ function Eval_Discrete_Range_Left (Constraint : Iir) return Iir
+ is
+ Range_Expr : Iir;
+ begin
+ Range_Expr := Eval_Discrete_Range_Expression (Constraint);
+ return Get_Left_Limit (Range_Expr);
+ end Eval_Discrete_Range_Left;
+
+ procedure Eval_Operator_Symbol_Name (Id : Name_Id)
+ is
+ begin
+ Image (Id);
+ Name_Buffer (2 .. Name_Length + 1) := Name_Buffer (1 .. Name_Length);
+ Name_Buffer (1) := '"'; --"
+ Name_Length := Name_Length + 2;
+ Name_Buffer (Name_Length) := '"'; --"
+ end Eval_Operator_Symbol_Name;
+
+ procedure Eval_Simple_Name (Id : Name_Id)
+ is
+ begin
+ -- LRM 14.1
+ -- E'SIMPLE_NAME
+ -- Result: [...] but with apostrophes (in the case of a character
+ -- literal)
+ if Is_Character (Id) then
+ Name_Buffer (1) := ''';
+ Name_Buffer (2) := Get_Character (Id);
+ Name_Buffer (3) := ''';
+ Name_Length := 3;
+ return;
+ end if;
+ case Id is
+ when Std_Names.Name_Word_Operators
+ | Std_Names.Name_First_Operator .. Std_Names.Name_Last_Operator =>
+ Eval_Operator_Symbol_Name (Id);
+ return;
+ when Std_Names.Name_Xnor
+ | Std_Names.Name_Shift_Operators =>
+ if Flags.Vhdl_Std > Vhdl_87 then
+ Eval_Operator_Symbol_Name (Id);
+ return;
+ end if;
+ when others =>
+ null;
+ end case;
+ Image (Id);
+-- if Name_Buffer (1) = '\' then
+-- declare
+-- I : Natural;
+-- begin
+-- I := 2;
+-- while I <= Name_Length loop
+-- if Name_Buffer (I) = '\' then
+-- Name_Length := Name_Length + 1;
+-- Name_Buffer (I + 1 .. Name_Length) :=
+-- Name_Buffer (I .. Name_Length - 1);
+-- I := I + 1;
+-- end if;
+-- I := I + 1;
+-- end loop;
+-- Name_Length := Name_Length + 1;
+-- Name_Buffer (Name_Length) := '\';
+-- end;
+-- end if;
+ end Eval_Simple_Name;
+
+ function Compare_String_Literals (L, R : Iir) return Compare_Type
+ is
+ type Str_Info is record
+ El : Iir;
+ Ptr : String_Fat_Acc;
+ Len : Nat32;
+ Lit_0 : Iir;
+ Lit_1 : Iir;
+ List : Iir_List;
+ end record;
+
+ Literal_List : Iir_List;
+
+ -- Fill Res from EL. This is used to speed up Lt and Eq operations.
+ procedure Get_Info (Expr : Iir; Res : out Str_Info) is
+ begin
+ case Get_Kind (Expr) is
+ when Iir_Kind_Simple_Aggregate =>
+ Res := Str_Info'(El => Expr,
+ Ptr => null,
+ Len => 0,
+ Lit_0 | Lit_1 => Null_Iir,
+ List => Get_Simple_Aggregate_List (Expr));
+ Res.Len := Nat32 (Get_Nbr_Elements (Res.List));
+ when Iir_Kind_Bit_String_Literal =>
+ Res := Str_Info'(El => Expr,
+ Ptr => Get_String_Fat_Acc (Expr),
+ Len => Get_String_Length (Expr),
+ Lit_0 => Get_Bit_String_0 (Expr),
+ Lit_1 => Get_Bit_String_1 (Expr),
+ List => Null_Iir_List);
+ when Iir_Kind_String_Literal =>
+ Res := Str_Info'(El => Expr,
+ Ptr => Get_String_Fat_Acc (Expr),
+ Len => Get_String_Length (Expr),
+ Lit_0 | Lit_1 => Null_Iir,
+ List => Null_Iir_List);
+ when others =>
+ Error_Kind ("sem_string_choice_range.get_info", Expr);
+ end case;
+ end Get_Info;
+
+ -- Return the position of element IDX of STR.
+ function Get_Pos (Str : Str_Info; Idx : Nat32) return Iir_Int32
+ is
+ S : Iir;
+ C : Character;
+ begin
+ case Get_Kind (Str.El) is
+ when Iir_Kind_Simple_Aggregate =>
+ S := Get_Nth_Element (Str.List, Natural (Idx));
+ when Iir_Kind_String_Literal =>
+ C := Str.Ptr (Idx + 1);
+ -- FIXME: build a table from character to position.
+ -- This linear search is O(n)!
+ S := Find_Name_In_List (Literal_List,
+ Name_Table.Get_Identifier (C));
+ if S = Null_Iir then
+ return -1;
+ end if;
+ when Iir_Kind_Bit_String_Literal =>
+ C := Str.Ptr (Idx + 1);
+ case C is
+ when '0' =>
+ S := Str.Lit_0;
+ when '1' =>
+ S := Str.Lit_1;
+ when others =>
+ raise Internal_Error;
+ end case;
+ when others =>
+ Error_Kind ("sem_string_choice_range.get_pos", Str.El);
+ end case;
+ return Get_Enum_Pos (S);
+ end Get_Pos;
+
+ L_Info, R_Info : Str_Info;
+ L_Pos, R_Pos : Iir_Int32;
+ begin
+ Get_Info (L, L_Info);
+ Get_Info (R, R_Info);
+
+ if L_Info.Len /= R_Info.Len then
+ raise Internal_Error;
+ end if;
+
+ Literal_List := Get_Enumeration_Literal_List
+ (Get_Base_Type (Get_Element_Subtype (Get_Type (L))));
+
+ for I in 0 .. L_Info.Len - 1 loop
+ L_Pos := Get_Pos (L_Info, I);
+ R_Pos := Get_Pos (R_Info, I);
+ if L_Pos /= R_Pos then
+ if L_Pos < R_Pos then
+ return Compare_Lt;
+ else
+ return Compare_Gt;
+ end if;
+ end if;
+ end loop;
+ return Compare_Eq;
+ end Compare_String_Literals;
+
+ function Get_Path_Instance_Name_Suffix (Attr : Iir)
+ return Path_Instance_Name_Type
+ is
+ -- Current path for name attributes.
+ Path_Str : String_Acc := null;
+ Path_Maxlen : Natural := 0;
+ Path_Len : Natural;
+ Path_Instance : Iir;
+
+ procedure Deallocate is new Ada.Unchecked_Deallocation
+ (Name => String_Acc, Object => String);
+
+ procedure Path_Reset is
+ begin
+ Path_Len := 0;
+ Path_Instance := Null_Iir;
+ if Path_Maxlen = 0 then
+ Path_Maxlen := 256;
+ Path_Str := new String (1 .. Path_Maxlen);
+ end if;
+ end Path_Reset;
+
+ procedure Path_Add (Str : String)
+ is
+ N_Len : Natural;
+ N_Path : String_Acc;
+ begin
+ N_Len := Path_Maxlen;
+ loop
+ exit when Path_Len + Str'Length <= N_Len;
+ N_Len := N_Len * 2;
+ end loop;
+ if N_Len /= Path_Maxlen then
+ N_Path := new String (1 .. N_Len);
+ N_Path (1 .. Path_Len) := Path_Str (1 .. Path_Len);
+ Deallocate (Path_Str);
+ Path_Str := N_Path;
+ Path_Maxlen := N_Len;
+ end if;
+ Path_Str (Path_Len + 1 .. Path_Len + Str'Length) := Str;
+ Path_Len := Path_Len + Str'Length;
+ end Path_Add;
+
+ procedure Path_Add_Type_Name (Atype : Iir)
+ is
+ Adecl : Iir;
+ begin
+ Adecl := Get_Type_Declarator (Atype);
+ Image (Get_Identifier (Adecl));
+ Path_Add (Name_Buffer (1 .. Name_Length));
+ end Path_Add_Type_Name;
+
+ procedure Path_Add_Signature (Subprg : Iir)
+ is
+ Chain : Iir;
+ begin
+ Path_Add ("[");
+ Chain := Get_Interface_Declaration_Chain (Subprg);
+ while Chain /= Null_Iir loop
+ Path_Add_Type_Name (Get_Type (Chain));
+ Chain := Get_Chain (Chain);
+ if Chain /= Null_Iir then
+ Path_Add (",");
+ end if;
+ end loop;
+
+ case Get_Kind (Subprg) is
+ when Iir_Kind_Function_Declaration
+ | Iir_Kind_Implicit_Function_Declaration =>
+ Path_Add (" return ");
+ Path_Add_Type_Name (Get_Return_Type (Subprg));
+ when others =>
+ null;
+ end case;
+ Path_Add ("]");
+ end Path_Add_Signature;
+
+ procedure Path_Add_Name (N : Iir) is
+ begin
+ Eval_Simple_Name (Get_Identifier (N));
+ if Name_Buffer (1) /= 'P' then
+ -- Skip anonymous processes.
+ Path_Add (Name_Buffer (1 .. Name_Length));
+ end if;
+ end Path_Add_Name;
+
+ procedure Path_Add_Element (El : Iir; Is_Instance : Boolean) is
+ begin
+ -- LRM 14.1
+ -- E'INSTANCE_NAME
+ -- There is one full path instance element for each component
+ -- instantiation, block statement, generate statemenent, process
+ -- statement, or subprogram body in the design hierarchy between
+ -- the top design entity and the named entity denoted by the
+ -- prefix.
+ --
+ -- E'PATH_NAME
+ -- There is one path instance element for each component
+ -- instantiation, block statement, generate statement, process
+ -- statement, or subprogram body in the design hierarchy between
+ -- the root design entity and the named entity denoted by the
+ -- prefix.
+ case Get_Kind (El) is
+ when Iir_Kind_Library_Declaration =>
+ Path_Add (":");
+ Path_Add_Name (El);
+ Path_Add (":");
+ when Iir_Kind_Package_Declaration
+ | Iir_Kind_Package_Body =>
+ Path_Add_Element
+ (Get_Library (Get_Design_File (Get_Design_Unit (El))),
+ Is_Instance);
+ Path_Add_Name (El);
+ Path_Add (":");
+ when Iir_Kind_Entity_Declaration =>
+ Path_Instance := El;
+ when Iir_Kind_Architecture_Body =>
+ Path_Instance := El;
+ when Iir_Kind_Design_Unit =>
+ Path_Add_Element (Get_Library_Unit (El), Is_Instance);
+ when Iir_Kind_Sensitized_Process_Statement
+ | Iir_Kind_Process_Statement
+ | Iir_Kind_Block_Statement =>
+ Path_Add_Element (Get_Parent (El), Is_Instance);
+ Path_Add_Name (El);
+ Path_Add (":");
+ when Iir_Kind_Function_Declaration
+ | Iir_Kind_Procedure_Declaration
+ | Iir_Kind_Implicit_Function_Declaration
+ | Iir_Kind_Implicit_Procedure_Declaration =>
+ Path_Add_Element (Get_Parent (El), Is_Instance);
+ Path_Add_Name (El);
+ if Flags.Vhdl_Std >= Vhdl_02 then
+ -- Add signature.
+ Path_Add_Signature (El);
+ end if;
+ Path_Add (":");
+ when Iir_Kind_Procedure_Body =>
+ Path_Add_Element (Get_Subprogram_Specification (El),
+ Is_Instance);
+ when Iir_Kind_Generate_Statement =>
+ declare
+ Scheme : Iir;
+ begin
+ Scheme := Get_Generation_Scheme (El);
+ if Get_Kind (Scheme) = Iir_Kind_Iterator_Declaration then
+ Path_Instance := El;
+ else
+ Path_Add_Element (Get_Parent (El), Is_Instance);
+ Path_Add_Name (El);
+ Path_Add (":");
+ end if;
+ end;
+ when Iir_Kinds_Sequential_Statement =>
+ Path_Add_Element (Get_Parent (El), Is_Instance);
+ when others =>
+ Error_Kind ("path_add_element", El);
+ end case;
+ end Path_Add_Element;
+
+ Prefix : constant Iir := Get_Named_Entity (Get_Prefix (Attr));
+ Is_Instance : constant Boolean :=
+ Get_Kind (Attr) = Iir_Kind_Instance_Name_Attribute;
+ begin
+ Path_Reset;
+
+ -- LRM 14.1
+ -- E'PATH_NAME
+ -- The local item name in E'PATH_NAME equals E'SIMPLE_NAME, unless
+ -- E denotes a library, package, subprogram or label. In this
+ -- latter case, the package based path or instance based path,
+ -- as appropriate, will not contain a local item name.
+ --
+ -- E'INSTANCE_NAME
+ -- The local item name in E'INSTANCE_NAME equals E'SIMPLE_NAME,
+ -- unless E denotes a library, package, subprogram, or label. In
+ -- this latter case, the package based path or full instance based
+ -- path, as appropriate, will not contain a local item name.
+ case Get_Kind (Prefix) is
+ when Iir_Kind_Constant_Declaration
+ | Iir_Kind_Interface_Constant_Declaration
+ | Iir_Kind_Iterator_Declaration
+ | Iir_Kind_Variable_Declaration
+ | Iir_Kind_Interface_Variable_Declaration
+ | Iir_Kind_Signal_Declaration
+ | Iir_Kind_Interface_Signal_Declaration
+ | Iir_Kind_File_Declaration
+ | Iir_Kind_Interface_File_Declaration
+ | Iir_Kind_Type_Declaration
+ | Iir_Kind_Subtype_Declaration =>
+ Path_Add_Element (Get_Parent (Prefix), Is_Instance);
+ Path_Add_Name (Prefix);
+ when Iir_Kind_Library_Declaration
+ | Iir_Kinds_Library_Unit_Declaration
+ | Iir_Kind_Function_Declaration
+ | Iir_Kind_Procedure_Declaration
+ | Iir_Kind_Implicit_Function_Declaration
+ | Iir_Kind_Implicit_Procedure_Declaration
+ | Iir_Kinds_Concurrent_Statement
+ | Iir_Kinds_Sequential_Statement =>
+ Path_Add_Element (Prefix, Is_Instance);
+ when others =>
+ Error_Kind ("get_path_instance_name_suffix", Prefix);
+ end case;
+
+ declare
+ Result : constant Path_Instance_Name_Type :=
+ (Len => Path_Len,
+ Path_Instance => Path_Instance,
+ Suffix => Path_Str (1 .. Path_Len));
+ begin
+ Deallocate (Path_Str);
+ return Result;
+ end;
+ end Get_Path_Instance_Name_Suffix;
+
+end Evaluation;