diff mbox series

[fortran] PR90903 - Implement runtime checks for bit manipulation intrinsics

Message ID 5D0FF0E8.3090108@gmx.de
State New
Headers show
Series [fortran] PR90903 - Implement runtime checks for bit manipulation intrinsics | expand

Commit Message

Harald Anlauf June 23, 2019, 9:36 p.m. UTC
Dear all,

the attached patch provides run-time checks for the bit manipulation
intrinsic functions (IBSET/IBCLR/BTEST/SHIFT[RLA]/ISHFT/ISHFTC).
I am using only one testcase whose purpose is mainly to verify that
there are no false positives, which I consider essential, and one
"failing" test at the end.

What is still missing are run-time checks for the subroutine MVBITS.
I am not sure yet how to handle that case (frontend or library?),
and I am open to suggestions.  For this purpose I intend to leave
the PR open until a good solution is found.

Regtested on x86_64-pc-linux-gnu.  OK for trunk?

Harald

2019-06-23  Harald Anlauf  <anlauf@gmx.de>

	PR fortran/90903
	* libgfortran.h: Add mask for -fcheck=bits option.
	* options.c (gfc_handle_runtime_check_option): Add option "bits"
	to run-time checks selectable via -fcheck.
	* trans-intrinsic.c (gfc_conv_intrinsic_btest)
	(gfc_conv_intrinsic_singlebitop, gfc_conv_intrinsic_ibits)
	(gfc_conv_intrinsic_shift, gfc_conv_intrinsic_ishft)
	(gfc_conv_intrinsic_ishftc): Implement run-time checks for the
	POS, LEN, SHIFT, and SIZE arguments.
	* gfortran.texi: Document run-time checks for bit manipulation
	intrinsics.
	* invoke.texi: Document new -fcheck=bits option.

2019-06-23  Harald Anlauf  <anlauf@gmx.de>

	PR fortran/90903
	* gfortran.dg/check_bits_1.f90: New testcase.

Index: gcc/testsuite/gfortran.dg/check_bits_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/check_bits_1.f90	(nonexistent)
+++ gcc/testsuite/gfortran.dg/check_bits_1.f90	(working copy)
@@ -0,0 +1,49 @@
+! { dg-do run }
+! { dg-options "-fcheck=bits -fdump-tree-original" }
+! { dg-shouldfail "Fortran runtime error: SIZE argument (0) out of range 1:32 in intrinsic ISHFTC" }
+! { dg-output "At line 44 .*" }
+!
+! Verify that the runtime checks for the bit manipulation intrinsic functions
+! do not generate false-positives
+program check
+  implicit none
+  integer :: i, k, pos, len, shift, size, nb
+  nb = bit_size (i)
+  i = 0
+  do pos = 0, nb-1
+     k = ibset (i, pos)
+     i = ibclr (k, pos)
+     if (btest (i, pos)) stop 1
+  end do
+  do pos = 0, nb
+     do len = 0, nb-pos
+        i = ibits (i, pos, len)
+     end do
+  end do
+  do shift = 0, nb
+     k = ishft (i,  shift)
+     i = ishft (k, -shift)
+  end do
+  do shift = 0, nb
+     k = shiftl (i, shift) ! Fortran 2008
+     i = shiftr (k, shift)
+     i = shifta (i, shift)
+     k = lshift (i, shift) ! GNU extensions
+     i = rshift (k, shift)
+  end do
+  do shift = 0, nb
+     k = ishftc (i,  shift)
+     i = ishftc (k, -shift)
+     do size = max (1,shift), nb
+        k = ishftc (i,  shift, size)
+        i = ishftc (k, -shift, size)
+     end do
+  end do
+  size = 0
+  ! The following line should fail with a runtime error:
+  k = ishftc (i, 0, size)
+  ! Should never get here with -fcheck=bits
+  stop 2
+end program check
+
+! { dg-final { scan-tree-dump-times "_gfortran_runtime_error_at" 21 "original" } }

Comments

