From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1914) id A484A38A83D7; Tue, 12 Jul 2022 12:27:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A484A38A83D7 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Pierre-Marie de Rodat To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-1643] [Ada] Use right implementation type for nonbinary-modulus ops X-Act-Checkin: gcc X-Git-Author: Steve Baird X-Git-Refname: refs/heads/master X-Git-Oldrev: 729d2e2a80768b6df008ea98979dbe34b7e4ab9a X-Git-Newrev: 33338e7289288404de79cb57dd1003a7552fb3d4 Message-Id: <20220712122708.A484A38A83D7@sourceware.org> Date: Tue, 12 Jul 2022 12:27:08 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jul 2022 12:27:08 -0000 https://gcc.gnu.org/g:33338e7289288404de79cb57dd1003a7552fb3d4 commit r13-1643-g33338e7289288404de79cb57dd1003a7552fb3d4 Author: Steve Baird Date: Wed Jun 29 17:21:03 2022 -0700 [Ada] Use right implementation type for nonbinary-modulus ops If the flag Opt.Expand_Nonbinary_Modular_Ops is set (which occurs if -gnateg is specified) then we implement predefined operations for a modular type whose modulus is not a power of two by converting the operands to some other type (either a signed integer type or a modular type with a power-of-two modulus), doing the operation in that representation, and converting back. If the bounds of the chosen type are too narrow, then problems with intermediate overflow can result. But there are performance advantages to choosing narrower bounds (and to prefering an unsigned choice over a signed choice of the same size) when multiple safe choices are available. gcc/ada/ * exp_ch4.adb (Expand_Nonbinary_Modular_Op.Expand_Modular_Op): Reimplement choice of which predefined type to use for the implementation of a predefined operation of a modular type with a non-power-of-two modulus. Diff: --- gcc/ada/exp_ch4.adb | 101 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 31 deletions(-) diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index 288ce9a9958..911bdf31b78 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -4177,43 +4177,82 @@ package body Exp_Ch4 is ----------------------- procedure Expand_Modular_Op is + -- We will convert to another type (not a nonbinary-modulus modular + -- type), evaluate the op in that representation, reduce the result, + -- and convert back to the original type. This means that the + -- backend does not have to deal with nonbinary-modulus ops. + Op_Expr : constant Node_Id := New_Op_Node (Nkind (N), Loc); Mod_Expr : constant Node_Id := New_Op_Node (N_Op_Mod, Loc); - Target_Type : Entity_Id; - + Target_Type : Entity_Id; begin - -- Convert nonbinary modular type operands into integer values. Thus - -- we avoid never-ending loops expanding them, and we also ensure - -- the back end never receives nonbinary modular type expressions. - - if Nkind (N) in N_Op_And | N_Op_Or | N_Op_Xor then - Set_Left_Opnd (Op_Expr, - Unchecked_Convert_To (Standard_Unsigned, - New_Copy_Tree (Left_Opnd (N)))); - Set_Right_Opnd (Op_Expr, - Unchecked_Convert_To (Standard_Unsigned, - New_Copy_Tree (Right_Opnd (N)))); - Set_Left_Opnd (Mod_Expr, - Unchecked_Convert_To (Standard_Integer, Op_Expr)); - - else - -- If the modulus of the type is larger than Integer'Last use a - -- larger type for the operands, to prevent spurious constraint - -- errors on large legal literals of the type. + -- Select a target type that is large enough to avoid spurious + -- intermediate overflow on pre-reduction computation (for + -- correctness) but is no larger than is needed (for performance). - if Modulus (Etype (N)) > Int (Integer'Last) then - Target_Type := Standard_Long_Long_Integer; + declare + Required_Size : Uint := RM_Size (Etype (N)); + Use_Unsigned : Boolean := True; + begin + case Nkind (N) is + when N_Op_Add => + -- For example, if modulus is 255 then RM_Size will be 8 + -- and the range of possible values (before reduction) will + -- be 0 .. 508; that range requires 9 bits. + Required_Size := Required_Size + 1; + + when N_Op_Subtract => + -- For example, if modulus is 255 then RM_Size will be 8 + -- and the range of possible values (before reduction) will + -- be -254 .. 254; that range requires 9 bits, signed. + Use_Unsigned := False; + Required_Size := Required_Size + 1; + + when N_Op_Multiply => + -- For example, if modulus is 255 then RM_Size will be 8 + -- and the range of possible values (before reduction) will + -- be 0 .. 64,516; that range requires 16 bits. + Required_Size := Required_Size * 2; + + when others => + null; + end case; + + if Use_Unsigned then + if Required_Size <= Standard_Short_Short_Integer_Size then + Target_Type := Standard_Short_Short_Unsigned; + elsif Required_Size <= Standard_Short_Integer_Size then + Target_Type := Standard_Short_Unsigned; + elsif Required_Size <= Standard_Integer_Size then + Target_Type := Standard_Unsigned; + else + pragma Assert (Required_Size <= 64); + Target_Type := Standard_Unsigned_64; + end if; + elsif Required_Size <= 8 then + Target_Type := Standard_Integer_8; + elsif Required_Size <= 16 then + Target_Type := Standard_Integer_16; + elsif Required_Size <= 32 then + Target_Type := Standard_Integer_32; else - Target_Type := Standard_Integer; + pragma Assert (Required_Size <= 64); + Target_Type := Standard_Integer_64; end if; - Set_Left_Opnd (Op_Expr, - Unchecked_Convert_To (Target_Type, - New_Copy_Tree (Left_Opnd (N)))); - Set_Right_Opnd (Op_Expr, - Unchecked_Convert_To (Target_Type, - New_Copy_Tree (Right_Opnd (N)))); + pragma Assert (Present (Target_Type)); + end; + + Set_Left_Opnd (Op_Expr, + Unchecked_Convert_To (Target_Type, + New_Copy_Tree (Left_Opnd (N)))); + Set_Right_Opnd (Op_Expr, + Unchecked_Convert_To (Target_Type, + New_Copy_Tree (Right_Opnd (N)))); + + -- ??? Why do this stuff for some ops and not others? + if Nkind (N) not in N_Op_And | N_Op_Or | N_Op_Xor then -- Link this node to the tree to analyze it @@ -4237,10 +4276,10 @@ package body Exp_Ch4 is -- several times. Force_Evaluation (Op_Expr, Mode => Strict); - - Set_Left_Opnd (Mod_Expr, Op_Expr); end if; + Set_Left_Opnd (Mod_Expr, Op_Expr); + Set_Right_Opnd (Mod_Expr, Make_Integer_Literal (Loc, Modulus (Typ)));