]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
2008-03-28 Thomas Koenig <tkoenig@gcc.gnu.org>
authortkoenig <tkoenig@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 28 Mar 2008 23:22:49 +0000 (23:22 +0000)
committertkoenig <tkoenig@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 28 Mar 2008 23:22:49 +0000 (23:22 +0000)
PR libfortran/32972
PR libfortran/32512
* Makefile.am:  Add new variable, i_spread_c, containing
pack_i1.c, pack_i2.c, pack_i4.c, pack_i8.c, spread_i16.c,
spread_r4.c, spread_r8.c, spread_r10.c, spread_r16.c,
spread_c4.c, spread_c8.c, spread_c10.c, spread_c16.c.
* Makefile.in:  Regenerated.
* libgfortran.h:  Add prototypes for spread_i1, spread_i2,
spread_i4, spread_i8, spread_i16, spread_r4, spread_r8,
spread_c4, spread_c8, spread_c10, spread_c16,
spread_scalar_i1, spread_scalar_i2, spread_scalar_i4,
spread_scalar_i8, spread_scalar_i16, spread_scalar_r4
spread_scalar_r8, spread_scalar_c4, spread_scalar_c8,
spread_scalar_c10 and spread_scalar_c16.
Add macros to isolate both type and size information
from array descriptors with a single mask operation.
* intrinsics/spread_generic.c:  Add calls to specific
spread functions.
* m4/spread.m4:  New file.
* generated/spread_i1.c:  New file.
* generated/spread_i2.c:  New file.
* generated/spread_i4.c:  New file.
* generated/spread_i8.c:  New file.
* generated/spread_i16.c:  New file.
* generated/spread_r4.c:  New file.
* generated/spread_r8.c:  New file.
* generated/spread_r10.c:  New file.
* generated/spread_r16.c:  New file.
* generated/spread_c4.c:  New file.
* generated/spread_c8.c:  New file.
* generated/spread_c10.c:  New file.
* generated/spread_c16.c:  New file.

2008-03-28  Thomas Koenig  <tkoenig@gcc.gnu.org>

PR libfortran/32972
PR libfortran/32512
* intrinsic_spread_1.f90:  New file.
* intrinsic_spread_2.f90:  New file.
* intrinsic_spread_3.f90:  New file.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@133702 138bc75d-0d04-0410-961f-82ee72b054a4

23 files changed:
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/intrinsic_spread_1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/intrinsic_spread_2.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/intrinsic_spread_3.f90 [new file with mode: 0644]
libgfortran/ChangeLog
libgfortran/Makefile.am
libgfortran/Makefile.in
libgfortran/generated/spread_c10.c [new file with mode: 0644]
libgfortran/generated/spread_c16.c [new file with mode: 0644]
libgfortran/generated/spread_c4.c [new file with mode: 0644]
libgfortran/generated/spread_c8.c [new file with mode: 0644]
libgfortran/generated/spread_i1.c [new file with mode: 0644]
libgfortran/generated/spread_i16.c [new file with mode: 0644]
libgfortran/generated/spread_i2.c [new file with mode: 0644]
libgfortran/generated/spread_i4.c [new file with mode: 0644]
libgfortran/generated/spread_i8.c [new file with mode: 0644]
libgfortran/generated/spread_r10.c [new file with mode: 0644]
libgfortran/generated/spread_r16.c [new file with mode: 0644]
libgfortran/generated/spread_r4.c [new file with mode: 0644]
libgfortran/generated/spread_r8.c [new file with mode: 0644]
libgfortran/intrinsics/spread_generic.c
libgfortran/libgfortran.h
libgfortran/m4/spread.m4 [new file with mode: 0644]

index 468a4dbefd1d7feded19bfe6110b2e35c880de6b..303840604440868194feb81db8d577558709f778 100644 (file)
@@ -1,3 +1,11 @@
+2008-03-28  Thomas Koenig  <tkoenig@gcc.gnu.org>
+
+       PR libfortran/32972
+       PR libfortran/32512
+       * intrinsic_spread_1.f90:  New file.
+       * intrinsic_spread_2.f90:  New file.
+       * intrinsic_spread_3.f90:  New file.
+
 2008-03-28  Daniel Franke  <franke.daniel@gmail.com>
 
        PR fortran/34714