Harald Anlauf July 14, 2019, 7:37 p.m. UTC | #1
Ping!

On 06/23/19 23:36, Harald Anlauf wrote:
> Dear all,
>
> the attached patch provides run-time checks for the bit manipulation
> intrinsic functions (IBSET/IBCLR/BTEST/SHIFT[RLA]/ISHFT/ISHFTC).
> I am using only one testcase whose purpose is mainly to verify that
> there are no false positives, which I consider essential, and one
> "failing" test at the end.
>
> What is still missing are run-time checks for the subroutine MVBITS.
> I am not sure yet how to handle that case (frontend or library?),
> and I am open to suggestions.  For this purpose I intend to leave
> the PR open until a good solution is found.
>
> Regtested on x86_64-pc-linux-gnu.  OK for trunk?
>
> Harald
>
> 2019-06-23  Harald Anlauf  <anlauf@gmx.de>
>
> 	PR fortran/90903
> 	* libgfortran.h: Add mask for -fcheck=bits option.
> 	* options.c (gfc_handle_runtime_check_option): Add option "bits"
> 	to run-time checks selectable via -fcheck.
> 	* trans-intrinsic.c (gfc_conv_intrinsic_btest)
> 	(gfc_conv_intrinsic_singlebitop, gfc_conv_intrinsic_ibits)
> 	(gfc_conv_intrinsic_shift, gfc_conv_intrinsic_ishft)
> 	(gfc_conv_intrinsic_ishftc): Implement run-time checks for the
> 	POS, LEN, SHIFT, and SIZE arguments.
> 	* gfortran.texi: Document run-time checks for bit manipulation
> 	intrinsics.
> 	* invoke.texi: Document new -fcheck=bits option.
>
> 2019-06-23  Harald Anlauf  <anlauf@gmx.de>
>
> 	PR fortran/90903
> 	* gfortran.dg/check_bits_1.f90: New testcase.
>
Steve Kargl July 15, 2019, 2:33 a.m. UTC | #2
Harald, thanks for the patch.  I'm that the best person
for reading the trans-* file, but your patch and changes
look good to me.  If no one else speaks up, in the next
day or so, please commit.
Paul Richard Thomas July 16, 2019, 5:40 a.m. UTC | #3
Hi Harald and Steve,

The patch looks fine to me - it's good be committed.

Thanks

Paul

On Mon, 15 Jul 2019 at 03:34, Steve Kargl
<sgk@troutmask.apl.washington.edu> wrote:
>
> Harald, thanks for the patch.  I'm that the best person
> for reading the trans-* file, but your patch and changes
> look good to me.  If no one else speaks up, in the next
> day or so, please commit.
>
> --
> steve
>
> On Sun, Jul 14, 2019 at 09:37:27PM +0200, Harald Anlauf wrote:
> > Ping!
> >
> > On 06/23/19 23:36, Harald Anlauf wrote:
> > > Dear all,
> > >
> > > the attached patch provides run-time checks for the bit manipulation
> > > intrinsic functions (IBSET/IBCLR/BTEST/SHIFT[RLA]/ISHFT/ISHFTC).
> > > I am using only one testcase whose purpose is mainly to verify that
> > > there are no false positives, which I consider essential, and one
> > > "failing" test at the end.
> > >
> > > What is still missing are run-time checks for the subroutine MVBITS.
> > > I am not sure yet how to handle that case (frontend or library?),
> > > and I am open to suggestions.  For this purpose I intend to leave
> > > the PR open until a good solution is found.
> > >
> > > Regtested on x86_64-pc-linux-gnu.  OK for trunk?
> > >
> > > Harald
> > >
> > > 2019-06-23  Harald Anlauf  <anlauf@gmx.de>
> > >
> > >     PR fortran/90903
> > >     * libgfortran.h: Add mask for -fcheck=bits option.
> > >     * options.c (gfc_handle_runtime_check_option): Add option "bits"
> > >     to run-time checks selectable via -fcheck.
> > >     * trans-intrinsic.c (gfc_conv_intrinsic_btest)
> > >     (gfc_conv_intrinsic_singlebitop, gfc_conv_intrinsic_ibits)
> > >     (gfc_conv_intrinsic_shift, gfc_conv_intrinsic_ishft)
> > >     (gfc_conv_intrinsic_ishftc): Implement run-time checks for the
> > >     POS, LEN, SHIFT, and SIZE arguments.
> > >     * gfortran.texi: Document run-time checks for bit manipulation
> > >     intrinsics.
> > >     * invoke.texi: Document new -fcheck=bits option.
> > >
> > > 2019-06-23  Harald Anlauf  <anlauf@gmx.de>
> > >
> > >     PR fortran/90903
> > >     * gfortran.dg/check_bits_1.f90: New testcase.
> > >
> >
>
> --
> Steve
> 20170425 https://www.youtube.com/watch?v=VWUpyCsUKR4
> 20161221 https://www.youtube.com/watch?v=IbCHE-hONow
Harald Anlauf July 16, 2019, 8 p.m. UTC | #4
Committed with svn revision 273535.

