> -----Original Message-----
> From: Richard Biener <richard.guent...@gmail.com>
> Sent: Monday, July 29, 2024 7:18 PM
> To: Prathamesh Kulkarni <prathame...@nvidia.com>
> Cc: gcc@gcc.gnu.org
> Subject: Re: [RFC] Summary of libgomp failures for offloading to nvptx
> from AArch64
> 
> External email: Use caution opening links or attachments
> 
> 
> On Mon, Jul 29, 2024 at 1:35 PM Prathamesh Kulkarni
> <prathame...@nvidia.com> wrote:
> >
> >
> >
> > > -----Original Message-----
> > > From: Richard Biener <richard.guent...@gmail.com>
> > > Sent: Friday, July 26, 2024 6:51 PM
> > > To: Prathamesh Kulkarni <prathame...@nvidia.com>
> > > Cc: gcc@gcc.gnu.org
> > > Subject: Re: [RFC] Summary of libgomp failures for offloading to
> > > nvptx from AArch64
> > >
> > > External email: Use caution opening links or attachments
> > >
> > >
> > > On Thu, Jul 25, 2024 at 3:36 PM Prathamesh Kulkarni via Gcc
> > > <gcc@gcc.gnu.org> wrote:
> > > >
> > > > Hi,
> > > > I am working on enabling offloading to nvptx from AAarch64 host.
> > > > As mentioned on wiki
> > > > (https://gcc.gnu.org/wiki/Offloading#Running_.27make_check.27),
> > > > I ran make check-target-libgomp on AAarch64 host (and no GPU)
> with
> > > following results:
> > > >
> > > >                 === libgomp Summary ===
> > > >
> > > > # of expected passes            14568
> > > > # of unexpected failures        1023
> > > > # of expected failures          309
> > > > # of untested testcases         54
> > > > # of unresolved testcases       992
> > > > # of unsupported tests          644
> > > >
> > > > It seems majority of the tests fail due to the following 4
> issues:
> > > >
> > > > * Compiling a minimal test-case:
> > > >
> > > > int main()
> > > > {
> > > >   int x;
> > > >   #pragma omp target map (to: x)
> > > >   {
> > > >     x = 0;
> > > >   }
> > > >   return x;
> > > > }
> > > >
> > > > Compiling with -fopenmp -foffload=nvptx-none results in
> following
> > > issues:
> > > >
> > > > (1) Differing values of NUM_POLY_INT_COEFFS between host and
> > > accelerator, which results in following ICE:
> > > >
> > > > 0x1a6e0a7 pp_quoted_string
> > > >         ../../gcc/gcc/pretty-print.cc:2277
> > > >  0x1a6ffb3 pp_format(pretty_printer*, text_info*, urlifier
> const*)
> > > >         ../../gcc/gcc/pretty-print.cc:1634
> > > >  0x1a4a3f3
> diagnostic_context::report_diagnostic(diagnostic_info*)
> > > >         ../../gcc/gcc/diagnostic.cc:1612
> > > >  0x1a4a727 diagnostic_impl
> > > >         ../../gcc/gcc/diagnostic.cc:1775  0x1a4e20b
> > > > fatal_error(unsigned int, char const*, ...)
> > > >         ../../gcc/gcc/diagnostic.cc:2218  0xb3088f
> > > > lto_input_mode_table(lto_file_decl_data*)
> > > >          ../../gcc/gcc/lto-streamer-in.cc:2121
> > > >  0x6f5cdf lto_file_finalize
> > > >         ../../gcc/gcc/lto/lto-common.cc:2285
> > > >  0x6f5cdf lto_create_files_from_ids
> > > >         ../../gcc/gcc/lto/lto-common.cc:2309
> > > >  0x6f5cdf lto_file_read
> > > >         ../../gcc/gcc/lto/lto-common.cc:2364
> > > >  0x6f5cdf read_cgraph_and_symbols(unsigned int, char const**)
> > > >         ../../gcc/gcc/lto/lto-common.cc:2812
> > > >  0x6cfb93 lto_main()
> > > >         ../../gcc/gcc/lto/lto.cc:658
> > > >
> > > > This is already tracked in https://gcc.gnu.org/PR96265 (and
> > > > related
> > > > PR's)
> > > >
> > > > Streaming out mode_table:
> > > > mode = SI, mclass = 2, size = 4, prec = 32 mode = DI, mclass =
> 2,
> > > size
> > > > = 8, prec = 64
> > > >
> > > > Streaming in mode_table (in lto_input_mode_table):
> > > > mclass = 2, size = 4, prec = 0
> > > > (and then calculates the correct mode value by iterating over
> all
> > > > modes of mclass starting from narrowest mode)
> > > >
> > > > The issue is that the value for prec is not getting streamed-in
> > > > correctly for SImode as seen above. While streaming out from
> > > > AArch64
> > > host, it is 32, but while streaming in for nvptx, it is 0. This
> > > happens because of differing values of NUM_POLY_INT_COEFFS between
> > > AArch64 and nvptx backend.
> > > >
> > > > Since NUM_POLY_INT_COEFFS is 2 for aarch64, the streamed-out
> > > > values for mode, precision would be <4, 0> and <32, 0>
> > > > respectively (streamed-out in bp_pack_poly_value). Both zeros
> come
> > > > from coeffs[1] of size and prec. While streaming in however,
> > > > NUM_POLY_INT_COEFFS is
> > > 1 for nvptx, and thus it incorrectly treats <4, 0> as size and
> > > precision respectively, which is why precision gets streamed in as
> > > 0, and thus it encounters the above ICE.
> > > >
> > > > Supporting non VLA code with offloading:
> > > >
> > > > In the general case, it's hard to support offloading for
> arbitrary
> > > poly_ints when NUM_POLY_INT_COEFFS differs for host and
> accelerator.
> > > > For example, it's not possible to represent a degree-2 poly_int
> > > > like
> > > 4 + 4x (as-is) on an accelerator with NUM_POLY_INT_COEFFS == 1.
> > > >
> > > > However, IIUC, we can support offloading for restricted set of
> > > > poly_ints whose degree <= accel's NUM_POLY_INT_COEFFS, since
> they
> > > can
> > > > be represented on accelerator ? For a hypothetical example, if
> > > > host
> > > NUM_POLY_INT_COEFFS == 3 and accel NUM_POLY_INT_COEFFS == 2, then
> I
> > > suppose we could represent a degree 2 poly_int on accelerator, but
> > > not a degree 3 poly_int like 3+4x+5x^2 ?
> > > >
> > > > Based on that, I have come up with following approach in
> attached
> > > "quick-and-dirty" patch (p-163-2.diff):
> > > > Stream-out host NUM_POLY_INT_COEFFS, and while streaming-in
> during
> > > lto1, compare it with accelerator's NUM_POLY_INT_COEFFS as
> follows:
> > > >
> > > > Stream in host_num_poly_int_coeffs; if (host_num_poly_int_coeffs
> > > > == NUM_POLY_INT_COEFFS) //
> > > NUM_POLY_INT_COEFFS represents accelerator's value here.
> > > > {
> > > >     /* Both are equal, proceed to unpacking NUM_POLY_INT_COEFFS
> > > words
> > > > from bitstream.  */ } else if (host_num_poly_int_coeffs <
> > > > NUM_POLY_INT_COEFFS) {
> > > >     /* Unpack host_num_poly_int_coeffs words and zero out
> > > > remaining higher coeffs (similar to zero-extension).  */ } else
> {
> > > >     /* Unpack host_num_poly_int_coeffs words and ensure that
> > > > degree
> > > of
> > > > streamed-out poly_int <= NUM_POLY_INT_COEFFS.  */ }
> > > >
> > > > For example, with host NUM_POLY_INT_COEFFS == 2 and accel
> > > > NUM_POLY_INT_COEFFS == 1, this will allow streaming of "degree-
> 1"
> > > poly_ints like 4+0x (which will degenerate to constant 4), but
> give
> > > an error for streaming degree-2 poly_int like 4+4x.
> > > >
> > > > Following this approach, I am assuming we can support
> > > > AArch64/nvptx offloading for non VLA code, since poly_ints used
> > > > for representing various artefacts like mode_size,
> mode_precision, vector length etc.
> > > will be degree-1 poly_int for scalar variables and fixed-length
> > > vectors (and thus degenerate to constants). With the patch
> applied,
> > > it proceeds forward from this point, but fails at a later stage
> (see
> > > below).
> > > >
> > > > Does this approach look reasonable for supporting offloading for
> > > > non
> > > VLA code ?
> > > > Are there any cases I may have overlooked, where offloading will
> > > still fail for non-VLA code due to differing NUM_POLY_INT_COEFFS
> > > issue ?
> > >
> > > I think I'd change how we stream POLY_INTs and make that
> "independent"
> > > of NUM_POLY_INT_COEFFS
> > > in that I'd stream the effective number of coeffs required - as
> you
> > > suggest "trailing" zero coeffs do not need to be represented.  We
> > > always stream coeff zero.
> > >
> > > On read in when that N is bigger than NUM_POLY_INT_COEFFS we have
> to
> > > error and we zero-fill extra elements (using the type of coeff
> zero).
> > >
> > > > (2) nvptx mkoffload.cc passes -m64/-m32 to host compiler if
> > > > -foffload-abi=lp64/ilp32 After applying workaround for the above
> > > assertion failure, it hits the following error:
> > > > gcc: error: unrecognized command-line option '-m64'
> > > > nvptx mkoffload: fatal error: ../install/bin/gcc returned 1 exit
> > > > status compilation terminated.
> > > >
> > > > This happens because nvptx/mkoffload.cc:compile_native passes
> > > > -m64/-m32 to host compiler depending on whether offload_abi is
> > > OFFLOAD_ABI_LP64 or OFFLOAD_ABI_ILP32, and aarch64 backend doesn't
> > > recognize these options.
> > > >
> > > > I suppose a simple solution to check if host_compiler supports a
> > > > particular command-line option, would be to create a dummy C
> file
> > > and
> > > > check if the command "host_compiler <opt> dummy_file.c" returns
> > > > zero
> > > exit status. Alternative could be to check exit status for
> > > "host_compiler <opt> --version", once http://gcc.gnu.org/PR116050
> is
> > > fixed, but I am not sure if either is an ideal solution.
> > >
> > > I think an explicit configure when building the offload compiler
> > > would be cleaner, like simply adding an additional
> > > AC_SUBST(host_no_multilibs) var computed from the --enable-as-
> > > accelerator-for target triplet?
> > >
> > > > With workarounds for these 2 issues, the minimal test builds and
> > > runs successfully.
> > > >
> > > > (3) Assertion error in lto_read_decls during lto1:
> > > > There are several failures (~350+) in the testsuite caused due
> to
> > > the
> > > > following assert in lto_read_decls:
> > > > gcc_assert (data_in->reader_cache->nodes.length () == from + 1);
> > > >
> > > > AFAIU, this seems to happen because of presence of LTO_null tag.
> > > > The following workaround avoids hitting the assert, but am not
> > > > sure if
> > > it's the right fix:
> > > >
> > > >         t = lto_input_tree_1 (&ib_main, data_in, tag, 0);
> > > > +       if (t == NULL_TREE)
> > > > +         continue;
> > > >         gcc_assert (data_in->reader_cache->nodes.length () ==
> from
> > > > + 1);
> > > >
> > > > (FWIW, this was reproducible with the above minimal test, but
> has
> > > > seemingly gone away for it after updating the sources recently,
> > > > but still reproduces with libgomp tests like for-9.c, baseptrs-
> 4.C
> > > > etc.)
> > >
> > > It looks like a discrepancy between host and target that wasn't
> > > properly analyzed to me.  The assert makes sure we read the
> expected
> > > number of tree nodes - what's the tag when you hit this?
> > > Please open a bug.
> > Sure, will do shortly.
> >
> > I checked with for-9.c, and it shows the following state on hitting
> the assert:
> > reader_cache->nodes.length () = 2384, from+1 = 2385, tag: LTO_null
> >
> > From lto_read_decls:
> >       unsigned from = data_in->reader_cache->nodes.length ();
> >       /* Read and uniquify SCCs as in the input stream.  */
> >       enum LTO_tags tag = streamer_read_record_start (&ib_main);
> >       if (tag == LTO_tree_scc || tag == LTO_trees)
> >
> > In this case, tag is LTO_null, and it skips to the else part:
> >       t = lto_input_tree_1 (&ib_main, data_in, tag, 0);
> >       gcc_assert (data_in->reader_cache->nodes.length () == from +
> 1);
> >
> > and lto_input_tree_1 simply returns NULL_TREE if tag is LTO_null
> without any additional streaming-in.
> > So IIUC, data_in->reader_cache->nodes.length () won't change since
> > there is no tree node streamed in lto_input_tree_1, and thus
> reader_cache->length() remains equal to from (rather than from + 1),
> which triggers the assert ?
> 
> Interesting.  The thing is that we don't expect LTO_null when
> streaming in global decls and types - we wouldn't have streamed a NULL
> decl or type.  So can you debug this on the writer side and see where
> we stream such?
Hi Richard,
Sorry for late response.

The ICE can also be reproduced with an even simpler test-case:

int main()
{
  int x;
  #pragma omp target map(x)
    x;
}

Compiling with -O3 -fopenmp -foffload=nvptx-none hits the same assert in 
lto_read_decls.

I think the issue here possibly is corrupted streaming of optimization_node, due
to presence of AArch64 specific optimization options in LTO bytecode.

From AArch64 cl_optimization_stream_out:

  bp_pack_var_len_int (bp, ptr->x_flag_wrapv_pointer);
  bp_pack_var_len_int (bp, ptr->x_debug_nonbind_markers_p);

  bp_pack_var_len_int (bp, ptr->x_flag_aarch64_early_ldp_fusion);
  bp_pack_var_len_int (bp, ptr->x_aarch64_early_ra);
  bp_pack_var_len_int (bp, ptr->x_flag_aarch64_late_ldp_fusion);
  bp_pack_var_len_int (bp, ptr->x_flag_mlow_precision_div);
  bp_pack_var_len_int (bp, ptr->x_flag_mrecip_low_precision_sqrt);
  bp_pack_var_len_int (bp, ptr->x_flag_mlow_precision_sqrt);

  for (size_t i = 0; i < ARRAY_SIZE (ptr->explicit_mask); i++)
    bp_pack_value (bp, ptr->explicit_mask[i], 64);

And nvptx cl_optimization_stream_in:

  ptr->x_flag_wrapv_pointer = (signed char ) bp_unpack_var_len_int (bp);
  ptr->x_debug_nonbind_markers_p = (signed char ) bp_unpack_var_len_int (bp);
  for (size_t i = 0; i < ARRAY_SIZE (ptr->explicit_mask); i++)
    ptr->explicit_mask[i] = bp_unpack_value (bp, 64);

While AArch64 host streams out target-specific opts like 
flag_aarch64_early_ldp_fusion, aarch64_early_ra etc., there's no corresponding
stream-in for these options for nvptx. And will thus result in invalid 
streaming-in for ptr->explicit_mask (and subsequent data structures).

To verify if this was indeed the cause of failure, I (temporarily) changed 
options in aarch64.opt marked with Optimization
to Save, and verified that AArch64 cl_optimization_stream_out matches with 
nvptx cl_optimization_stream_in,
which prevents the above ICE.

FWIW, x86_64 cl_optimization_stream_out also similarly streams out 
ix86_unroll_only_small_loops:

  bp_pack_var_len_int (bp, ptr->x_flag_wrapv_pointer);
  bp_pack_var_len_int (bp, ptr->x_debug_nonbind_markers_p);
  bp_pack_var_len_int (bp, ptr->x_ix86_unroll_only_small_loops);
  for (size_t i = 0; i < ARRAY_SIZE (ptr->explicit_mask); i++)
    bp_pack_value (bp, ptr->explicit_mask[i], 64);

which I suppose can cause similar streaming issues ?

This change was introduced recently in:
https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a59c4e496fa916cb9a484a649aa1b4cebd6550f2

Which perhaps explains recent failures I am seeing in libgomp tests for 
x86_64->nvptx offloading:

FAIL: libgomp.fortran/target-print-1.f90   -O2  (internal compiler error: in 
lto_read_decls, at lto/lto-common.cc:1970)
FAIL: libgomp.oacc-c++/../libgomp.oacc-c-c++-common/private-variables.c 
-DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  
(internal compiler error: in lto_read_decls, at lto/lto-common.cc:1970)
FAIL: libgomp.oacc-c/../libgomp.oacc-c-c++-common/private-variables.c 
-DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  
(internal compiler error: in lto_read_decls, at lto/lto-common.cc:1970)
FAIL: libgomp.oacc-fortran/print-1-nvptx.f90 -DACC_DEVICE_TYPE_nvidia=1 
-DACC_MEM_SHARED=0 -foffload=nvptx-none  -O2  (internal compiler error: in 
lto_read_decls, at lto/lto-common.cc:1970)

Thanks,
Prathamesh
> 
> Richard.
> 
> > >
> > > >
> > > > (4) AAarch64 uses OImode for 256-bit size array, which is not
> > > supported on nvptx:
> > > > This causes ~18 tests to fail.
> > > >
> > > > Can be reproduced with following simple test:
> > > > int main()
> > > > {
> > > >   long c[4];
> > > >   #pragma omp target map(c)
> > > >     c[0] = 0;
> > > >   return 0;
> > > > }
> > > >
> > > > Compiling with -O2 -fopenmp -foffload=nvptx-none results in:
> > > > lto1: fatal error: nvptx-none - 256-bit integer numbers
> > > > unsupported (mode 'OI') compilation terminated.
> > > > nvptx mkoffload: fatal error:
> > > > ../install/bin/aarch64-unknown-linux-gnu-accel-nvptx-none-gcc
> > > returned 1 exit status compilation terminated.
> > > >
> > > > This happens with AArch64 host because, it uses OImode (256-bit
> > > > integer mode) for ARRAY_TYPE (long c[4] fits 256-bits), which
> > > > isn't supported on nvptx. This decision is made during
> layout_type
> > > > for
> > > 'c', which calls mode_for_array, and mode_for_array uses target
> > > hooks array_mode and array_mode_supported_p to determine
> > > target-specific modes to use for ARRAY_TYPE.
> > > > For x86_64, AFAIK, it uses BLKmode for ARRAY_TYPE.
> > > >
> > > > I have attached a "quick-and-dirty" patch (p-166-2.diff) which
> > > > falls back to using BLKmode for ARRAY_TYPE if offloading is
> > > > enabled, and avoids streaming-out target-specific int modes in
> > > > lto_write_mode_table. I used default_scalar_mode_supported_p
> check
> > > to test if the int_mode is "generic", but not sure if that's
> > > entirely correct. The test compiles and runs OK with patch
> applied.
> > > I suppose a more general solution would be to somehow "intersect"
> > > available
> > > AArch64 modes with nvptx modes, and use those for offloading ?
> > >
> > > Hmm, I think we shouldn't stream modes for aggregates but instead
> > > let stor-layout re-assign them.  They are not usually expected to
> match.
> > > Not sure if we should do that generally or only for offload
> > > streaming though (it does have an overhead to recompute the mode).
> > > We could stream VOIDmode here as indicator it needs recomputation
> > > (splitting out sub-workers from layout_type, there's one already
> for
> > > record type).
> > Thanks, this indeed sounds better. I will try to work on patch
> following this approach.
> >
> > Thanks,
> > Prathamesh
> > >
> > > > With local workarounds for the above 4 issues, running make
> check-
> > > target-libgomp shows following results:
> > > >
> > > >                 === libgomp Summary ===
> > > >
> > > > # of expected passes            16604
> > > > # of unexpected failures        10
> > > > # of expected failures          309
> > > > # of untested testcases         54
> > > > # of unresolved testcases       3
> > > > # of unsupported tests          643
> > > >
> > > > The remaining issues are:
> > > >
> > > > (5) "error: alias definitions not supported in this
> configuration"
> > > > Fails for pr96390.c, and pr96390.C. This seems to be related to
> > > > https://gcc.gnu.org/PR97102
> > > >
> > > > (6) Execution Failures:
> > > > - libgomp/pr104783.c
> > > > - libgomp/pr104783-2.c
> > > > I haven't investigated these yet.
> > > >
> > > > (7) Several warnings fail for libgomp.oacc-c-c++-
> common/acc_prof-
> > > kernels-1.c and following excess errors:
> > > > acc_prof-kernels-1.c:185:9: optimized: assigned OpenACC seq loop
> > > > parallelism
> > > > acc_prof-kernels-1.c:214:9: optimized: assigned OpenACC seq loop
> > > > parallelism
> > > > acc_prof-kernels-1.c:245:9: optimized: assigned OpenACC seq loop
> > > > parallelism
> > > >
> > > > So far, I have only been testing make check-target-libgomp.
> Should
> > > > I
> > > be testing any additional parts of the testsuite for offloading
> > > changes ?
> > > >
> > > > My initial goals are:
> > > > (a) To get AArch64/nvptx offloading to work for above minimal
> test.
> > > > (b) Testsuite results for libgomp on par with x86_64 for non VLA
> > > code (as far as correctness is concerned).
> > > > (c) After (a) and (b) are in place, try to enable support for
> > > offloading with VLA/SVE.
> > > >
> > > > I am planning to address these issues and will post patches for
> > > > the
> > > same shortly. I will be grateful for any feedback or suggestions
> on
> > > how to proceed forward.
> > > >
> > > > Thanks,
> > > > Prathamesh

Reply via email to