diff --git a/gcc/testsuite/gfortran.dg/intrinsic_spread_1.f90 b/gcc/testsuite/gfortran.dg/intrinsic_spread_1.f90
new file mode 100644 (file)
index 0000000..e2a0e16
--- /dev/null
@@ -0,0 +1,123 @@
+! { dg-do run }
+program foo
+   implicit none
+   integer(kind=1), dimension (10) :: i_1
+   integer(kind=1), dimension (2, 3) :: a_1
+   integer(kind=1), dimension (2, 2, 3) :: b_1
+   integer(kind=2), dimension (10) :: i_2
+   integer(kind=2), dimension (2, 3) :: a_2
+   integer(kind=2), dimension (2, 2, 3) :: b_2
+   integer(kind=4), dimension (10) :: i_4
+   integer(kind=4), dimension (2, 3) :: a_4
+   integer(kind=4), dimension (2, 2, 3) :: b_4
+   integer(kind=8), dimension (10) :: i_8
+   integer(kind=8), dimension (2, 3) :: a_8
+   integer(kind=8), dimension (2, 2, 3) :: b_8
+   real(kind=4), dimension (10) :: r_4
+   real(kind=4), dimension (2, 3) :: ar_4
+   real(kind=4), dimension (2, 2, 3) :: br_4
+   real(kind=8), dimension (10) :: r_8
+   real(kind=8), dimension (2, 3) :: ar_8
+   real(kind=8), dimension (2, 2, 3) :: br_8
+   character (len=200) line1, line2, line3
+
+   a_1 = reshape ((/1_1, 2_1, 3_1, 4_1, 5_1, 6_1/), (/2, 3/))
+   b_1 = spread (a_1, 1, 2)
+   if (any (b_1 .ne. reshape ((/1_1, 1_1, 2_1, 2_1, 3_1, 3_1, 4_1, 4_1, 5_1, 5_1, 6_1, 6_1/), &
+                            (/2, 2, 3/)))) &
+      call abort
+   line1 = ' '
+   write(line1, 9000) b_1
+   line2 = ' '
+   write(line2, 9000) spread (a_1, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9000) spread (a_1, 1, 2) + 0_1
+   if (line1 /= line3) call abort
+   i_1 = spread(1_1,1,10)
+   if (any(i_1 /= 1_1)) call abort
+
+   a_2 = reshape ((/1_2, 2_2, 3_2, 4_2, 5_2, 6_2/), (/2, 3/))
+   b_2 = spread (a_2, 1, 2)
+   if (any (b_2 .ne. reshape ((/1_2, 1_2, 2_2, 2_2, 3_2, 3_2, 4_2, 4_2, 5_2, 5_2, 6_2, 6_2/), &
+                            (/2, 2, 3/)))) &
+      call abort
+   line1 = ' '
+   write(line1, 9000) b_2
+   line2 = ' '
+   write(line2, 9000) spread (a_2, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9000) spread (a_2, 1, 2) + 0_2
+   if (line1 /= line3) call abort
+   i_2 = spread(1_2,1,10)
+   if (any(i_2 /= 1_2)) call abort
+
+   a_4 = reshape ((/1_4, 2_4, 3_4, 4_4, 5_4, 6_4/), (/2, 3/))
+   b_4 = spread (a_4, 1, 2)
+   if (any (b_4 .ne. reshape ((/1_4, 1_4, 2_4, 2_4, 3_4, 3_4, 4_4, 4_4, 5_4, 5_4, 6_4, 6_4/), &
+                            (/2, 2, 3/)))) &
+      call abort
+   line1 = ' '
+   write(line1, 9000) b_4
+   line2 = ' '
+   write(line2, 9000) spread (a_4, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9000) spread (a_4, 1, 2) + 0_4
+   if (line1 /= line3) call abort
+   i_4 = spread(1_4,1,10)
+   if (any(i_4 /= 1_4)) call abort
+
+   a_8 = reshape ((/1_8, 2_8, 3_8, 4_8, 5_8, 6_8/), (/2, 3/))
+   b_8 = spread (a_8, 1, 2)
+   if (any (b_8 .ne. reshape ((/1_8, 1_8, 2_8, 2_8, 3_8, 3_8, 4_8, 4_8, 5_8, 5_8, 6_8, 6_8/), &
+                            (/2, 2, 3/)))) &
+      call abort
+   line1 = ' '
+   write(line1, 9000) b_8
+   line2 = ' '
+   write(line2, 9000) spread (a_8, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9000) spread (a_8, 1, 2) + 0_8
+   if (line1 /= line3) call abort
+   i_8 = spread(1_8,1,10)
+   if (any(i_8 /= 1_8)) call abort
+
+
+   ar_4 = reshape ((/1._4, 2._4, 3._4, 4._4, 5._4, 6._4/), (/2, 3/))
+   br_4 = spread (ar_4, 1, 2)
+   if (any (br_4 .ne. reshape ((/1._4, 1._4, 2._4, 2._4, 3._4, 3._4, &
+   & 4._4, 4._4, 5._4, 5._4, 6._4, 6._4/), (/2, 2, 3/)))) call abort
+   line1 = ' '
+   write(line1, 9010) br_4
+   line2 = ' '
+   write(line2, 9010) spread (ar_4, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9010) spread (ar_4, 1, 2) + 0._4
+   if (line1 /= line3) call abort
+   r_4 = spread(1._4,1,10)
+   if (any(r_4 /= 1._4)) call abort
+
+
+   ar_8 = reshape ((/1._8, 2._8, 3._8, 4._8, 5._8, 6._8/), (/2, 3/))
+   br_8 = spread (ar_8, 1, 2)
+   if (any (br_8 .ne. reshape ((/1._8, 1._8, 2._8, 2._8, 3._8, 3._8, &
+   & 4._8, 4._8, 5._8, 5._8, 6._8, 6._8/), (/2, 2, 3/)))) call abort
+   line1 = ' '
+   write(line1, 9010) br_8
+   line2 = ' '
+   write(line2, 9010) spread (ar_8, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9010) spread (ar_8, 1, 2) + 0._8
+   if (line1 /= line3) call abort
+   r_8 = spread(1._8,1,10)
+   if (any(r_8 /= 1._8)) call abort
+
+9000 format(12I3)
+9010 format(12F7.3)
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/intrinsic_spread_2.f90 b/gcc/testsuite/gfortran.dg/intrinsic_spread_2.f90
new file mode 100644 (file)
index 0000000..ab01521
--- /dev/null
@@ -0,0 +1,29 @@
+! { dg-do run }
+! { dg-require-effective-target fortran_large_real }
+program foo
+   implicit none
+   integer,parameter :: k = selected_real_kind (precision (0.0_8) + 1)
+
+   real(kind=k), dimension(10) :: r_k
+   real(kind=k), dimension (2, 3) :: ar_k
+   real(kind=k), dimension (2, 2, 3) :: br_k
+   character (len=200) line1, line2, line3
+
+   ar_k = reshape ((/1._k, 2._k, 3._k, 4._k, 5._k, 6._k/), (/2, 3/))
+   br_k = spread (ar_k, 1, 2)
+   if (any (br_k .ne. reshape ((/1._k, 1._k, 2._k, 2._k, 3._k, 3._k, &
+   & 4._k, 4._k, 5._k, 5._k, 6._k, 6._k/), (/2, 2, 3/)))) call abort
+   line1 = ' '
+   write(line1, 9010) br_k
+   line2 = ' '
+   write(line2, 9010) spread (ar_k, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9010) spread (ar_k, 1, 2) + 0._k
+   if (line1 /= line3) call abort
+   r_k = spread(1._k,1,10)
+   if (any(r_k /= 1._k)) call abort
+
+9010 format(12F7.3)
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/intrinsic_spread_3.f90 b/gcc/testsuite/gfortran.dg/intrinsic_spread_3.f90
new file mode 100644 (file)
index 0000000..1dd2feb
--- /dev/null
@@ -0,0 +1,31 @@
+! { dg-do run }
+! { dg-require-effective-target fortran_large_int }
+
+program foo
+   implicit none
+   integer,parameter :: k = selected_int_kind (range (0_8) + 1)
+
+   integer(kind=k), dimension(10) :: i_k
+   integer(kind=k), dimension (2, 3) :: a_k
+   integer(kind=k), dimension (2, 2, 3) :: b_k
+   character (len=200) line1, line2, line3
+
+   a_k = reshape ((/1_k, 2_k, 3_k, 4_k, 5_k, 6_k/), (/2, 3/))
+   b_k = spread (a_k, 1, 2)
+   if (any (b_k .ne. reshape ((/1_k, 1_k, 2_k, 2_k, 3_k, 3_k, 4_k, 4_k, 5_k, 5_k, 6_k, 6_k/), &
+                            (/2, 2, 3/)))) &
+      call abort
+   line1 = ' '
+   write(line1, 9000) b_k
+   line2 = ' '
+   write(line2, 9000) spread (a_k, 1, 2)
+   if (line1 /= line2) call abort
+   line3 = ' '
+   write(line3, 9000) spread (a_k, 1, 2) + 0_k
+   if (line1 /= line3) call abort
+   i_k = spread(1_k,1,10)
+   if (any(i_k /= 1_k)) call abort
+
+9000 format(12I3)
+
+end program
index 9e10c90b7e42c3db6ec50245bbe8ab0b59440df5..11592e4b4cc4368beabf72442c6d9fbfc9080644 100644 (file)
@@ -1,3 +1,38 @@
+2008-03-28  Thomas Koenig  <tkoenig@gcc.gnu.org>
+
+       PR libfortran/32972
+       PR libfortran/32512
+       * Makefile.am:  Add new variable, i_spread_c, containing
+       pack_i1.c, pack_i2.c, pack_i4.c, pack_i8.c, spread_i16.c,
+       spread_r4.c, spread_r8.c, spread_r10.c, spread_r16.c,
+       spread_c4.c, spread_c8.c, spread_c10.c, spread_c16.c.
+       * Makefile.in:  Regenerated.
+       * libgfortran.h:  Add prototypes for spread_i1, spread_i2,
+       spread_i4, spread_i8, spread_i16, spread_r4, spread_r8,
+       spread_c4, spread_c8, spread_c10, spread_c16,
+       spread_scalar_i1, spread_scalar_i2, spread_scalar_i4,
+       spread_scalar_i8, spread_scalar_i16, spread_scalar_r4
+       spread_scalar_r8, spread_scalar_c4, spread_scalar_c8,
+       spread_scalar_c10 and spread_scalar_c16.
+       Add macros to isolate both type and size information
+       from array descriptors with a single mask operation.
+       * intrinsics/spread_generic.c:  Add calls to specific
+       spread functions.
+       * m4/spread.m4:  New file.
+       * generated/spread_i1.c:  New file.
+       * generated/spread_i2.c:  New file.
+       * generated/spread_i4.c:  New file.
+       * generated/spread_i8.c:  New file.
+       * generated/spread_i16.c:  New file.
+       * generated/spread_r4.c:  New file.
+       * generated/spread_r8.c:  New file.
+       * generated/spread_r10.c:  New file.
+       * generated/spread_r16.c:  New file.
+       * generated/spread_c4.c:  New file.
+       * generated/spread_c8.c:  New file.
+       * generated/spread_c10.c:  New file.
+       * generated/spread_c16.c:  New file.
+
 2008-03-28  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
 
        PR libfortran/35699
index 4e9655a6071feeee28dfa72d410062b8f13cf0d6..62ae5f31db830b37e09a5703e40c8ca821c8a8eb 100644 (file)
@@ -506,6 +506,21 @@ $(srcdir)/generated/unpack_c8.c \
 $(srcdir)/generated/unpack_c10.c \
 $(srcdir)/generated/unpack_c16.c
 