Steve, Paul, thanks for the review!

Harald

On 07/16/19 07:40, Paul Richard Thomas wrote:
> Hi Harald and Steve,
>
> The patch looks fine to me - it's good be committed.
>
> Thanks
>
> Paul
>
> On Mon, 15 Jul 2019 at 03:34, Steve Kargl
> <sgk@troutmask.apl.washington.edu> wrote:
>>
>> Harald, thanks for the patch.  I'm that the best person
>> for reading the trans-* file, but your patch and changes
>> look good to me.  If no one else speaks up, in the next
>> day or so, please commit.
>>
>> --
>> steve
>>
>> On Sun, Jul 14, 2019 at 09:37:27PM +0200, Harald Anlauf wrote:
>>> Ping!
>>>
>>> On 06/23/19 23:36, Harald Anlauf wrote:
>>>> Dear all,
>>>>
>>>> the attached patch provides run-time checks for the bit manipulation
>>>> intrinsic functions (IBSET/IBCLR/BTEST/SHIFT[RLA]/ISHFT/ISHFTC).
>>>> I am using only one testcase whose purpose is mainly to verify that
>>>> there are no false positives, which I consider essential, and one
>>>> "failing" test at the end.
>>>>
>>>> What is still missing are run-time checks for the subroutine MVBITS.
>>>> I am not sure yet how to handle that case (frontend or library?),
>>>> and I am open to suggestions.  For this purpose I intend to leave
>>>> the PR open until a good solution is found.
>>>>
>>>> Regtested on x86_64-pc-linux-gnu.  OK for trunk?
>>>>
>>>> Harald
>>>>
>>>> 2019-06-23  Harald Anlauf  <anlauf@gmx.de>
>>>>
>>>>     PR fortran/90903
>>>>     * libgfortran.h: Add mask for -fcheck=bits option.
>>>>     * options.c (gfc_handle_runtime_check_option): Add option "bits"
>>>>     to run-time checks selectable via -fcheck.
>>>>     * trans-intrinsic.c (gfc_conv_intrinsic_btest)
>>>>     (gfc_conv_intrinsic_singlebitop, gfc_conv_intrinsic_ibits)
>>>>     (gfc_conv_intrinsic_shift, gfc_conv_intrinsic_ishft)
>>>>     (gfc_conv_intrinsic_ishftc): Implement run-time checks for the
>>>>     POS, LEN, SHIFT, and SIZE arguments.
>>>>     * gfortran.texi: Document run-time checks for bit manipulation
>>>>     intrinsics.
>>>>     * invoke.texi: Document new -fcheck=bits option.
>>>>
>>>> 2019-06-23  Harald Anlauf  <anlauf@gmx.de>
>>>>
>>>>     PR fortran/90903
>>>>     * gfortran.dg/check_bits_1.f90: New testcase.
>>>>
>>>
>>
>> --
>> Steve
>> 20170425 https://www.youtube.com/watch?v=VWUpyCsUKR4
>> 20161221 https://www.youtube.com/watch?v=IbCHE-hONow
>
>
>
diff mbox series

