Bug 42484 - ICE with -fopenmp
Summary: ICE with -fopenmp
Status: RESOLVED DUPLICATE of bug 41344
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: ---
Assignee: janus
URL:
Keywords: ice-on-invalid-code, openmp
Depends on:
Blocks:
 
Reported: 2009-12-23 22:00 UTC by janus
Modified: 2009-12-28 21:41 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2009-12-27 15:57:18


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description janus 2009-12-23 22:00:24 UTC
Consider the following Fortran snippet:

  subroutine sub
    integer :: nRead
    !$omp critical
    if (nRead<3) return
    !$omp end critical
  end subroutine

Compiling this with "gfortran -fopenmp" results in a segfault (with 4.4.1 and current trunk on x86_64-unknown-linux-gnu). The backtrace is:

#0  0x0000000000a0abcc in main_block_label (label=0x7ffff7f64180) at /home/jweil/gcc45/trunk/gcc/tree-cfg.c:1064
#1  0x0000000000a0b157 in cleanup_dead_labels () at /home/jweil/gcc45/trunk/gcc/tree-cfg.c:1192
#2  0x0000000000a08f27 in build_gimple_cfg (seq=0x7ffff7f54600) at /home/jweil/gcc45/trunk/gcc/tree-cfg.c:201
#3  0x0000000000a08fd1 in execute_build_cfg () at /home/jweil/gcc45/trunk/gcc/tree-cfg.c:238
#4  0x0000000000907d9b in execute_one_pass (pass=0x16c4dc0) at /home/jweil/gcc45/trunk/gcc/passes.c:1556
#5  0x0000000000907f8f in execute_pass_list (pass=0x16c4dc0) at /home/jweil/gcc45/trunk/gcc/passes.c:1611
#6  0x0000000000a7fe21 in tree_lowering_passes (fn=0x7ffff7f63f00) at /home/jweil/gcc45/trunk/gcc/tree-optimize.c:364
#7  0x0000000000cc9f23 in cgraph_lower_function (node=0x7ffff7e7d4e0) at /home/jweil/gcc45/trunk/gcc/cgraphunit.c:499
#8  0x0000000000ccadf3 in cgraph_analyze_function (node=0x7ffff7e7d4e0) at /home/jweil/gcc45/trunk/gcc/cgraphunit.c:847
#9  0x0000000000ccb347 in cgraph_analyze_functions () at /home/jweil/gcc45/trunk/gcc/cgraphunit.c:979
#10 0x0000000000ccb7b8 in cgraph_finalize_compilation_unit () at /home/jweil/gcc45/trunk/gcc/cgraphunit.c:1084
#11 0x00000000008aa088 in write_global_declarations () at /home/jweil/gcc45/trunk/gcc/langhooks.c:309
#12 0x00000000009fe59d in compile_file () at /home/jweil/gcc45/trunk/gcc/toplev.c:1061
#13 0x0000000000a00775 in do_compile () at /home/jweil/gcc45/trunk/gcc/toplev.c:2387
#14 0x0000000000a0084b in toplev_main (argc=3, argv=0x7fffffffe2c8) at /home/jweil/gcc45/trunk/gcc/toplev.c:2429
#15 0x00000000005dbcac in main (argc=3, argv=0x7fffffffe2c8) at /home/jweil/gcc45/trunk/gcc/main.c:35
Comment 1 janus 2009-12-24 13:54:21 UTC
I think the example is valid. ifort and sunf95 accept it.
Comment 2 janus 2009-12-25 20:36:48 UTC
Sorry. Of course the code is *not* valid. Section 1.2.2 of the OpenMP 3.0 specification says: "The point of exit cannot be a branch out of the structured block."

Also, an analogous example in C is correctly rejected:

void sub ()
{
  int nRead;
  #pragma omp critical
  if (nRead<3) return;
}


In function ‘sub’:
error: invalid branch to/from an OpenMP structured block


So, I guess it is a problem of the Fortran front-end, which should detect this situation and reject the code.
Comment 3 janus 2009-12-26 20:11:18 UTC
There is a pass 'diagnose_omp_blocks', which generates the error message for the C code. Its execution function is 'diagnose_omp_structured_block_errors' in omp-low.x, which is correctly called also for Fortran code. However, the checks in 'diagnose_sb_0' and 'diagnose_sb_2' don't seem to work for the Fortran test case.