+i_spread_c = \
+$(srcdir)/generated/spread_i1.c \
+$(srcdir)/generated/spread_i2.c \
+$(srcdir)/generated/spread_i4.c \
+$(srcdir)/generated/spread_i8.c \
+$(srcdir)/generated/spread_i16.c \
+$(srcdir)/generated/spread_r4.c \
+$(srcdir)/generated/spread_r8.c \
+$(srcdir)/generated/spread_r10.c \
+$(srcdir)/generated/spread_r16.c \
+$(srcdir)/generated/spread_c4.c \
+$(srcdir)/generated/spread_c8.c \
+$(srcdir)/generated/spread_c10.c \
+$(srcdir)/generated/spread_c16.c 
+
 m4_files= m4/iparm.m4 m4/ifunction.m4 m4/iforeach.m4 m4/all.m4 \
     m4/any.m4 m4/count.m4 m4/maxloc0.m4 m4/maxloc1.m4 m4/maxval.m4 \
     m4/minloc0.m4 m4/minloc1.m4 m4/minval.m4 m4/product.m4 m4/sum.m4 \
@@ -515,7 +530,7 @@ m4_files= m4/iparm.m4 m4/ifunction.m4 m4/iforeach.m4 m4/all.m4 \
     m4/transpose.m4 m4/eoshift1.m4 m4/eoshift3.m4 m4/exponent.m4 \
     m4/fraction.m4 m4/nearest.m4 m4/set_exponent.m4 m4/pow.m4 \
     m4/misc_specifics.m4 m4/rrspacing.m4 m4/spacing.m4 m4/pack.m4 \
-    m4/unpack.m4
+    m4/unpack.m4 m4/spread.m4
 
 gfor_built_src= $(i_all_c) $(i_any_c) $(i_count_c) $(i_maxloc0_c) \
     $(i_maxloc1_c) $(i_maxval_c) $(i_minloc0_c) $(i_minloc1_c) $(i_minval_c) \
@@ -524,7 +539,7 @@ gfor_built_src= $(i_all_c) $(i_any_c) $(i_count_c) $(i_maxloc0_c) \
     $(i_eoshift3_c) $(i_cshift1_c) $(i_reshape_c) $(in_pack_c) $(in_unpack_c) \
     $(i_exponent_c) $(i_fraction_c) $(i_nearest_c) $(i_set_exponent_c) \
     $(i_pow_c) $(i_rrspacing_c) $(i_spacing_c) $(i_pack_c) $(i_unpack_c) \
-    selected_int_kind.inc selected_real_kind.inc kinds.h \
+    $(i_spread_c) selected_int_kind.inc selected_real_kind.inc kinds.h \
     kinds.inc c99_protos.inc fpu-target.h
 
 # Machine generated specifics
@@ -845,6 +860,9 @@ $(i_pack_c): m4/pack.m4 $(I_M4_DEPS)
 $(i_unpack_c): m4/unpack.m4 $(I_M4_DEPS)
        $(M4) -Dfile=$@ -I$(srcdir)/m4 unpack.m4 > $@
 
+$(i_spread_c): m4/spread.m4 $(I_M4_DEPS)
+       $(M4) -Dfile=$@ -I$(srcdir)/m4 spread.m4 > $@
+
 $(gfor_built_specific_src): m4/specific.m4 m4/head.m4
        $(M4) -Dfile=$@ -I$(srcdir)/m4 specific.m4 > $@
 
index fb6056f2d5ce1d5d0209b2ceea06dde1be3f794f..71eb44e23df63a79e5d0553d5ace39bd9cfb912f 100644 (file)
@@ -382,7 +382,20 @@ am__libgfortran_la_SOURCES_DIST = runtime/backtrace.c \
        $(srcdir)/generated/unpack_c4.c \
        $(srcdir)/generated/unpack_c8.c \
        $(srcdir)/generated/unpack_c10.c \
-       $(srcdir)/generated/unpack_c16.c selected_int_kind.inc \
+       $(srcdir)/generated/unpack_c16.c \
+       $(srcdir)/generated/spread_i1.c \
+       $(srcdir)/generated/spread_i2.c \
+       $(srcdir)/generated/spread_i4.c \
+       $(srcdir)/generated/spread_i8.c \
+       $(srcdir)/generated/spread_i16.c \
+       $(srcdir)/generated/spread_r4.c \
+       $(srcdir)/generated/spread_r8.c \
+       $(srcdir)/generated/spread_r10.c \
+       $(srcdir)/generated/spread_r16.c \
+       $(srcdir)/generated/spread_c4.c \
+       $(srcdir)/generated/spread_c8.c \
+       $(srcdir)/generated/spread_c10.c \
+       $(srcdir)/generated/spread_c16.c selected_int_kind.inc \
        selected_real_kind.inc kinds.h kinds.inc c99_protos.inc \
        fpu-target.h io/close.c io/file_pos.c io/format.c io/inquire.c \
        io/intrinsics.c io/list_read.c io/lock.c io/open.c io/read.c \
@@ -659,7 +672,11 @@ am__objects_31 = unpack_i1.lo unpack_i2.lo unpack_i4.lo unpack_i8.lo \
        unpack_i16.lo unpack_r4.lo unpack_r8.lo unpack_r10.lo \
        unpack_r16.lo unpack_c4.lo unpack_c8.lo unpack_c10.lo \
        unpack_c16.lo
-am__objects_32 = $(am__objects_2) $(am__objects_3) $(am__objects_4) \
+am__objects_32 = spread_i1.lo spread_i2.lo spread_i4.lo spread_i8.lo \
+       spread_i16.lo spread_r4.lo spread_r8.lo spread_r10.lo \
+       spread_r16.lo spread_c4.lo spread_c8.lo spread_c10.lo \
+       spread_c16.lo
+am__objects_33 = $(am__objects_2) $(am__objects_3) $(am__objects_4) \
        $(am__objects_5) $(am__objects_6) $(am__objects_7) \
        $(am__objects_8) $(am__objects_9) $(am__objects_10) \
        $(am__objects_11) $(am__objects_12) $(am__objects_13) \
@@ -668,11 +685,12 @@ am__objects_32 = $(am__objects_2) $(am__objects_3) $(am__objects_4) \
        $(am__objects_20) $(am__objects_21) $(am__objects_22) \
        $(am__objects_23) $(am__objects_24) $(am__objects_25) \
        $(am__objects_26) $(am__objects_27) $(am__objects_28) \
-       $(am__objects_29) $(am__objects_30) $(am__objects_31)
-am__objects_33 = close.lo file_pos.lo format.lo inquire.lo \
+       $(am__objects_29) $(am__objects_30) $(am__objects_31) \
+       $(am__objects_32)
+am__objects_34 = close.lo file_pos.lo format.lo inquire.lo \
        intrinsics.lo list_read.lo lock.lo open.lo read.lo \
        size_from_kind.lo transfer.lo unit.lo unix.lo write.lo
-am__objects_34 = associated.lo abort.lo access.lo args.lo \
+am__objects_35 = associated.lo abort.lo access.lo args.lo \
        c99_functions.lo chdir.lo chmod.lo clock.lo cpu_time.lo \
        cshift0.lo ctime.lo date_and_time.lo dtime.lo env.lo \
        eoshift0.lo eoshift2.lo erfc_scaled.lo etime.lo exit.lo \
@@ -686,8 +704,8 @@ am__objects_34 = associated.lo abort.lo access.lo args.lo \
        system_clock.lo time.lo transpose_generic.lo umask.lo \
        unlink.lo unpack_generic.lo in_pack_generic.lo \
        in_unpack_generic.lo
-am__objects_35 =
-am__objects_36 = _abs_c4.lo _abs_c8.lo _abs_c10.lo _abs_c16.lo \
+am__objects_36 =
+am__objects_37 = _abs_c4.lo _abs_c8.lo _abs_c10.lo _abs_c16.lo \
        _abs_i4.lo _abs_i8.lo _abs_i16.lo _abs_r4.lo _abs_r8.lo \
        _abs_r10.lo _abs_r16.lo _aimag_c4.lo _aimag_c8.lo \
        _aimag_c10.lo _aimag_c16.lo _exp_r4.lo _exp_r8.lo _exp_r10.lo \
@@ -711,18 +729,18 @@ am__objects_36 = _abs_c4.lo _abs_c8.lo _abs_c10.lo _abs_c16.lo \
        _conjg_c4.lo _conjg_c8.lo _conjg_c10.lo _conjg_c16.lo \
        _aint_r4.lo _aint_r8.lo _aint_r10.lo _aint_r16.lo _anint_r4.lo \
        _anint_r8.lo _anint_r10.lo _anint_r16.lo