Patch

Index: gcc/fortran/gfortran.texi
===================================================================
--- gcc/fortran/gfortran.texi	(revision 272560)
+++ gcc/fortran/gfortran.texi	(working copy)
@@ -3790,7 +3790,8 @@ 
 Default: enabled.
 @item @var{option}[6] @tab Enables run-time checking.  Possible values
 are (bitwise or-ed): GFC_RTCHECK_BOUNDS (1), GFC_RTCHECK_ARRAY_TEMPS (2),
-GFC_RTCHECK_RECURSION (4), GFC_RTCHECK_DO (16), GFC_RTCHECK_POINTER (32).
+GFC_RTCHECK_RECURSION (4), GFC_RTCHECK_DO (16), GFC_RTCHECK_POINTER (32),
+GFC_RTCHECK_BITS (64).
 Default: disabled.
 @item @var{option}[7] @tab Unused.
 @item @var{option}[8] @tab Show a warning when invoking @code{STOP} and
Index: gcc/fortran/invoke.texi
===================================================================
--- gcc/fortran/invoke.texi	(revision 272560)
+++ gcc/fortran/invoke.texi	(working copy)
@@ -183,7 +183,7 @@ 
 @gccoptlist{-faggressive-function-elimination -fblas-matmul-limit=@var{n} @gol
 -fbounds-check -ftail-call-workaround -ftail-call-workaround=@var{n} @gol
 -fcheck-array-temporaries @gol
--fcheck=@var{<all|array-temps|bounds|do|mem|pointer|recursion>} @gol
+-fcheck=@var{<all|array-temps|bits|bounds|do|mem|pointer|recursion>} @gol
 -fcoarray=@var{<none|single|lib>} -fexternal-blas -ff2c
 -ffrontend-loop-interchange @gol
 -ffrontend-optimize @gol
@@ -1558,6 +1558,7 @@ 
 @item -fcheck=@var{<keyword>}
 @opindex @code{fcheck}
 @cindex array, bounds checking
+@cindex bit intrinsics checking
 @cindex bounds checking
 @cindex pointer checking
 @cindex memory checking
@@ -1582,6 +1583,10 @@ 

 Note: The warning is only printed once per location.

+@item @samp{bits}
+Enable generation of run-time checks for invalid arguments to the bit
+manipulation intrinsics.
+
 @item @samp{bounds}
 Enable generation of run-time checks for array subscripts
 and against the declared minimum and maximum values.  It also
Index: gcc/fortran/libgfortran.h
===================================================================
--- gcc/fortran/libgfortran.h	(revision 272560)
+++ gcc/fortran/libgfortran.h	(working copy)
@@ -73,9 +73,11 @@ 
 #define GFC_RTCHECK_DO          (1<<3)
 #define GFC_RTCHECK_POINTER     (1<<4)
 #define GFC_RTCHECK_MEM         (1<<5)
+#define GFC_RTCHECK_BITS        (1<<6)
 #define GFC_RTCHECK_ALL        (GFC_RTCHECK_BOUNDS | GFC_RTCHECK_ARRAY_TEMPS \
 				| GFC_RTCHECK_RECURSION | GFC_RTCHECK_DO \
-				| GFC_RTCHECK_POINTER | GFC_RTCHECK_MEM)
+				| GFC_RTCHECK_POINTER | GFC_RTCHECK_MEM \
+				| GFC_RTCHECK_BITS)

 /* Special unit numbers used to convey certain conditions.  Numbers -4
    thru -9 available.  NEWUNIT values start at -10.  */
