Exemplo n.º 1
0
tree
create_cilk_function_exit (tree frame, bool detaches, bool needs_sync)
{
  tree epi = alloc_stmt_list ();

  if (needs_sync) 
    append_to_statement_list (build_cilk_sync (), &epi);
  tree func_ptr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
  tree pop_frame = build_call_expr (cilk_pop_fndecl, 1, func_ptr);
  tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, 0);
  tree current = cilk_arrow (worker, CILK_TI_WORKER_CUR, 0);
  tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
  tree set_current = build2 (MODIFY_EXPR, void_type_node, current, parent);
  append_to_statement_list (set_current, &epi);
  append_to_statement_list (pop_frame, &epi);
  tree call = build_call_expr (cilk_leave_fndecl, 1, func_ptr);
  if (!detaches)
    {
      tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
      tree flags_cmp_expr = fold_build2 (NE_EXPR, TREE_TYPE (flags), flags, 
					 build_int_cst (TREE_TYPE (flags), 
							CILK_FRAME_VERSION));
      call = fold_build3 (COND_EXPR, void_type_node, flags_cmp_expr,
			  call, build_empty_stmt (EXPR_LOCATION (flags)));
    }
  append_to_statement_list (call, &epi);  
  return epi;
}
Exemplo n.º 2
0
static tree
expand_cilk_sync (void)
{
  tree frame = cfun->cilk_frame_decl;

  /* Cilk_sync is converted to the following code:

     sf.pedigree = sf.worker->pedigree;
     if (frame.flags & CILK_FRAME_UNSYNCHED)
     {
        __cilkrts_save_fp_state (&sf);
        if (!builtin_setjmp (sf.ctx) 
	    __cilkrts_sync (&sf); 
	else 
	   if (sf.flags & CILK_FRAME_EXCEPTING) 
	     __cilkrts_rethrow (&sf); 
      }
      sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1;  */

  tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
  
  tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
				build_int_cst (TREE_TYPE (flags),
					       CILK_FRAME_UNSYNCHED));

  unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
			   build_int_cst (TREE_TYPE (unsynched), 0));

  tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);

  /* Check if exception (0x10) bit is set in the sf->flags.  */
  tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
				  build_int_cst (TREE_TYPE (flags),
						 CILK_FRAME_EXCEPTING));
  except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
			     build_int_cst (TREE_TYPE (except_flag), 0));

  /* If the exception flag is set then call the __cilkrts_rethrow (&sf).  */
  tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
				  build_call_expr (cilk_rethrow_fndecl, 1,
						   frame_addr),
				  build_empty_stmt (EXPR_LOCATION (unsynched)));
  
  tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
  tree setjmp_expr = cilk_call_setjmp (frame);
  setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
			     build_int_cst (TREE_TYPE (setjmp_expr), 0));
  
  setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
			     sync_expr, except_cond);
  tree sync_list = alloc_stmt_list ();
  append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
					     frame_addr), &sync_list);
  append_to_statement_list (setjmp_expr, &sync_list);
  tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
			   build_empty_stmt (EXPR_LOCATION (unsynched)));
  tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
  tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
  tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
  tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
				      parent_pedigree, worker_pedigree);
  tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree), 
			      CILK_TI_PEDIGREE_RANK, false);
  tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
				    w_ped_rank,
				    build_one_cst (TREE_TYPE (w_ped_rank)));
  incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
			       incr_ped_rank);
  tree ret_sync_exp = alloc_stmt_list ();
  append_to_statement_list (assign_pedigree, &ret_sync_exp);
  append_to_statement_list (sync, &ret_sync_exp);
  append_to_statement_list (incr_ped_rank, &ret_sync_exp);
  return ret_sync_exp;
}
Exemplo n.º 3
0
void
expand_builtin_cilk_detach (tree exp)
{
  rtx_insn *insn;
  tree fptr = get_frame_arg (exp);

  if (fptr == NULL_TREE)
    return;

  tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
  tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
  tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);

  rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
  if (GET_CODE (wreg) != REG)
    wreg = copy_to_reg (wreg);
  rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);

  /* TMP <- WORKER.TAIL
    *TMP <- PARENT
     TMP <- TMP + 1
     WORKER.TAIL <- TMP   */

  HOST_WIDE_INT worker_tail_offset =
    tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
    tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
    BITS_PER_UNIT;
  rtx tmem0 = gen_rtx_MEM (Pmode,
			   plus_constant (Pmode, wreg, worker_tail_offset));
  set_mem_attributes (tmem0, tail, 0);
  MEM_NOTRAP_P (tmem0) = 1;
  gcc_assert (MEM_VOLATILE_P (tmem0));
  rtx treg = copy_to_mode_reg (Pmode, tmem0);
  rtx tmem1 = gen_rtx_MEM (Pmode, treg);
  set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
  MEM_NOTRAP_P (tmem1) = 1;
  emit_move_insn (tmem1, preg);
  emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));

  /* There is a release barrier (st8.rel, membar #StoreStore,
     sfence, lwsync, etc.) between the two stores.  On x86
     normal volatile stores have proper semantics; the sfence
     would only be needed for nontemporal stores (which we
     could generate using the storent optab, for no benefit
     in this case).

     The predicate may return false even for a REG if this is
     the limited release operation that only stores 0.  */
  enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode); 
  if (icode != CODE_FOR_nothing
      && insn_data[icode].operand[1].predicate (treg, Pmode)
      && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
    emit_insn (insn);
  else
    emit_move_insn (tmem0, treg);

  /* The memory barrier inserted above should not prevent
     the load of flags from being moved before the stores,
     but in practice it does because it is implemented with
     unspec_volatile.  In-order RISC machines should
     explicitly load flags earlier.  */

  tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
  expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
		       build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
			       build_int_cst (TREE_TYPE (flags),
					      CILK_FRAME_DETACHED))),
	       const0_rtx, VOIDmode, EXPAND_NORMAL);
}