For the C code in comment #2, the GIMPLE_RETURN branch in diagnose_sb_2 is in effect and calls diagnose_sb_0, which throws the errror. For the Fortran case this does not work, since the RETURN is translated to a GOTO. However, GOTOs jumping out of an OMP CRITICAL section should also be rejected. (I still don't see where things go wrong.)
Comment 4 janus 2009-12-26 22:31:26 UTC
Here are test cases in Fortran and C, which both use GOTOs. Again, the Fortran code ICEs, while the C code gives an error message:


  subroutine sub
    integer :: nRead
    !$omp critical
    if (nRead<3) goto 100
    !$omp end critical
100 nRead=4
  end subroutine


void sub ()
{
  int nRead;
  #pragma omp critical
  if (nRead<3) goto out;
out: nRead=4;
}
Comment 5 janus 2009-12-26 22:46:49 UTC
For the Fortran test case in comment #4, diagnose_sb_2 (omp-low.c) is called six times, with the following statements:

* GIMPLE_BIND
* GIMPLE_OMP_CRITICAL
* GIMPLE_COND
* GIMPLE_LABEL
* GIMPLE_LABEL
* GIMPLE_ASSIGN

For the C case, it is called eight times:

* GIMPLE_BIND
* GIMPLE_OMP_CRITICAL
* GIMPLE_COND
* GIMPLE_LABEL
* GIMPLE_GOTO
* GIMPLE_LABEL
* GIMPLE_LABEL
* GIMPLE_ASSIGN

The question is why GIMPLE_GOTO is missing for the Fortran case?!?
Comment 6 janus 2009-12-27 11:38:21 UTC
One more observation: The Fortran test case works, with return as well as goto, giving the correct error message, if one removes the 'if' statement:

  subroutine sub
    !$omp critical
    return
    !$omp end critical
  end subroutine

"error: invalid branch to/from an OpenMP structured block"
Comment 7 janus 2009-12-27 12:53:58 UTC
Interestingly, the test case also works when using an 'if ... then ... end if' instead of a simple 'if':

  subroutine sub
    integer :: nRead
    !$omp critical
    if (nRead<3) then
      goto 100
    end if
    !$omp end critical
100 nRead=4
  end subroutine
Comment 8 janus 2009-12-27 13:05:43 UTC
The reason for the failure of comment #0 and #4 is that these cases run into the following optimization in gimplify_cond_expr (gimplify.c):

  if (TREE_OPERAND (expr, 1) != NULL
      && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
	  == current_function_decl)
      /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
	 have different locations, otherwise we end up with incorrect
	 location information on the branches.  */
      && (optimize
	  || !EXPR_HAS_LOCATION (expr)
	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
    {
      label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
      have_then_clause_p = true;
    }

Note that one only runs into this, if the locations of the IF condition and the THEN clause are the same, which is the case for the simple IF in Fortran, but not for IF...THEN...END IF statements. In C, the locations always seem to be different, also for the simple one-lined case.

So, I guess the solution is to apply different locations to the simple IF statement in Fortran.
Comment 9 janus 2009-12-27 15:57:18 UTC
Here is a patch which fixes the ICE, and gives the correct error messages:


Index: gcc/fortran/trans.c
===================================================================
--- gcc/fortran/trans.c (revision 155304)
+++ gcc/fortran/trans.c (working copy)
@@ -1043,7 +1043,9 @@ void
 gfc_set_backend_locus (locus * loc)
 {
   gfc_current_backend_file = loc->lb->file;
-  input_location = loc->lb->location;
+  /* 'loc->lb->location' only gives the location of the start of the line,
+     so we add the column number here.  */
+  input_location = loc->lb->location + loc->nextc - loc->lb->line;
 }


Index: gcc/fortran/match.c
===================================================================
--- gcc/fortran/match.c (revision 155304)
+++ gcc/fortran/match.c (working copy)
@@ -1602,7 +1602,7 @@ got_match:
   p = gfc_get_code ();
   p->next = gfc_get_code ();
   *p->next = new_st;
-  p->next->loc = gfc_current_locus;
+  p->next->loc = old_loc2;

   p->expr1 = expr;
   p->op = EXEC_IF;
Comment 10 janus 2009-12-28 21:41:20 UTC

*** This bug has been marked as a duplicate of 41344 ***