Index: gcc/fortran/options.c
===================================================================
--- gcc/fortran/options.c	(revision 272560)
+++ gcc/fortran/options.c	(working copy)
@@ -580,12 +580,12 @@ 
   int result, pos = 0, n;
   static const char * const optname[] = { "all", "bounds", "array-temps",
 					  "recursion", "do", "pointer",
-					  "mem", NULL };
+					  "mem", "bits", NULL };
   static const int optmask[] = { GFC_RTCHECK_ALL, GFC_RTCHECK_BOUNDS,
 				 GFC_RTCHECK_ARRAY_TEMPS,
 				 GFC_RTCHECK_RECURSION, GFC_RTCHECK_DO,
 				 GFC_RTCHECK_POINTER, GFC_RTCHECK_MEM,
-				 0 };
+				 GFC_RTCHECK_BITS, 0 };

   while (*arg)
     {
Index: gcc/fortran/trans-intrinsic.c
===================================================================
--- gcc/fortran/trans-intrinsic.c	(revision 272560)
+++ gcc/fortran/trans-intrinsic.c	(working copy)
@@ -6166,6 +6166,24 @@ 
   gfc_conv_intrinsic_function_args (se, expr, args, 2);
   type = TREE_TYPE (args[0]);

+  /* Optionally generate code for runtime argument check.  */
+  if (gfc_option.rtcheck & GFC_RTCHECK_BITS)
+    {
+      tree below = fold_build2_loc (input_location, LT_EXPR,
+				    logical_type_node, args[1],
+				    build_int_cst (TREE_TYPE (args[1]), 0));
+      tree nbits = build_int_cst (TREE_TYPE (args[1]), TYPE_PRECISION (type));
+      tree above = fold_build2_loc (input_location, GE_EXPR,
+				    logical_type_node, args[1], nbits);
+      tree scond = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+				    logical_type_node, below, above);
+      gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+			       "POS argument (%ld) out of range 0:%ld "
+			       "in intrinsic BTEST",
+			       fold_convert (long_integer_type_node, args[1]),
+			       fold_convert (long_integer_type_node, nbits));
+    }
+
   tmp = fold_build2_loc (input_location, LSHIFT_EXPR, type,
 			 build_int_cst (type, 1), args[1]);
   tmp = fold_build2_loc (input_location, BIT_AND_EXPR, type, args[0], tmp);
@@ -6236,6 +6254,32 @@ 
   gfc_conv_intrinsic_function_args (se, expr, args, 2);
   type = TREE_TYPE (args[0]);

+  /* Optionally generate code for runtime argument check.  */
+  if (gfc_option.rtcheck & GFC_RTCHECK_BITS)
+    {
+      tree below = fold_build2_loc (input_location, LT_EXPR,
+				    logical_type_node, args[1],
+				    build_int_cst (TREE_TYPE (args[1]), 0));
+      tree nbits = build_int_cst (TREE_TYPE (args[1]), TYPE_PRECISION (type));
+      tree above = fold_build2_loc (input_location, GE_EXPR,
+				    logical_type_node, args[1], nbits);
+      tree scond = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+				    logical_type_node, below, above);
+      size_t len_name = strlen (expr->value.function.isym->name);
+      char *name = XALLOCAVEC (char, len_name + 1);
+      for (size_t i = 0; i < len_name; i++)
+	name[i] = TOUPPER (expr->value.function.isym->name[i]);
+      name[len_name] = '\0';
+      tree iname = gfc_build_addr_expr (pchar_type_node,
+					gfc_build_cstring_const (name));
+      gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+			       "POS argument (%ld) out of range 0:%ld "
+			       "in intrinsic %s",
+			       fold_convert (long_integer_type_node, args[1]),
+			       fold_convert (long_integer_type_node, nbits),
+			       iname);
+    }
+
   tmp = fold_build2_loc (input_location, LSHIFT_EXPR, type,
 			 build_int_cst (type, 1), args[1]);
   if (set)
@@ -6261,6 +6305,42 @@ 
   gfc_conv_intrinsic_function_args (se, expr, args, 3);
   type = TREE_TYPE (args[0]);

