public inbox for gcc-cvs@sourceware.org help / color / mirror / Atom feed
From: Pierre-Marie de Rodat <pmderodat@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-1643] [Ada] Use right implementation type for nonbinary-modulus ops Date: Tue, 12 Jul 2022 12:27:08 +0000 (GMT) [thread overview] Message-ID: <20220712122708.A484A38A83D7@sourceware.org> (raw) https://gcc.gnu.org/g:33338e7289288404de79cb57dd1003a7552fb3d4 commit r13-1643-g33338e7289288404de79cb57dd1003a7552fb3d4 Author: Steve Baird <baird@adacore.com> 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)));
reply other threads:[~2022-07-12 12:27 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220712122708.A484A38A83D7@sourceware.org \ --to=pmderodat@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).