static tree trans_code (gfc_code * code, tree cond) { stmtblock_t block; tree res; if (!code) return build_empty_stmt (input_location); gfc_start_block (&block); /* Translate statements one by one into GENERIC trees until we reach the end of this gfc_code branch. */ for (; code; code = code->next) { if (code->here != 0) { res = gfc_trans_label_here (code); gfc_add_expr_to_block (&block, res); } gfc_set_backend_locus (&code->loc); switch (code->op) { case EXEC_NOP: case EXEC_END_BLOCK: case EXEC_END_NESTED_BLOCK: case EXEC_END_PROCEDURE: res = NULL_TREE; break; case EXEC_ASSIGN: if (code->expr1->ts.type == BT_CLASS) res = gfc_trans_class_assign (code->expr1, code->expr2, code->op); else res = gfc_trans_assign (code); break; case EXEC_LABEL_ASSIGN: res = gfc_trans_label_assign (code); break; case EXEC_POINTER_ASSIGN: if (code->expr1->ts.type == BT_CLASS) res = gfc_trans_class_assign (code->expr1, code->expr2, code->op); else res = gfc_trans_pointer_assign (code); break; case EXEC_INIT_ASSIGN: if (code->expr1->ts.type == BT_CLASS) res = gfc_trans_class_init_assign (code); else res = gfc_trans_init_assign (code); break; case EXEC_CONTINUE: res = NULL_TREE; break; case EXEC_CRITICAL: res = gfc_trans_critical (code); break; case EXEC_CYCLE: res = gfc_trans_cycle (code); break; case EXEC_EXIT: res = gfc_trans_exit (code); break; case EXEC_GOTO: res = gfc_trans_goto (code); break; case EXEC_ENTRY: res = gfc_trans_entry (code); break; case EXEC_PAUSE: res = gfc_trans_pause (code); break; case EXEC_STOP: case EXEC_ERROR_STOP: res = gfc_trans_stop (code, code->op == EXEC_ERROR_STOP); break; case EXEC_CALL: /* For MVBITS we've got the special exception that we need a dependency check, too. */ { bool is_mvbits = false; if (code->resolved_isym) { res = gfc_conv_intrinsic_subroutine (code); if (res != NULL_TREE) break; } if (code->resolved_isym && code->resolved_isym->id == GFC_ISYM_MVBITS) is_mvbits = true; res = gfc_trans_call (code, is_mvbits, NULL_TREE, NULL_TREE, false); } break; case EXEC_CALL_PPC: res = gfc_trans_call (code, false, NULL_TREE, NULL_TREE, false); break; case EXEC_ASSIGN_CALL: res = gfc_trans_call (code, true, NULL_TREE, NULL_TREE, false); break; case EXEC_RETURN: res = gfc_trans_return (code); break; case EXEC_IF: res = gfc_trans_if (code); break; case EXEC_ARITHMETIC_IF: res = gfc_trans_arithmetic_if (code); break; case EXEC_BLOCK: res = gfc_trans_block_construct (code); break; case EXEC_DO: res = gfc_trans_do (code, cond); break; case EXEC_DO_CONCURRENT: res = gfc_trans_do_concurrent (code); break; case EXEC_DO_WHILE: res = gfc_trans_do_while (code); break; case EXEC_SELECT: res = gfc_trans_select (code); break; case EXEC_SELECT_TYPE: /* Do nothing. SELECT TYPE statements should be transformed into an ordinary SELECT CASE at resolution stage. TODO: Add an error message here once this is done. */ res = NULL_TREE; break; case EXEC_FLUSH: res = gfc_trans_flush (code); break; case EXEC_SYNC_ALL: case EXEC_SYNC_IMAGES: case EXEC_SYNC_MEMORY: res = gfc_trans_sync (code, code->op); break; case EXEC_LOCK: case EXEC_UNLOCK: res = gfc_trans_lock_unlock (code, code->op); break; case EXEC_FORALL: res = gfc_trans_forall (code); break; case EXEC_WHERE: res = gfc_trans_where (code); break; case EXEC_ALLOCATE: res = gfc_trans_allocate (code); break; case EXEC_DEALLOCATE: res = gfc_trans_deallocate (code); break; case EXEC_OPEN: res = gfc_trans_open (code); break; case EXEC_CLOSE: res = gfc_trans_close (code); break; case EXEC_READ: res = gfc_trans_read (code); break; case EXEC_WRITE: res = gfc_trans_write (code); break; case EXEC_IOLENGTH: res = gfc_trans_iolength (code); break; case EXEC_BACKSPACE: res = gfc_trans_backspace (code); break; case EXEC_ENDFILE: res = gfc_trans_endfile (code); break; case EXEC_INQUIRE: res = gfc_trans_inquire (code); break; case EXEC_WAIT: res = gfc_trans_wait (code); break; case EXEC_REWIND: res = gfc_trans_rewind (code); break; case EXEC_TRANSFER: res = gfc_trans_transfer (code); break; case EXEC_DT_END: res = gfc_trans_dt_end (code); break; case EXEC_OMP_ATOMIC: case EXEC_OMP_BARRIER: case EXEC_OMP_CRITICAL: case EXEC_OMP_DO: case EXEC_OMP_FLUSH: case EXEC_OMP_MASTER: case EXEC_OMP_ORDERED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SINGLE: case EXEC_OMP_TASK: case EXEC_OMP_TASKWAIT: case EXEC_OMP_TASKYIELD: case EXEC_OMP_WORKSHARE: res = gfc_trans_omp_directive (code); break; default: internal_error ("gfc_trans_code(): Bad statement code"); } gfc_set_backend_locus (&code->loc); if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) { if (TREE_CODE (res) != STATEMENT_LIST) SET_EXPR_LOCATION (res, input_location); /* Add the new statement to the block. */ gfc_add_expr_to_block (&block, res); } } /* Return the finished block. */ return gfc_finish_block (&block); }
tree gfc_trans_code (gfc_code * code) { stmtblock_t block; tree res; if (!code) return build_empty_stmt (); gfc_start_block (&block); /* Translate statements one by one to GIMPLE trees until we reach the end of this gfc_code branch. */ for (; code; code = code->next) { if (code->here != 0) { res = gfc_trans_label_here (code); gfc_add_expr_to_block (&block, res); } switch (code->op) { case EXEC_NOP: res = NULL_TREE; break; case EXEC_ASSIGN: res = gfc_trans_assign (code); break; case EXEC_LABEL_ASSIGN: res = gfc_trans_label_assign (code); break; case EXEC_POINTER_ASSIGN: res = gfc_trans_pointer_assign (code); break; case EXEC_INIT_ASSIGN: res = gfc_trans_init_assign (code); break; case EXEC_CONTINUE: res = NULL_TREE; break; case EXEC_CYCLE: res = gfc_trans_cycle (code); break; case EXEC_EXIT: res = gfc_trans_exit (code); break; case EXEC_GOTO: res = gfc_trans_goto (code); break; case EXEC_ENTRY: res = gfc_trans_entry (code); break; case EXEC_PAUSE: res = gfc_trans_pause (code); break; case EXEC_STOP: res = gfc_trans_stop (code); break; case EXEC_CALL: res = gfc_trans_call (code, false); break; case EXEC_ASSIGN_CALL: res = gfc_trans_call (code, true); break; case EXEC_RETURN: res = gfc_trans_return (code); break; case EXEC_IF: res = gfc_trans_if (code); break; case EXEC_ARITHMETIC_IF: res = gfc_trans_arithmetic_if (code); break; case EXEC_DO: res = gfc_trans_do (code); break; case EXEC_DO_WHILE: res = gfc_trans_do_while (code); break; case EXEC_SELECT: res = gfc_trans_select (code); break; case EXEC_FLUSH: res = gfc_trans_flush (code); break; case EXEC_FORALL: res = gfc_trans_forall (code); break; case EXEC_WHERE: res = gfc_trans_where (code); break; case EXEC_ALLOCATE: res = gfc_trans_allocate (code); break; case EXEC_DEALLOCATE: res = gfc_trans_deallocate (code); break; case EXEC_OPEN: res = gfc_trans_open (code); break; case EXEC_CLOSE: res = gfc_trans_close (code); break; case EXEC_READ: res = gfc_trans_read (code); break; case EXEC_WRITE: res = gfc_trans_write (code); break; case EXEC_IOLENGTH: res = gfc_trans_iolength (code); break; case EXEC_BACKSPACE: res = gfc_trans_backspace (code); break; case EXEC_ENDFILE: res = gfc_trans_endfile (code); break; case EXEC_INQUIRE: res = gfc_trans_inquire (code); break; case EXEC_REWIND: res = gfc_trans_rewind (code); break; case EXEC_TRANSFER: res = gfc_trans_transfer (code); break; case EXEC_DT_END: res = gfc_trans_dt_end (code); break; case EXEC_OMP_ATOMIC: case EXEC_OMP_BARRIER: case EXEC_OMP_CRITICAL: case EXEC_OMP_DO: case EXEC_OMP_FLUSH: case EXEC_OMP_MASTER: case EXEC_OMP_ORDERED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SINGLE: case EXEC_OMP_WORKSHARE: res = gfc_trans_omp_directive (code); break; default: internal_error ("gfc_trans_code(): Bad statement code"); } gfc_set_backend_locus (&code->loc); if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) { if (TREE_CODE (res) == STATEMENT_LIST) annotate_all_with_locus (&res, input_location); else SET_EXPR_LOCATION (res, input_location); /* Add the new statement to the block. */ gfc_add_expr_to_block (&block, res); } } /* Return the finished block. */ return gfc_finish_block (&block); }
static tree gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) { tree res, tmp, stmt; stmtblock_t block, *pblock = NULL; stmtblock_t singleblock; int saved_ompws_flags; bool singleblock_in_progress = false; /* True if previous gfc_code in workshare construct is not workshared. */ bool prev_singleunit; code = code->block->next; pushlevel (0); if (!code) return build_empty_stmt (input_location); gfc_start_block (&block); pblock = █ ompws_flags = OMPWS_WORKSHARE_FLAG; prev_singleunit = false; /* Translate statements one by one to trees until we reach the end of the workshare construct. Adjacent gfc_codes that are a single unit of work are clustered and encapsulated in a single OMP_SINGLE construct. */ for (; code; code = code->next) { if (code->here != 0) { res = gfc_trans_label_here (code); gfc_add_expr_to_block (pblock, res); } /* No dependence analysis, use for clauses with wait. If this is the last gfc_code, use default omp_clauses. */ if (code->next == NULL && clauses->nowait) ompws_flags |= OMPWS_NOWAIT; /* By default, every gfc_code is a single unit of work. */ ompws_flags |= OMPWS_CURR_SINGLEUNIT; ompws_flags &= ~OMPWS_SCALARIZER_WS; switch (code->op) { case EXEC_NOP: res = NULL_TREE; break; case EXEC_ASSIGN: res = gfc_trans_assign (code); break; case EXEC_POINTER_ASSIGN: res = gfc_trans_pointer_assign (code); break; case EXEC_INIT_ASSIGN: res = gfc_trans_init_assign (code); break; case EXEC_FORALL: res = gfc_trans_forall (code); break; case EXEC_WHERE: res = gfc_trans_where (code); break; case EXEC_OMP_ATOMIC: res = gfc_trans_omp_directive (code); break; case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_CRITICAL: saved_ompws_flags = ompws_flags; ompws_flags = 0; res = gfc_trans_omp_directive (code); ompws_flags = saved_ompws_flags; break; default: internal_error ("gfc_trans_omp_workshare(): Bad statement code"); } gfc_set_backend_locus (&code->loc); if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) { if (prev_singleunit) { if (ompws_flags & OMPWS_CURR_SINGLEUNIT) /* Add current gfc_code to single block. */ gfc_add_expr_to_block (&singleblock, res); else { /* Finish single block and add it to pblock. */ tmp = gfc_finish_block (&singleblock); tmp = build2 (OMP_SINGLE, void_type_node, tmp, NULL_TREE); gfc_add_expr_to_block (pblock, tmp); /* Add current gfc_code to pblock. */ gfc_add_expr_to_block (pblock, res); singleblock_in_progress = false; } } else { if (ompws_flags & OMPWS_CURR_SINGLEUNIT) { /* Start single block. */ gfc_init_block (&singleblock); gfc_add_expr_to_block (&singleblock, res); singleblock_in_progress = true; } else /* Add the new statement to the block. */ gfc_add_expr_to_block (pblock, res); } prev_singleunit = (ompws_flags & OMPWS_CURR_SINGLEUNIT) != 0; } } /* Finish remaining SINGLE block, if we were in the middle of one. */ if (singleblock_in_progress) { /* Finish single block and add it to pblock. */ tmp = gfc_finish_block (&singleblock); tmp = build2 (OMP_SINGLE, void_type_node, tmp, clauses->nowait ? build_omp_clause (input_location, OMP_CLAUSE_NOWAIT) : NULL_TREE); gfc_add_expr_to_block (pblock, tmp); } stmt = gfc_finish_block (pblock); if (TREE_CODE (stmt) != BIND_EXPR) { if (!IS_EMPTY_STMT (stmt)) { tree bindblock = poplevel (1, 0, 0); stmt = build3_v (BIND_EXPR, NULL, stmt, bindblock); } else poplevel (0, 0, 0); } else poplevel (0, 0, 0); ompws_flags = 0; return stmt; }