+  /* Optionally generate code for runtime argument check.  */
+  if (gfc_option.rtcheck & GFC_RTCHECK_BITS)
+    {
+      tree tmp1 = fold_convert (long_integer_type_node, args[1]);
+      tree tmp2 = fold_convert (long_integer_type_node, args[2]);
+      tree nbits = build_int_cst (long_integer_type_node,
+				  TYPE_PRECISION (type));
+      tree below = fold_build2_loc (input_location, LT_EXPR,
+				    logical_type_node, args[1],
+				    build_int_cst (TREE_TYPE (args[1]), 0));
+      tree above = fold_build2_loc (input_location, GT_EXPR,
+				    logical_type_node, tmp1, nbits);
+      tree scond = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+				    logical_type_node, below, above);
+      gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+			       "POS argument (%ld) out of range 0:%ld "
+			       "in intrinsic IBITS", tmp1, nbits);
+      below = fold_build2_loc (input_location, LT_EXPR,
+			       logical_type_node, args[2],
+			       build_int_cst (TREE_TYPE (args[2]), 0));
+      above = fold_build2_loc (input_location, GT_EXPR,
+			       logical_type_node, tmp2, nbits);
+      scond = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+			       logical_type_node, below, above);
+      gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+			       "LEN argument (%ld) out of range 0:%ld "
+			       "in intrinsic IBITS", tmp2, nbits);
+      above = fold_build2_loc (input_location, PLUS_EXPR,
+			       long_integer_type_node, tmp1, tmp2);
+      scond = fold_build2_loc (input_location, GT_EXPR,
+			       logical_type_node, above, nbits);
+      gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+			       "POS(%ld)+LEN(%ld)>BIT_SIZE(%ld) "
+			       "in intrinsic IBITS", tmp1, tmp2, nbits);
+    }
+
   mask = build_int_cst (type, -1);
   mask = fold_build2_loc (input_location, LSHIFT_EXPR, type, mask, args[2]);
   mask = fold_build1_loc (input_location, BIT_NOT_EXPR, type, mask);
@@ -6382,6 +6462,32 @@ 
      gcc requires a shift width < BIT_SIZE(I), so we have to catch this
      special case.  */
   num_bits = build_int_cst (TREE_TYPE (args[1]), TYPE_PRECISION (type));
+
+  /* Optionally generate code for runtime argument check.  */
+  if (gfc_option.rtcheck & GFC_RTCHECK_BITS)
+    {
+      tree below = fold_build2_loc (input_location, LT_EXPR,
+				    logical_type_node, args[1],
+				    build_int_cst (TREE_TYPE (args[1]), 0));
+      tree above = fold_build2_loc (input_location, GT_EXPR,
+				    logical_type_node, args[1], num_bits);
+      tree scond = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+				    logical_type_node, below, above);
+      size_t len_name = strlen (expr->value.function.isym->name);
+      char *name = XALLOCAVEC (char, len_name + 1);
+      for (size_t i = 0; i < len_name; i++)
+	name[i] = TOUPPER (expr->value.function.isym->name[i]);
+      name[len_name] = '\0';
+      tree iname = gfc_build_addr_expr (pchar_type_node,
+					gfc_build_cstring_const (name));
+      gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+			       "SHIFT argument (%ld) out of range 0:%ld "
+			       "in intrinsic %s",
+			       fold_convert (long_integer_type_node, args[1]),
+			       fold_convert (long_integer_type_node, num_bits),
+			       iname);
+    }
+
   cond = fold_build2_loc (input_location, GE_EXPR, logical_type_node,
 			  args[1], num_bits);

@@ -6436,6 +6542,20 @@ 
      gcc requires a shift width < BIT_SIZE(I), so we have to catch this
      special case.  */
   num_bits = build_int_cst (TREE_TYPE (args[1]), TYPE_PRECISION (type));
