From: Bob Duff <d...@adacore.com> The compiler usually turns 2**N into Shift_Left(1,N). This patch removes the check for "shift amount too big" in the modular case, because Shift_Left works properly in that case (i.e. if N is very large, it returns 0).
This removes a redundant check on most hardware; Shift_Left takes care of large shirt amounts as necessary, even though most hardware does not. gcc/ada/ * exp_ch4.adb (Expand_N_Op_Expon): Remove the too-big check. Simplify. Signed and modular cases are combined, etc. Remove code with comment "We only handle cases where the right type is a[sic] integer", because the right operand must always be an integer at this point. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/exp_ch4.adb | 131 +++++++++----------------------------------- 1 file changed, 26 insertions(+), 105 deletions(-) diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index 31823eaeca7..c1fe02d60c1 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -9048,7 +9048,7 @@ package body Exp_Ch4 is end if; end if; - -- Deal with optimizing 2 ** expression to shift where possible + -- Optimize 2 ** expression to shift where possible -- Note: we used to check that Exptyp was an unsigned type. But that is -- an unnecessary check, since if Exp is negative, we have a run-time @@ -9063,14 +9063,8 @@ package body Exp_Ch4 is and then CRT_Safe_Compile_Time_Known_Value (Base) and then Expr_Value (Base) = Uint_2 - -- We only handle cases where the right type is a integer - - and then Is_Integer_Type (Root_Type (Exptyp)) - and then Esize (Root_Type (Exptyp)) <= Standard_Integer_Size - -- This transformation is not applicable for a modular type with a - -- nonbinary modulus because we do not handle modular reduction in - -- a correct manner if we attempt this transformation in this case. + -- nonbinary modulus because shifting makes no sense in that case. and then not Non_Binary_Modulus (Typ) then @@ -9107,61 +9101,26 @@ package body Exp_Ch4 is end if; end; - -- Here we just have 2 ** N on its own, so we can convert this to a - -- shift node. We are prepared to deal with overflow here, and we - -- also have to handle proper modular reduction for binary modular. + -- Here we have 2 ** N on its own, so we can convert this into a + -- shift. else - declare - OK : Boolean; - Lo : Uint; - Hi : Uint; - - MaxS : Uint; - -- Maximum shift count with no overflow - - TestS : Boolean; - -- Set True if we must test the shift count - - Test_Gt : Node_Id; - -- Node for test against TestS - - begin - -- Compute maximum shift based on the underlying size. For a - -- modular type this is one less than the size. - - if Is_Modular_Integer_Type (Typ) then - - -- For modular integer types, this is the size of the value - -- being shifted minus one. Any larger values will cause - -- modular reduction to a result of zero. Note that we do - -- want the RM_Size here (e.g. mod 2 ** 7, we want a result - -- of 6, since 2**7 should be reduced to zero). - - MaxS := RM_Size (Rtyp) - 1; - - -- For signed integer types, we use the size of the value - -- being shifted minus 2. Larger values cause overflow. + -- Op_Shift_Left (generated below) has modular-shift semantics; + -- therefore we might need to generate an overflow check here + -- if the type is signed. - else - MaxS := Esize (Rtyp) - 2; - end if; - - -- Determine range to see if it can be larger than MaxS - - Determine_Range (Exp, OK, Lo, Hi, Assume_Valid => True); - TestS := (not OK) or else Hi > MaxS; - - -- Signed integer case - - if Is_Signed_Integer_Type (Typ) then + if Is_Signed_Integer_Type (Typ) and then Ovflo then + declare + OK : Boolean; + Lo : Uint; + Hi : Uint; - -- Generate overflow check if overflow is active. Note that - -- we can simply ignore the possibility of overflow if the - -- flag is not set (means that overflow cannot happen or - -- that overflow checks are suppressed). + MaxS : constant Uint := Esize (Rtyp) - 2; + -- Maximum shift count with no overflow + begin + Determine_Range (Exp, OK, Lo, Hi, Assume_Valid => True); - if Ovflo and TestS then + if (not OK) or else Hi > MaxS then Insert_Action (N, Make_Raise_Constraint_Error (Loc, Condition => @@ -9170,56 +9129,18 @@ package body Exp_Ch4 is Right_Opnd => Make_Integer_Literal (Loc, MaxS)), Reason => CE_Overflow_Check_Failed)); end if; + end; + end if; - -- Now rewrite node as Shift_Left (1, right-operand) - - Rewrite (N, - Make_Op_Shift_Left (Loc, - Left_Opnd => Make_Integer_Literal (Loc, Uint_1), - Right_Opnd => Exp)); - - -- Modular integer case - - else pragma Assert (Is_Modular_Integer_Type (Typ)); - - -- If shift count can be greater than MaxS, we need to wrap - -- the shift in a test that will reduce the result value to - -- zero if this shift count is exceeded. - - if TestS then - - -- Note: build node for the comparison first, before we - -- reuse the Right_Opnd, so that we have proper parents - -- in place for the Duplicate_Subexpr call. - - Test_Gt := - Make_Op_Gt (Loc, - Left_Opnd => Duplicate_Subexpr (Exp), - Right_Opnd => Make_Integer_Literal (Loc, MaxS)); - - Rewrite (N, - Make_If_Expression (Loc, - Expressions => New_List ( - Test_Gt, - Make_Integer_Literal (Loc, Uint_0), - Make_Op_Shift_Left (Loc, - Left_Opnd => Make_Integer_Literal (Loc, Uint_1), - Right_Opnd => Exp)))); - - -- If we know shift count cannot be greater than MaxS, then - -- it is safe to just rewrite as a shift with no test. + -- Generate Shift_Left (1, Exp) - else - Rewrite (N, - Make_Op_Shift_Left (Loc, - Left_Opnd => Make_Integer_Literal (Loc, Uint_1), - Right_Opnd => Exp)); - end if; - end if; + Rewrite (N, + Make_Op_Shift_Left (Loc, + Left_Opnd => Make_Integer_Literal (Loc, Uint_1), + Right_Opnd => Exp)); - Analyze_And_Resolve (N, Typ); - return; - end; + Analyze_And_Resolve (N, Typ); + return; end if; end if; -- 2.40.0