-am__objects_37 = _sign_i4.lo _sign_i8.lo _sign_i16.lo _sign_r4.lo \
+am__objects_38 = _sign_i4.lo _sign_i8.lo _sign_i16.lo _sign_r4.lo \
        _sign_r8.lo _sign_r10.lo _sign_r16.lo _dim_i4.lo _dim_i8.lo \
        _dim_i16.lo _dim_r4.lo _dim_r8.lo _dim_r10.lo _dim_r16.lo \
        _atan2_r4.lo _atan2_r8.lo _atan2_r10.lo _atan2_r16.lo \
        _mod_i4.lo _mod_i8.lo _mod_i16.lo _mod_r4.lo _mod_r8.lo \
        _mod_r10.lo _mod_r16.lo
-am__objects_38 = misc_specifics.lo
-am__objects_39 = $(am__objects_36) $(am__objects_37) $(am__objects_38) \
+am__objects_39 = misc_specifics.lo
+am__objects_40 = $(am__objects_37) $(am__objects_38) $(am__objects_39) \
        dprod_r8.lo f2c_specifics.lo
-am__objects_40 = $(am__objects_1) $(am__objects_32) $(am__objects_33) \
-       $(am__objects_34) $(am__objects_35) $(am__objects_39)
-@onestep_FALSE@am_libgfortran_la_OBJECTS = $(am__objects_40)
+am__objects_41 = $(am__objects_1) $(am__objects_33) $(am__objects_34) \
+       $(am__objects_35) $(am__objects_36) $(am__objects_40)
+@onestep_FALSE@am_libgfortran_la_OBJECTS = $(am__objects_41)
 @onestep_TRUE@am_libgfortran_la_OBJECTS = libgfortran_c.lo
 libgfortran_la_OBJECTS = $(am_libgfortran_la_OBJECTS)
 libgfortranbegin_la_LIBADD =
@@ -1386,6 +1404,21 @@ $(srcdir)/generated/unpack_c8.c \
 $(srcdir)/generated/unpack_c10.c \
 $(srcdir)/generated/unpack_c16.c
 
+i_spread_c = \
+$(srcdir)/generated/spread_i1.c \
+$(srcdir)/generated/spread_i2.c \
+$(srcdir)/generated/spread_i4.c \
+$(srcdir)/generated/spread_i8.c \
+$(srcdir)/generated/spread_i16.c \
+$(srcdir)/generated/spread_r4.c \
+$(srcdir)/generated/spread_r8.c \
+$(srcdir)/generated/spread_r10.c \
+$(srcdir)/generated/spread_r16.c \
+$(srcdir)/generated/spread_c4.c \
+$(srcdir)/generated/spread_c8.c \
+$(srcdir)/generated/spread_c10.c \
+$(srcdir)/generated/spread_c16.c 
+
 m4_files = m4/iparm.m4 m4/ifunction.m4 m4/iforeach.m4 m4/all.m4 \
     m4/any.m4 m4/count.m4 m4/maxloc0.m4 m4/maxloc1.m4 m4/maxval.m4 \
     m4/minloc0.m4 m4/minloc1.m4 m4/minval.m4 m4/product.m4 m4/sum.m4 \
@@ -1395,7 +1428,7 @@ m4_files = m4/iparm.m4 m4/ifunction.m4 m4/iforeach.m4 m4/all.m4 \
     m4/transpose.m4 m4/eoshift1.m4 m4/eoshift3.m4 m4/exponent.m4 \
     m4/fraction.m4 m4/nearest.m4 m4/set_exponent.m4 m4/pow.m4 \
     m4/misc_specifics.m4 m4/rrspacing.m4 m4/spacing.m4 m4/pack.m4 \
-    m4/unpack.m4
+    m4/unpack.m4 m4/spread.m4
 
 gfor_built_src = $(i_all_c) $(i_any_c) $(i_count_c) $(i_maxloc0_c) \
     $(i_maxloc1_c) $(i_maxval_c) $(i_minloc0_c) $(i_minloc1_c) $(i_minval_c) \
@@ -1404,7 +1437,7 @@ gfor_built_src = $(i_all_c) $(i_any_c) $(i_count_c) $(i_maxloc0_c) \
     $(i_eoshift3_c) $(i_cshift1_c) $(i_reshape_c) $(in_pack_c) $(in_unpack_c) \
     $(i_exponent_c) $(i_fraction_c) $(i_nearest_c) $(i_set_exponent_c) \
     $(i_pow_c) $(i_rrspacing_c) $(i_spacing_c) $(i_pack_c) $(i_unpack_c) \
-    selected_int_kind.inc selected_real_kind.inc kinds.h \
+    $(i_spread_c) selected_int_kind.inc selected_real_kind.inc kinds.h \
     kinds.inc c99_protos.inc fpu-target.h
 
 
@@ -2054,7 +2087,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spacing_r16.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spacing_r4.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spacing_r8.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_c10.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_c16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_c4.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_c8.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_generic.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_i1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_i16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_i2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_i4.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_i8.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_r10.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_r16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_r4.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_r8.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stop.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Plo@am__quote@
@@ -4884,6 +4930,97 @@ unpack_c16.lo: $(srcdir)/generated/unpack_c16.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unpack_c16.lo `test -f '$(srcdir)/generated/unpack_c16.c' || echo '$(srcdir)/'`$(srcdir)/generated/unpack_c16.c
 