+
+  /* Optionally generate code for runtime argument check.  */
+  if (gfc_option.rtcheck & GFC_RTCHECK_BITS)
+    {
+      tree outside = fold_build2_loc (input_location, GT_EXPR,
+				    logical_type_node, width, num_bits);
+      gfc_trans_runtime_check (true, false, outside, &se->pre, &expr->where,
+			       "SHIFT argument (%ld) out of range -%ld:%ld "
+			       "in intrinsic ISHFT",
+			       fold_convert (long_integer_type_node, args[1]),
+			       fold_convert (long_integer_type_node, num_bits),
+			       fold_convert (long_integer_type_node, num_bits));
+    }
+
   cond = fold_build2_loc (input_location, GE_EXPR, logical_type_node, width,
 			  num_bits);
   se->expr = fold_build3_loc (input_location, COND_EXPR, type, cond,
@@ -6454,6 +6574,7 @@ 
   tree lrot;
   tree rrot;
   tree zero;
+  tree nbits;
   unsigned int num_args;

   num_args = gfc_intrinsic_argument_list_length (expr);
@@ -6461,12 +6582,14 @@ 

   gfc_conv_intrinsic_function_args (se, expr, args, num_args);

+  type = TREE_TYPE (args[0]);
+  nbits = build_int_cst (long_integer_type_node, TYPE_PRECISION (type));
+
   if (num_args == 3)
     {
       /* Use a library function for the 3 parameter version.  */
       tree int4type = gfc_get_int_type (4);

-      type = TREE_TYPE (args[0]);
       /* We convert the first argument to at least 4 bytes, and
 	 convert back afterwards.  This removes the need for library
 	 functions for all argument sizes, and function will be
@@ -6480,6 +6603,32 @@ 
       args[1] = convert (int4type, args[1]);
       args[2] = convert (int4type, args[2]);

+      /* Optionally generate code for runtime argument check.  */
+      if (gfc_option.rtcheck & GFC_RTCHECK_BITS)
+	{
+	  tree size = fold_convert (long_integer_type_node, args[2]);
+	  tree below = fold_build2_loc (input_location, LE_EXPR,
+					logical_type_node, size,
+					build_int_cst (TREE_TYPE (args[1]), 0));
+	  tree above = fold_build2_loc (input_location, GT_EXPR,
+					logical_type_node, size, nbits);
+	  tree scond = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+					logical_type_node, below, above);
+	  gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+				   "SIZE argument (%ld) out of range 1:%ld "
+				   "in intrinsic ISHFTC", size, nbits);
+	  tree width = fold_convert (long_integer_type_node, args[1]);
+	  width = fold_build1_loc (input_location, ABS_EXPR,
+				   long_integer_type_node, width);
+	  scond = fold_build2_loc (input_location, GT_EXPR,
+				   logical_type_node, width, size);
+	  gfc_trans_runtime_check (true, false, scond, &se->pre, &expr->where,
+				   "SHIFT argument (%ld) out of range -%ld:%ld "
+				   "in intrinsic ISHFTC",
+				   fold_convert (long_integer_type_node, args[1]),
+				   size, size);
+	}
+
       switch (expr->ts.kind)
 	{
 	case 1:
@@ -6505,12 +6654,26 @@ 

       return;
     }
-  type = TREE_TYPE (args[0]);

   /* Evaluate arguments only once.  */
   args[0] = gfc_evaluate_now (args[0], &se->pre);
   args[1] = gfc_evaluate_now (args[1], &se->pre);

+  /* Optionally generate code for runtime argument check.  */
+  if (gfc_option.rtcheck & GFC_RTCHECK_BITS)
+    {
+      tree width = fold_convert (long_integer_type_node, args[1]);
+      width = fold_build1_loc (input_location, ABS_EXPR,
+			       long_integer_type_node, width);
+      tree outside = fold_build2_loc (input_location, GT_EXPR,
+				      logical_type_node, width, nbits);
+      gfc_trans_runtime_check (true, false, outside, &se->pre, &expr->where,
+			       "SHIFT argument (%ld) out of range -%ld:%ld "
+			       "in intrinsic ISHFTC",
+			       fold_convert (long_integer_type_node, args[1]),
+			       nbits, nbits);
+    }
+
   /* Rotate left if positive.  */
   lrot = fold_build2_loc (input_location, LROTATE_EXPR, type, args[0], args[1]);