+spread_i1.lo: $(srcdir)/generated/spread_i1.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_i1.lo -MD -MP -MF "$(DEPDIR)/spread_i1.Tpo" -c -o spread_i1.lo `test -f '$(srcdir)/generated/spread_i1.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i1.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_i1.Tpo" "$(DEPDIR)/spread_i1.Plo"; else rm -f "$(DEPDIR)/spread_i1.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_i1.c' object='spread_i1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_i1.lo `test -f '$(srcdir)/generated/spread_i1.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i1.c
+
+spread_i2.lo: $(srcdir)/generated/spread_i2.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_i2.lo -MD -MP -MF "$(DEPDIR)/spread_i2.Tpo" -c -o spread_i2.lo `test -f '$(srcdir)/generated/spread_i2.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i2.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_i2.Tpo" "$(DEPDIR)/spread_i2.Plo"; else rm -f "$(DEPDIR)/spread_i2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_i2.c' object='spread_i2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_i2.lo `test -f '$(srcdir)/generated/spread_i2.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i2.c
+
+spread_i4.lo: $(srcdir)/generated/spread_i4.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_i4.lo -MD -MP -MF "$(DEPDIR)/spread_i4.Tpo" -c -o spread_i4.lo `test -f '$(srcdir)/generated/spread_i4.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i4.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_i4.Tpo" "$(DEPDIR)/spread_i4.Plo"; else rm -f "$(DEPDIR)/spread_i4.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_i4.c' object='spread_i4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_i4.lo `test -f '$(srcdir)/generated/spread_i4.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i4.c
+
+spread_i8.lo: $(srcdir)/generated/spread_i8.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_i8.lo -MD -MP -MF "$(DEPDIR)/spread_i8.Tpo" -c -o spread_i8.lo `test -f '$(srcdir)/generated/spread_i8.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i8.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_i8.Tpo" "$(DEPDIR)/spread_i8.Plo"; else rm -f "$(DEPDIR)/spread_i8.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_i8.c' object='spread_i8.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_i8.lo `test -f '$(srcdir)/generated/spread_i8.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i8.c
+
+spread_i16.lo: $(srcdir)/generated/spread_i16.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_i16.lo -MD -MP -MF "$(DEPDIR)/spread_i16.Tpo" -c -o spread_i16.lo `test -f '$(srcdir)/generated/spread_i16.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i16.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_i16.Tpo" "$(DEPDIR)/spread_i16.Plo"; else rm -f "$(DEPDIR)/spread_i16.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_i16.c' object='spread_i16.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_i16.lo `test -f '$(srcdir)/generated/spread_i16.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_i16.c
+
+spread_r4.lo: $(srcdir)/generated/spread_r4.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_r4.lo -MD -MP -MF "$(DEPDIR)/spread_r4.Tpo" -c -o spread_r4.lo `test -f '$(srcdir)/generated/spread_r4.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r4.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_r4.Tpo" "$(DEPDIR)/spread_r4.Plo"; else rm -f "$(DEPDIR)/spread_r4.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_r4.c' object='spread_r4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_r4.lo `test -f '$(srcdir)/generated/spread_r4.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r4.c
+
+spread_r8.lo: $(srcdir)/generated/spread_r8.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_r8.lo -MD -MP -MF "$(DEPDIR)/spread_r8.Tpo" -c -o spread_r8.lo `test -f '$(srcdir)/generated/spread_r8.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r8.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_r8.Tpo" "$(DEPDIR)/spread_r8.Plo"; else rm -f "$(DEPDIR)/spread_r8.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_r8.c' object='spread_r8.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_r8.lo `test -f '$(srcdir)/generated/spread_r8.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r8.c
+
+spread_r10.lo: $(srcdir)/generated/spread_r10.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_r10.lo -MD -MP -MF "$(DEPDIR)/spread_r10.Tpo" -c -o spread_r10.lo `test -f '$(srcdir)/generated/spread_r10.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r10.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_r10.Tpo" "$(DEPDIR)/spread_r10.Plo"; else rm -f "$(DEPDIR)/spread_r10.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_r10.c' object='spread_r10.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_r10.lo `test -f '$(srcdir)/generated/spread_r10.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r10.c
+
+spread_r16.lo: $(srcdir)/generated/spread_r16.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_r16.lo -MD -MP -MF "$(DEPDIR)/spread_r16.Tpo" -c -o spread_r16.lo `test -f '$(srcdir)/generated/spread_r16.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r16.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_r16.Tpo" "$(DEPDIR)/spread_r16.Plo"; else rm -f "$(DEPDIR)/spread_r16.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_r16.c' object='spread_r16.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_r16.lo `test -f '$(srcdir)/generated/spread_r16.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_r16.c
+
+spread_c4.lo: $(srcdir)/generated/spread_c4.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_c4.lo -MD -MP -MF "$(DEPDIR)/spread_c4.Tpo" -c -o spread_c4.lo `test -f '$(srcdir)/generated/spread_c4.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c4.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_c4.Tpo" "$(DEPDIR)/spread_c4.Plo"; else rm -f "$(DEPDIR)/spread_c4.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_c4.c' object='spread_c4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_c4.lo `test -f '$(srcdir)/generated/spread_c4.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c4.c
+
+spread_c8.lo: $(srcdir)/generated/spread_c8.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_c8.lo -MD -MP -MF "$(DEPDIR)/spread_c8.Tpo" -c -o spread_c8.lo `test -f '$(srcdir)/generated/spread_c8.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c8.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_c8.Tpo" "$(DEPDIR)/spread_c8.Plo"; else rm -f "$(DEPDIR)/spread_c8.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_c8.c' object='spread_c8.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_c8.lo `test -f '$(srcdir)/generated/spread_c8.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c8.c
+
+spread_c10.lo: $(srcdir)/generated/spread_c10.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_c10.lo -MD -MP -MF "$(DEPDIR)/spread_c10.Tpo" -c -o spread_c10.lo `test -f '$(srcdir)/generated/spread_c10.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c10.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_c10.Tpo" "$(DEPDIR)/spread_c10.Plo"; else rm -f "$(DEPDIR)/spread_c10.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_c10.c' object='spread_c10.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_c10.lo `test -f '$(srcdir)/generated/spread_c10.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c10.c
+
+spread_c16.lo: $(srcdir)/generated/spread_c16.c
+@am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_c16.lo -MD -MP -MF "$(DEPDIR)/spread_c16.Tpo" -c -o spread_c16.lo `test -f '$(srcdir)/generated/spread_c16.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c16.c; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/spread_c16.Tpo" "$(DEPDIR)/spread_c16.Plo"; else rm -f "$(DEPDIR)/spread_c16.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$(srcdir)/generated/spread_c16.c' object='spread_c16.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_c16.lo `test -f '$(srcdir)/generated/spread_c16.c' || echo '$(srcdir)/'`$(srcdir)/generated/spread_c16.c
+
 close.lo: io/close.c
 @am__fastdepCC_TRUE@   if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT close.lo -MD -MP -MF "$(DEPDIR)/close.Tpo" -c -o close.lo `test -f 'io/close.c' || echo '$(srcdir)/'`io/close.c; \
 @am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/close.Tpo" "$(DEPDIR)/close.Plo"; else rm -f "$(DEPDIR)/close.Tpo"; exit 1; fi
@@ -5841,6 +5978,9 @@ fpu-target.h: $(srcdir)/$(FPU_HOST_HEADER)
 @MAINTAINER_MODE_TRUE@$(i_unpack_c): m4/unpack.m4 $(I_M4_DEPS)
 @MAINTAINER_MODE_TRUE@ $(M4) -Dfile=$@ -I$(srcdir)/m4 unpack.m4 > $@
 
+@MAINTAINER_MODE_TRUE@$(i_spread_c): m4/spread.m4 $(I_M4_DEPS)
+@MAINTAINER_MODE_TRUE@ $(M4) -Dfile=$@ -I$(srcdir)/m4 spread.m4 > $@
+
 @MAINTAINER_MODE_TRUE@$(gfor_built_specific_src): m4/specific.m4 m4/head.m4
 @MAINTAINER_MODE_TRUE@ $(M4) -Dfile=$@ -I$(srcdir)/m4 specific.m4 > $@
 
diff --git a/libgfortran/generated/spread_c10.c b/libgfortran/generated/spread_c10.c
new file mode 100644 (file)
index 0000000..76a3614
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_COMPLEX_10)
+
+void
+spread_c10 (gfc_array_c10 *ret, const gfc_array_c10 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_COMPLEX_10 *rptr;
+  GFC_COMPLEX_10 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_COMPLEX_10 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_COMPLEX_10));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_c10 (gfc_array_c10 *ret, const GFC_COMPLEX_10 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_COMPLEX_10 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_COMPLEX_10));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_c16.c b/libgfortran/generated/spread_c16.c
new file mode 100644 (file)
index 0000000..0ea5756
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_COMPLEX_16)
+
+void
+spread_c16 (gfc_array_c16 *ret, const gfc_array_c16 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_COMPLEX_16 *rptr;
+  GFC_COMPLEX_16 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_COMPLEX_16 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_COMPLEX_16));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_c16 (gfc_array_c16 *ret, const GFC_COMPLEX_16 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_COMPLEX_16 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_COMPLEX_16));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_c4.c b/libgfortran/generated/spread_c4.c
new file mode 100644 (file)
index 0000000..f86da84
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_COMPLEX_4)
+
+void
+spread_c4 (gfc_array_c4 *ret, const gfc_array_c4 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_COMPLEX_4 *rptr;
+  GFC_COMPLEX_4 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_COMPLEX_4 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_COMPLEX_4));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_c4 (gfc_array_c4 *ret, const GFC_COMPLEX_4 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_COMPLEX_4 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_COMPLEX_4));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_c8.c b/libgfortran/generated/spread_c8.c
new file mode 100644 (file)
index 0000000..7a3f4df
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_COMPLEX_8)
+
+void
+spread_c8 (gfc_array_c8 *ret, const gfc_array_c8 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_COMPLEX_8 *rptr;
+  GFC_COMPLEX_8 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_COMPLEX_8 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_COMPLEX_8));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_c8 (gfc_array_c8 *ret, const GFC_COMPLEX_8 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_COMPLEX_8 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_COMPLEX_8));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_i1.c b/libgfortran/generated/spread_i1.c
new file mode 100644 (file)
index 0000000..396a521
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_INTEGER_1)
+
+void
+spread_i1 (gfc_array_i1 *ret, const gfc_array_i1 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_INTEGER_1 *rptr;
+  GFC_INTEGER_1 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_INTEGER_1 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_INTEGER_1));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_i1 (gfc_array_i1 *ret, const GFC_INTEGER_1 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_INTEGER_1 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_INTEGER_1));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_i16.c b/libgfortran/generated/spread_i16.c
new file mode 100644 (file)
index 0000000..5599342
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_INTEGER_16)
+
+void
+spread_i16 (gfc_array_i16 *ret, const gfc_array_i16 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_INTEGER_16 *rptr;
+  GFC_INTEGER_16 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_INTEGER_16 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_INTEGER_16));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_i16 (gfc_array_i16 *ret, const GFC_INTEGER_16 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_INTEGER_16 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_INTEGER_16));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_i2.c b/libgfortran/generated/spread_i2.c
new file mode 100644 (file)
index 0000000..d8ac9dc
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_INTEGER_2)
+
+void
+spread_i2 (gfc_array_i2 *ret, const gfc_array_i2 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_INTEGER_2 *rptr;
+  GFC_INTEGER_2 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_INTEGER_2 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_INTEGER_2));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_i2 (gfc_array_i2 *ret, const GFC_INTEGER_2 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_INTEGER_2 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_INTEGER_2));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_i4.c b/libgfortran/generated/spread_i4.c
new file mode 100644 (file)
index 0000000..c0890b6
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_INTEGER_4)
+
+void
+spread_i4 (gfc_array_i4 *ret, const gfc_array_i4 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_INTEGER_4 *rptr;
+  GFC_INTEGER_4 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_INTEGER_4 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_INTEGER_4));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_i4 (gfc_array_i4 *ret, const GFC_INTEGER_4 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_INTEGER_4 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_INTEGER_4));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_i8.c b/libgfortran/generated/spread_i8.c
new file mode 100644 (file)
index 0000000..b0032bf
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_INTEGER_8)
+
+void
+spread_i8 (gfc_array_i8 *ret, const gfc_array_i8 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_INTEGER_8 *rptr;
+  GFC_INTEGER_8 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_INTEGER_8 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_INTEGER_8));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_i8 (gfc_array_i8 *ret, const GFC_INTEGER_8 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_INTEGER_8 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_INTEGER_8));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_r10.c b/libgfortran/generated/spread_r10.c
new file mode 100644 (file)
index 0000000..404aaa4
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_REAL_10)
+
+void
+spread_r10 (gfc_array_r10 *ret, const gfc_array_r10 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_REAL_10 *rptr;
+  GFC_REAL_10 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_REAL_10 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_REAL_10));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_r10 (gfc_array_r10 *ret, const GFC_REAL_10 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_REAL_10 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_REAL_10));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_r16.c b/libgfortran/generated/spread_r16.c
new file mode 100644 (file)
index 0000000..1226733
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_REAL_16)
+
+void
+spread_r16 (gfc_array_r16 *ret, const gfc_array_r16 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_REAL_16 *rptr;
+  GFC_REAL_16 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_REAL_16 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_REAL_16));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_r16 (gfc_array_r16 *ret, const GFC_REAL_16 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_REAL_16 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_REAL_16));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_r4.c b/libgfortran/generated/spread_r4.c
new file mode 100644 (file)
index 0000000..1569dbc
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_REAL_4)
+
+void
+spread_r4 (gfc_array_r4 *ret, const gfc_array_r4 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_REAL_4 *rptr;
+  GFC_REAL_4 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_REAL_4 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_REAL_4));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_r4 (gfc_array_r4 *ret, const GFC_REAL_4 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_REAL_4 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_REAL_4));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
diff --git a/libgfortran/generated/spread_r8.c b/libgfortran/generated/spread_r8.c
new file mode 100644 (file)
index 0000000..c028f80
--- /dev/null
@@ -0,0 +1,277 @@
+/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+#if defined (HAVE_GFC_REAL_8)
+
+void
+spread_r8 (gfc_array_r8 *ret, const gfc_array_r8 *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  GFC_REAL_8 *rptr;
+  GFC_REAL_8 *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const GFC_REAL_8 *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof(GFC_REAL_8));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_r8 (gfc_array_r8 *ret, const GFC_REAL_8 *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  GFC_REAL_8 * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof (GFC_REAL_8));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
index 4be0a164c8ac3d6ea0e4667fe599c3dc62dbd825..16578f788fceed598968e15694cf9dccba4ea297 100644 (file)
@@ -276,6 +276,92 @@ void
 spread (gfc_array_char *ret, const gfc_array_char *source,
        const index_type *along, const index_type *pncopies)
 {
+  index_type type_size;
+
+  type_size = GFC_DTYPE_TYPE_SIZE(ret);
+  switch(type_size)
+    {
+    case GFC_DTYPE_LOGICAL_1:
+    case GFC_DTYPE_INTEGER_1:
+      spread_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) source,
+                *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_LOGICAL_2:
+    case GFC_DTYPE_INTEGER_2:
+      spread_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) source,
+                *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_LOGICAL_4:
+    case GFC_DTYPE_INTEGER_4:
+      spread_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) source,
+                *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_LOGICAL_8:
+    case GFC_DTYPE_INTEGER_8:
+      spread_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) source,
+                *along, *pncopies);
+      return;
+
+#ifdef HAVE_GFC_INTEGER_16
+    case GFC_DTYPE_LOGICAL_16:
+    case GFC_DTYPE_INTEGER_16:
+      spread_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) source,
+                *along, *pncopies);
+      return;
+#endif
+
+    case GFC_DTYPE_REAL_4:
+      spread_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) source,
+                *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_REAL_8:
+      spread_r8 ((gfc_array_r8 *) ret, (gfc_array_r8 *) source,
+                *along, *pncopies);
+      return;
+
+#ifdef GFC_HAVE_REAL_10
+    case GFC_DTYPE_REAL_10:
+      spread_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) source,
+                *along, *pncopies);
+      return;
+#endif
+
+#ifdef GFC_HAVE_REAL_16
+    case GFC_DTYPE_REAL_16:
+      spread_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) source,
+                *along, *pncopies);
+      return;
+#endif
+
+    case GFC_DTYPE_COMPLEX_4:
+      spread_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) source,
+                *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_COMPLEX_8:
+      spread_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) source,
+                *along, *pncopies);
+      return;
+
+#ifdef GFC_HAVE_COMPLEX_10
+    case GFC_DTYPE_COMPLEX_10:
+      spread_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) source,
+                *along, *pncopies);
+      return;
+#endif
+
+#ifdef GFC_HAVE_COMPLEX_16
+    case GFC_DTYPE_COMPLEX_16:
+      spread_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) source,
+                *along, *pncopies);
+      return;
+#endif
+
+    }
   spread_internal (ret, source, along, pncopies, GFC_DESCRIPTOR_SIZE (source));
 }
 
@@ -304,8 +390,96 @@ void
 spread_scalar (gfc_array_char *ret, const char *source,
               const index_type *along, const index_type *pncopies)
 {
+  index_type type_size;
+
   if (!ret->dtype)
     runtime_error ("return array missing descriptor in spread()");
+
+  type_size = GFC_DTYPE_TYPE_SIZE(ret);
+  switch(type_size)
+    {
+    case GFC_DTYPE_LOGICAL_1:
+    case GFC_DTYPE_INTEGER_1:
+      spread_scalar_i1 ((gfc_array_i1 *) ret, (GFC_INTEGER_1 *) source,
+                       *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_LOGICAL_2:
+    case GFC_DTYPE_INTEGER_2:
+      spread_scalar_i2 ((gfc_array_i2 *) ret, (GFC_INTEGER_2 *) source,
+                       *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_LOGICAL_4:
+    case GFC_DTYPE_INTEGER_4:
+      spread_scalar_i4 ((gfc_array_i4 *) ret, (GFC_INTEGER_4 *) source,
+                       *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_LOGICAL_8:
+    case GFC_DTYPE_INTEGER_8:
+      spread_scalar_i8 ((gfc_array_i8 *) ret, (GFC_INTEGER_8 *) source,
+                       *along, *pncopies);
+      return;
+
+#ifdef HAVE_GFC_INTEGER_16
+    case GFC_DTYPE_LOGICAL_16:
+    case GFC_DTYPE_INTEGER_16:
+      spread_scalar_i16 ((gfc_array_i16 *) ret, (GFC_INTEGER_16 *) source,
+                       *along, *pncopies);
+      return;
+#endif
+
+    case GFC_DTYPE_REAL_4:
+      spread_scalar_r4 ((gfc_array_r4 *) ret, (GFC_REAL_4 *) source,
+                       *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_REAL_8:
+      spread_scalar_r8 ((gfc_array_r8 *) ret, (GFC_REAL_8 *) source,
+                       *along, *pncopies);
+      return;
+
+#ifdef HAVE_GFC_REAL_10
+    case GFC_DTYPE_REAL_10:
+      spread_scalar_r10 ((gfc_array_r10 *) ret, (GFC_REAL_10 *) source,
+                       *along, *pncopies);
+      return;
+#endif
+
+#ifdef HAVE_GFC_REAL_16
+    case GFC_DTYPE_REAL_16:
+      spread_scalar_r16 ((gfc_array_r16 *) ret, (GFC_REAL_16 *) source,
+                       *along, *pncopies);
+      return;
+#endif
+
+    case GFC_DTYPE_COMPLEX_4:
+      spread_scalar_c4 ((gfc_array_c4 *) ret, (GFC_COMPLEX_4 *) source,
+                       *along, *pncopies);
+      return;
+
+    case GFC_DTYPE_COMPLEX_8:
+      spread_scalar_c8 ((gfc_array_c8 *) ret, (GFC_COMPLEX_8 *) source,
+                       *along, *pncopies);
+      return;
+
+#ifdef HAVE_GFC_COMPLEX_10
+    case GFC_DTYPE_COMPLEX_10:
+      spread_scalar_c10 ((gfc_array_c10 *) ret, (GFC_COMPLEX_10 *) source,
+                       *along, *pncopies);
+      return;
+#endif
+
+#ifdef HAVE_GFC_COMPLEX_16
+    case GFC_DTYPE_COMPLEX_16:
+      spread_scalar_c16 ((gfc_array_c16 *) ret, (GFC_COMPLEX_16 *) source,
+                       *along, *pncopies);
+      return;
+#endif
+
+    }
+
   spread_internal_scalar (ret, source, along, pncopies, GFC_DESCRIPTOR_SIZE (ret));
 }
 
index 9a1f643d71d868db3534fa63438cf651f96c93fd..b5cad85c85fcbe3f49f3f4f6ce4a695cc1ac8b21 100644 (file)
@@ -308,6 +308,66 @@ typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_LOGICAL_16) gfc_array_l16;
 #define GFC_DESCRIPTOR_DATA(desc) ((desc)->data)
 #define GFC_DESCRIPTOR_DTYPE(desc) ((desc)->dtype)
 
+/* Macros to get both the size and the type with a single masking operation  */
+
+#define GFC_DTYPE_SIZE_MASK \
+  ((~((index_type) 0) >> GFC_DTYPE_SIZE_SHIFT) << GFC_DTYPE_SIZE_SHIFT)
+#define GFC_DTYPE_TYPE_SIZE_MASK (GFC_DTYPE_SIZE_MASK | GFC_DTYPE_TYPE_MASK)
+
+#define GFC_DTYPE_TYPE_SIZE(desc) ((desc)->dtype & GFC_DTYPE_TYPE_SIZE_MASK)
+
+#define GFC_DTYPE_INTEGER_1 ((GFC_DTYPE_INTEGER << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_INTEGER_1) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_INTEGER_2 ((GFC_DTYPE_INTEGER << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_INTEGER_2) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_INTEGER_4 ((GFC_DTYPE_INTEGER << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_INTEGER_4) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_INTEGER_8 ((GFC_DTYPE_INTEGER << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_INTEGER_8) << GFC_DTYPE_SIZE_SHIFT))
+#ifdef HAVE_GFC_INTEGER_16
+#define GFC_DTYPE_INTEGER_16 ((GFC_DTYPE_INTEGER << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_INTEGER_16) << GFC_DTYPE_SIZE_SHIFT))
+#endif
+
+#define GFC_DTYPE_LOGICAL_1 ((GFC_DTYPE_LOGICAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_LOGICAL_1) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_LOGICAL_2 ((GFC_DTYPE_LOGICAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_LOGICAL_2) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_LOGICAL_4 ((GFC_DTYPE_LOGICAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_LOGICAL_4) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_LOGICAL_8 ((GFC_DTYPE_LOGICAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_LOGICAL_8) << GFC_DTYPE_SIZE_SHIFT))
+#ifdef HAVE_GFC_LOGICAL_16
+#define GFC_DTYPE_LOGICAL_16 ((GFC_DTYPE_LOGICAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_LOGICAL_16) << GFC_DTYPE_SIZE_SHIFT))
+#endif
+
+#define GFC_DTYPE_REAL_4 ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_REAL_4) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_REAL_8 ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_REAL_8) << GFC_DTYPE_SIZE_SHIFT))
+#ifdef HAVE_GFC_REAL_10
+#define GFC_DTYPE_REAL_10  ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_REAL_10) << GFC_DTYPE_SIZE_SHIFT))
+#endif
+#ifdef HAVE_GFC_REAL_16
+#define GFC_DTYPE_REAL_16 ((GFC_DTYPE_REAL << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_REAL_16) << GFC_DTYPE_SIZE_SHIFT))
+#endif
+
+#define GFC_DTYPE_COMPLEX_4 ((GFC_DTYPE_COMPLEX << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_COMPLEX_4) << GFC_DTYPE_SIZE_SHIFT))
+#define GFC_DTYPE_COMPLEX_8 ((GFC_DTYPE_COMPLEX << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_COMPLEX_8) << GFC_DTYPE_SIZE_SHIFT))
+#ifdef HAVE_GFC_COMPLEX_10
+#define GFC_DTYPE_COMPLEX_10 ((GFC_DTYPE_COMPLEX << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_COMPLEX_10) << GFC_DTYPE_SIZE_SHIFT))
+#endif
+#ifdef HAVE_GFC_COMPLEX_16
+#define GFC_DTYPE_COMPLEX_16 ((GFC_DTYPE_COMPLEX << GFC_DTYPE_TYPE_SHIFT) \
+   | (sizeof(GFC_COMPLEX_16) << GFC_DTYPE_SIZE_SHIFT))
+#endif
+
 /* Runtime library include.  */
 #define stringize(x) expand_macro(x)
 #define expand_macro(x) # x
@@ -910,6 +970,142 @@ extern void unpack1_c16 (gfc_array_c16 *, const gfc_array_c16 *,
 internal_proto(unpack1_c16);
 #endif
 
+/* Helper functions for spread.  */
+
+extern void spread_i1 (gfc_array_i1 *, const gfc_array_i1 *,
+                      const index_type, const index_type);
+internal_proto(spread_i1);
+
+extern void spread_i2 (gfc_array_i2 *, const gfc_array_i2 *,
+                      const index_type, const index_type);
+internal_proto(spread_i2);
+
+extern void spread_i4 (gfc_array_i4 *, const gfc_array_i4 *,
+                      const index_type, const index_type);
+internal_proto(spread_i4);
+
+extern void spread_i8 (gfc_array_i8 *, const gfc_array_i8 *,
+                      const index_type, const index_type);
+internal_proto(spread_i8);
+
+#ifdef HAVE_GFC_INTEGER_16
+extern void spread_i16 (gfc_array_i16 *, const gfc_array_i16 *,
+                      const index_type, const index_type);
+internal_proto(spread_i16);
+
+#endif
+
+extern void spread_r4 (gfc_array_r4 *, const gfc_array_r4 *,
+                      const index_type, const index_type);
+internal_proto(spread_r4);
+
+extern void spread_r8 (gfc_array_r8 *, const gfc_array_r8 *,
+                      const index_type, const index_type);
+internal_proto(spread_r8);
+
+#ifdef HAVE_GFC_REAL_10
+extern void spread_r10 (gfc_array_r10 *, const gfc_array_r10 *,
+                      const index_type, const index_type);
+internal_proto(spread_r10);
+
+#endif
+
+#ifdef HAVE_GFC_REAL_16
+extern void spread_r16 (gfc_array_r16 *, const gfc_array_r16 *,
+                      const index_type, const index_type);
+internal_proto(spread_r16);
+
+#endif
+
+extern void spread_c4 (gfc_array_c4 *, const gfc_array_c4 *,
+                      const index_type, const index_type);
+internal_proto(spread_c4);
+
+extern void spread_c8 (gfc_array_c8 *, const gfc_array_c8 *,
+                      const index_type, const index_type);
+internal_proto(spread_c8);
+
+#ifdef HAVE_GFC_COMPLEX_10
+extern void spread_c10 (gfc_array_c10 *, const gfc_array_c10 *,
+                      const index_type, const index_type);
+internal_proto(spread_c10);
+
+#endif
+
+#ifdef HAVE_GFC_COMPLEX_16
+extern void spread_c16 (gfc_array_c16 *, const gfc_array_c16 *,
+                      const index_type, const index_type);
+internal_proto(spread_c16);
+
+#endif
+
+extern void spread_scalar_i1 (gfc_array_i1 *, const GFC_INTEGER_1 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_i1);
+
+extern void spread_scalar_i2 (gfc_array_i2 *, const GFC_INTEGER_2 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_i2);
+
+extern void spread_scalar_i4 (gfc_array_i4 *, const GFC_INTEGER_4 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_i4);
+
+extern void spread_scalar_i8 (gfc_array_i8 *, const GFC_INTEGER_8 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_i8);
+
+#ifdef HAVE_GFC_INTEGER_16
+extern void spread_scalar_i16 (gfc_array_i16 *, const GFC_INTEGER_16 *,
+                              const index_type, const index_type);
+internal_proto(spread_scalar_i16);
+
+#endif
+
+extern void spread_scalar_r4 (gfc_array_r4 *, const GFC_REAL_4 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_r4);
+
+extern void spread_scalar_r8 (gfc_array_r8 *, const GFC_REAL_8 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_r8);
+
+#ifdef HAVE_GFC_REAL_10
+extern void spread_scalar_r10 (gfc_array_r10 *, const GFC_REAL_10 *,
+                              const index_type, const index_type);
+internal_proto(spread_scalar_r10);
+
+#endif
+
+#ifdef HAVE_GFC_REAL_16
+extern void spread_scalar_r16 (gfc_array_r16 *, const GFC_REAL_16 *,
+                              const index_type, const index_type);
+internal_proto(spread_scalar_r16);
+
+#endif
+
+extern void spread_scalar_c4 (gfc_array_c4 *, const GFC_COMPLEX_4 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_c4);
+
+extern void spread_scalar_c8 (gfc_array_c8 *, const GFC_COMPLEX_8 *,
+                             const index_type, const index_type);
+internal_proto(spread_scalar_c8);
+
+#ifdef HAVE_GFC_COMPLEX_10
+extern void spread_scalar_c10 (gfc_array_c10 *, const GFC_COMPLEX_10 *,
+                              const index_type, const index_type);
+internal_proto(spread_scalar_c10);
+
+#endif
+
+#ifdef HAVE_GFC_COMPLEX_16
+extern void spread_scalar_c16 (gfc_array_c16 *, const GFC_COMPLEX_16 *,
+                              const index_type, const index_type);
+internal_proto(spread_scalar_c16);
+
+#endif
+
 /* string_intrinsics.c */
 
 extern int compare_string (GFC_INTEGER_4, const char *,
diff --git a/libgfortran/m4/spread.m4 b/libgfortran/m4/spread.m4
new file mode 100644 (file)
index 0000000..c301d1f
--- /dev/null
@@ -0,0 +1,279 @@
+`/* Special implementation of the SPREAD intrinsic
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
+   spread_generic.c written by Paul Brook <paul@nowt.org>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran 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 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Ligbfortran 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 libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "libgfortran.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>'
+
+include(iparm.m4)dnl
+
+`#if defined (HAVE_'rtype_name`)
+
+void
+spread_'rtype_code` ('rtype` *ret, const 'rtype` *source,
+                const index_type along, const index_type pncopies)
+{
+  /* r.* indicates the return array.  */
+  index_type rstride[GFC_MAX_DIMENSIONS];
+  index_type rstride0;
+  index_type rdelta = 0;
+  index_type rrank;
+  index_type rs;
+  'rtype_name` *rptr;
+  'rtype_name` *dest;
+  /* s.* indicates the source array.  */
+  index_type sstride[GFC_MAX_DIMENSIONS];
+  index_type sstride0;
+  index_type srank;
+  const 'rtype_name` *sptr;
+
+  index_type count[GFC_MAX_DIMENSIONS];
+  index_type extent[GFC_MAX_DIMENSIONS];
+  index_type n;
+  index_type dim;
+  index_type ncopies;
+
+  srank = GFC_DESCRIPTOR_RANK(source);
+
+  rrank = srank + 1;
+  if (rrank > GFC_MAX_DIMENSIONS)
+    runtime_error ("return rank too large in spread()");
+
+  if (along > rrank)
+      runtime_error ("dim outside of rank in spread()");
+
+  ncopies = pncopies;
+
+  if (ret->data == NULL)
+    {
+      /* The front end has signalled that we need to populate the
+        return array descriptor.  */
+      ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
+      dim = 0;
+      rs = 1;
+      for (n = 0; n < rrank; n++)
+       {
+         ret->dim[n].stride = rs;
+         ret->dim[n].lbound = 0;
+         if (n == along - 1)
+           {
+             ret->dim[n].ubound = ncopies - 1;
+             rdelta = rs;
+             rs *= ncopies;
+           }
+         else
+           {
+             count[dim] = 0;
+             extent[dim] = source->dim[dim].ubound + 1
+               - source->dim[dim].lbound;
+             sstride[dim] = source->dim[dim].stride;
+             rstride[dim] = rs;
+
+             ret->dim[n].ubound = extent[dim]-1;
+             rs *= extent[dim];
+             dim++;
+           }
+       }
+      ret->offset = 0;
+      if (rs > 0)
+        ret->data = internal_malloc_size (rs * sizeof('rtype_name`));
+      else
+       {
+         ret->data = internal_malloc_size (1);
+         return;
+       }
+    }
+  else
+    {
+      int zero_sized;
+
+      zero_sized = 0;
+
+      dim = 0;
+      if (GFC_DESCRIPTOR_RANK(ret) != rrank)
+       runtime_error ("rank mismatch in spread()");
+
+      if (compile_options.bounds_check)
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             index_type ret_extent;
+
+             ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+
+                 if (ret_extent != ncopies)
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent, (long int) ncopies);
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (ret_extent != extent[dim])
+                   runtime_error("Incorrect extent in return value of SPREAD"
+                                 " intrinsic in dimension %ld: is %ld,"
+                                 " should be %ld", (long int) n+1,
+                                 (long int) ret_extent,
+                                 (long int) extent[dim]);
+                   
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+      else
+       {
+         for (n = 0; n < rrank; n++)
+           {
+             if (n == along - 1)
+               {
+                 rdelta = ret->dim[n].stride;
+               }
+             else
+               {
+                 count[dim] = 0;
+                 extent[dim] = source->dim[dim].ubound + 1
+                   - source->dim[dim].lbound;
+                 if (extent[dim] <= 0)
+                   zero_sized = 1;
+                 sstride[dim] = source->dim[dim].stride;
+                 rstride[dim] = ret->dim[n].stride;
+                 dim++;
+               }
+           }
+       }
+
+      if (zero_sized)
+       return;
+
+      if (sstride[0] == 0)
+       sstride[0] = 1;
+    }
+  sstride0 = sstride[0];
+  rstride0 = rstride[0];
+  rptr = ret->data;
+  sptr = source->data;
+
+  while (sptr)
+    {
+      /* Spread this element.  */
+      dest = rptr;
+      for (n = 0; n < ncopies; n++)
+        {
+         *dest = *sptr;
+          dest += rdelta;
+        }
+      /* Advance to the next element.  */
+      sptr += sstride0;
+      rptr += rstride0;
+      count[0]++;
+      n = 0;
+      while (count[n] == extent[n])
+        {
+          /* When we get to the end of a dimension, reset it and increment
+             the next dimension.  */
+          count[n] = 0;
+          /* We could precalculate these products, but this is a less
+             frequently used path so probably not worth it.  */
+          sptr -= sstride[n] * extent[n];
+          rptr -= rstride[n] * extent[n];
+          n++;
+          if (n >= srank)
+            {
+              /* Break out of the loop.  */
+              sptr = NULL;
+              break;
+            }
+          else
+            {
+              count[n]++;
+              sptr += sstride[n];
+              rptr += rstride[n];
+            }
+        }
+    }
+}
+
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+void
+spread_scalar_'rtype_code` ('rtype` *ret, const 'rtype_name` *source,
+                       const index_type along, const index_type pncopies)
+{
+  int n;
+  int ncopies = pncopies;
+  'rtype_name` * dest;
+  index_type stride;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * sizeof ('rtype_name`));
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  dest = ret->data;
+  stride = ret->dim[0].stride;
+
+  for (n = 0; n < ncopies; n++)
+    {
+      *dest = *source;
+      dest += stride;
+    }
+}
+
+#endif
+'