trans-intrinsic.c

来自「gcc-fortran,linux使用fortran的编译软件。很好用的。」· C语言 代码 · 共 2,433 行 · 第 1/5 页

C
2,433
字号
    tmp = gfc_build_const (type, integer_zero_node);  else    tmp = gfc_build_const (type, integer_one_node);  gfc_add_modify_expr (&se->pre, resvar, tmp);  /* Walk the arguments.  */  actual = expr->value.function.actual;  arrayexpr = actual->expr;  arrayss = gfc_walk_expr (arrayexpr);  gcc_assert (arrayss != gfc_ss_terminator);  actual = actual->next->next;  gcc_assert (actual);  maskexpr = actual->expr;  if (maskexpr)    {      maskss = gfc_walk_expr (maskexpr);      gcc_assert (maskss != gfc_ss_terminator);    }  else    maskss = NULL;  /* Initialize the scalarizer.  */  gfc_init_loopinfo (&loop);  gfc_add_ss_to_loop (&loop, arrayss);  if (maskss)    gfc_add_ss_to_loop (&loop, maskss);  /* Initialize the loop.  */  gfc_conv_ss_startstride (&loop);  gfc_conv_loop_setup (&loop);  gfc_mark_ss_chain_used (arrayss, 1);  if (maskss)    gfc_mark_ss_chain_used (maskss, 1);  /* Generate the loop body.  */  gfc_start_scalarized_body (&loop, &body);  /* If we have a mask, only add this element if the mask is set.  */  if (maskss)    {      gfc_init_se (&maskse, NULL);      gfc_copy_loopinfo_to_se (&maskse, &loop);      maskse.ss = maskss;      gfc_conv_expr_val (&maskse, maskexpr);      gfc_add_block_to_block (&body, &maskse.pre);      gfc_start_block (&block);    }  else    gfc_init_block (&block);  /* Do the actual summation/product.  */  gfc_init_se (&arrayse, NULL);  gfc_copy_loopinfo_to_se (&arrayse, &loop);  arrayse.ss = arrayss;  gfc_conv_expr_val (&arrayse, arrayexpr);  gfc_add_block_to_block (&block, &arrayse.pre);  tmp = build2 (op, type, resvar, arrayse.expr);  gfc_add_modify_expr (&block, resvar, tmp);  gfc_add_block_to_block (&block, &arrayse.post);  if (maskss)    {      /* We enclose the above in if (mask) {...} .  */      tmp = gfc_finish_block (&block);      tmp = build3_v (COND_EXPR, maskse.expr, tmp, build_empty_stmt ());    }  else    tmp = gfc_finish_block (&block);  gfc_add_expr_to_block (&body, tmp);  gfc_trans_scalarizing_loops (&loop, &body);  gfc_add_block_to_block (&se->pre, &loop.pre);  gfc_add_block_to_block (&se->pre, &loop.post);  gfc_cleanup_loop (&loop);  se->expr = resvar;}static voidgfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, int op){  stmtblock_t body;  stmtblock_t block;  stmtblock_t ifblock;  tree limit;  tree type;  tree tmp;  tree ifbody;  tree cond;  gfc_loopinfo loop;  gfc_actual_arglist *actual;  gfc_ss *arrayss;  gfc_ss *maskss;  gfc_se arrayse;  gfc_se maskse;  gfc_expr *arrayexpr;  gfc_expr *maskexpr;  tree pos;  int n;  if (se->ss)    {      gfc_conv_intrinsic_funcall (se, expr);      return;    }  /* Initialize the result.  */  pos = gfc_create_var (gfc_array_index_type, "pos");  type = gfc_typenode_for_spec (&expr->ts);  /* Walk the arguments.  */  actual = expr->value.function.actual;  arrayexpr = actual->expr;  arrayss = gfc_walk_expr (arrayexpr);  gcc_assert (arrayss != gfc_ss_terminator);  actual = actual->next->next;  gcc_assert (actual);  maskexpr = actual->expr;  if (maskexpr)    {      maskss = gfc_walk_expr (maskexpr);      gcc_assert (maskss != gfc_ss_terminator);    }  else    maskss = NULL;  limit = gfc_create_var (gfc_typenode_for_spec (&arrayexpr->ts), "limit");  n = gfc_validate_kind (arrayexpr->ts.type, arrayexpr->ts.kind, false);  switch (arrayexpr->ts.type)    {    case BT_REAL:      tmp = gfc_conv_mpfr_to_tree (gfc_real_kinds[n].huge, arrayexpr->ts.kind);      break;    case BT_INTEGER:      tmp = gfc_conv_mpz_to_tree (gfc_integer_kinds[n].huge,				  arrayexpr->ts.kind);      break;    default:      gcc_unreachable ();    }  /* Most negative(+HUGE) for maxval, most negative (-HUGE) for minval.  */  if (op == GT_EXPR)    tmp = fold_build1 (NEGATE_EXPR, TREE_TYPE (tmp), tmp);  gfc_add_modify_expr (&se->pre, limit, tmp);  /* Initialize the scalarizer.  */  gfc_init_loopinfo (&loop);  gfc_add_ss_to_loop (&loop, arrayss);  if (maskss)    gfc_add_ss_to_loop (&loop, maskss);  /* Initialize the loop.  */  gfc_conv_ss_startstride (&loop);  gfc_conv_loop_setup (&loop);  gcc_assert (loop.dimen == 1);  /* Initialize the position to the first element.  If the array has zero     size we need to return zero.  Otherwise use the first element of the     array, in case all elements are equal to the limit.     i.e. pos = (ubound >= lbound) ? lbound, lbound - 1;  */  tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,		     loop.from[0], gfc_index_one_node);  cond = fold_build2 (GE_EXPR, boolean_type_node,		      loop.to[0], loop.from[0]);  tmp = fold_build3 (COND_EXPR, gfc_array_index_type, cond,		     loop.from[0], tmp);  gfc_add_modify_expr (&loop.pre, pos, tmp);  gfc_mark_ss_chain_used (arrayss, 1);  if (maskss)    gfc_mark_ss_chain_used (maskss, 1);  /* Generate the loop body.  */  gfc_start_scalarized_body (&loop, &body);  /* If we have a mask, only check this element if the mask is set.  */  if (maskss)    {      gfc_init_se (&maskse, NULL);      gfc_copy_loopinfo_to_se (&maskse, &loop);      maskse.ss = maskss;      gfc_conv_expr_val (&maskse, maskexpr);      gfc_add_block_to_block (&body, &maskse.pre);      gfc_start_block (&block);    }  else    gfc_init_block (&block);  /* Compare with the current limit.  */  gfc_init_se (&arrayse, NULL);  gfc_copy_loopinfo_to_se (&arrayse, &loop);  arrayse.ss = arrayss;  gfc_conv_expr_val (&arrayse, arrayexpr);  gfc_add_block_to_block (&block, &arrayse.pre);  /* We do the following if this is a more extreme value.  */  gfc_start_block (&ifblock);  /* Assign the value to the limit...  */  gfc_add_modify_expr (&ifblock, limit, arrayse.expr);  /* Remember where we are.  */  gfc_add_modify_expr (&ifblock, pos, loop.loopvar[0]);  ifbody = gfc_finish_block (&ifblock);  /* If it is a more extreme value.  */  tmp = build2 (op, boolean_type_node, arrayse.expr, limit);  tmp = build3_v (COND_EXPR, tmp, ifbody, build_empty_stmt ());  gfc_add_expr_to_block (&block, tmp);  if (maskss)    {      /* We enclose the above in if (mask) {...}.  */      tmp = gfc_finish_block (&block);      tmp = build3_v (COND_EXPR, maskse.expr, tmp, build_empty_stmt ());    }  else    tmp = gfc_finish_block (&block);  gfc_add_expr_to_block (&body, tmp);  gfc_trans_scalarizing_loops (&loop, &body);  gfc_add_block_to_block (&se->pre, &loop.pre);  gfc_add_block_to_block (&se->pre, &loop.post);  gfc_cleanup_loop (&loop);  /* Return a value in the range 1..SIZE(array).  */  tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, loop.from[0],		     gfc_index_one_node);  tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, pos, tmp);  /* And convert to the required type.  */  se->expr = convert (type, tmp);}static voidgfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, int op){  tree limit;  tree type;  tree tmp;  tree ifbody;  stmtblock_t body;  stmtblock_t block;  gfc_loopinfo loop;  gfc_actual_arglist *actual;  gfc_ss *arrayss;  gfc_ss *maskss;  gfc_se arrayse;  gfc_se maskse;  gfc_expr *arrayexpr;  gfc_expr *maskexpr;  int n;  if (se->ss)    {      gfc_conv_intrinsic_funcall (se, expr);      return;    }  type = gfc_typenode_for_spec (&expr->ts);  /* Initialize the result.  */  limit = gfc_create_var (type, "limit");  n = gfc_validate_kind (expr->ts.type, expr->ts.kind, false);  switch (expr->ts.type)    {    case BT_REAL:      tmp = gfc_conv_mpfr_to_tree (gfc_real_kinds[n].huge, expr->ts.kind);      break;    case BT_INTEGER:      tmp = gfc_conv_mpz_to_tree (gfc_integer_kinds[n].huge, expr->ts.kind);      break;    default:      gcc_unreachable ();    }  /* Most negative(-HUGE) for maxval, most positive (-HUGE) for minval.  */  if (op == GT_EXPR)    tmp = fold_build1 (NEGATE_EXPR, TREE_TYPE (tmp), tmp);  gfc_add_modify_expr (&se->pre, limit, tmp);  /* Walk the arguments.  */  actual = expr->value.function.actual;  arrayexpr = actual->expr;  arrayss = gfc_walk_expr (arrayexpr);  gcc_assert (arrayss != gfc_ss_terminator);  actual = actual->next->next;  gcc_assert (actual);  maskexpr = actual->expr;  if (maskexpr)    {      maskss = gfc_walk_expr (maskexpr);      gcc_assert (maskss != gfc_ss_terminator);    }  else    maskss = NULL;  /* Initialize the scalarizer.  */  gfc_init_loopinfo (&loop);  gfc_add_ss_to_loop (&loop, arrayss);  if (maskss)    gfc_add_ss_to_loop (&loop, maskss);  /* Initialize the loop.  */  gfc_conv_ss_startstride (&loop);  gfc_conv_loop_setup (&loop);  gfc_mark_ss_chain_used (arrayss, 1);  if (maskss)    gfc_mark_ss_chain_used (maskss, 1);  /* Generate the loop body.  */  gfc_start_scalarized_body (&loop, &body);  /* If we have a mask, only add this element if the mask is set.  */  if (maskss)    {      gfc_init_se (&maskse, NULL);      gfc_copy_loopinfo_to_se (&maskse, &loop);      maskse.ss = maskss;      gfc_conv_expr_val (&maskse, maskexpr);      gfc_add_block_to_block (&body, &maskse.pre);      gfc_start_block (&block);    }  else    gfc_init_block (&block);  /* Compare with the current limit.  */  gfc_init_se (&arrayse, NULL);  gfc_copy_loopinfo_to_se (&arrayse, &loop);  arrayse.ss = arrayss;  gfc_conv_expr_val (&arrayse, arrayexpr);  gfc_add_block_to_block (&block, &arrayse.pre);  /* Assign the value to the limit...  */  ifbody = build2_v (MODIFY_EXPR, limit, arrayse.expr);  /* If it is a more extreme value.  */  tmp = build2 (op, boolean_type_node, arrayse.expr, limit);  tmp = build3_v (COND_EXPR, tmp, ifbody, build_empty_stmt ());  gfc_add_expr_to_block (&block, tmp);  gfc_add_block_to_block (&block, &arrayse.post);  tmp = gfc_finish_block (&block);  if (maskss)    /* We enclose the above in if (mask) {...}.  */    tmp = build3_v (COND_EXPR, maskse.expr, tmp, build_empty_stmt ());  gfc_add_expr_to_block (&body, tmp);  gfc_trans_scalarizing_loops (&loop, &body);  gfc_add_block_to_block (&se->pre, &loop.pre);  gfc_add_block_to_block (&se->pre, &loop.post);  gfc_cleanup_loop (&loop);  se->expr = limit;}/* BTEST (i, pos) = (i & (1 << pos)) != 0.  */static voidgfc_conv_intrinsic_btest (gfc_se * se, gfc_expr * expr){  tree arg;  tree arg2;  tree type;  tree tmp;  arg = gfc_conv_intrinsic_function_args (se, expr);  arg2 = TREE_VALUE (TREE_CHAIN (arg));  arg = TREE_VALUE (arg);  type = TREE_TYPE (arg);  tmp = build2 (LSHIFT_EXPR, type, build_int_cst (type, 1), arg2);  tmp = build2 (BIT_AND_EXPR, type, arg, tmp);  tmp = fold_build2 (NE_EXPR, boolean_type_node, tmp,		     build_int_cst (type, 0));  type = gfc_typenode_for_spec (&expr->ts);  se->expr = convert (type, tmp);}/* Generate code to perform the specified operation.  */static voidgfc_conv_intrinsic_bitop (gfc_se * se, gfc_expr * expr, int op){  tree arg;  tree arg2;  tree type;  arg = gfc_conv_intrinsic_function_args (se, expr);  arg2 = TREE_VALUE (TREE_CHAIN (arg));  arg = TREE_VALUE (arg);  type = TREE_TYPE (arg);  se->expr = fold_build2 (op, type, arg, arg2);}/* Bitwise not.  */static voidgfc_conv_intrinsic_not (gfc_se * se, gfc_expr * expr){  tree arg;  arg = gfc_conv_intrinsic_function_args (se, expr);  arg = TREE_VALUE (arg);  se->expr = build1 (BIT_NOT_EXPR, TREE_TYPE (arg), arg);}/* Set or clear a single bit.  */static voidgfc_conv_intrinsic_singlebitop (gfc_se * se, gfc_expr * expr, int set){  tree arg;  tree arg2;  tree type;  tree tmp;  int op;  arg = gfc_conv_intrinsic_function_args (se, expr);  arg2 = TREE_VALUE (TREE_CHAIN (arg));  arg = TREE_VALUE (arg);  type = TREE_TYPE (arg);  tmp = fold_build2 (LSHIFT_EXPR, type, build_int_cst (type, 1), arg2);  if (set)    op = BIT_IOR_EXPR;  else    {      op = BIT_AND_EXPR;      tmp = fold_build1 (BIT_NOT_EXPR, type, tmp);    }  se->expr = fold_build2 (op, type, arg, tmp);}/* Extract a sequence of bits.    IBITS(I, POS, LEN) = (I >> POS) & ~((~0) << LEN).  */static voidgfc_conv_intrinsic_ibits (gfc_se * se, gfc_expr * expr){  tree arg;  tree arg2;  tree arg3;  tree type;  tree tmp;  tree mask;  arg = gfc_conv_intrinsic_function_args (se, expr);  arg2 = TREE_CHAIN (arg);  arg3 = TREE_VALUE (TREE_CHAIN (arg2));  arg = TREE_VALUE (arg);  arg2 = TREE_VALUE (arg2);  type = TREE_TYPE (arg);  mask = build_int_cst (NULL_TREE, -1);  mask = build2 (LSHIFT_EXPR, type, mask, arg3);  mask = build1 (BIT_NOT_EXPR, type, mask);  tmp = build2 (RSHIFT_EXPR, type, arg, arg2);  se->expr = fold_build2 (BIT_AND_EXPR, type, tmp, mask);}/* ISHFT (I, SHIFT) = (abs (shift) >= BIT_SIZE (i))                        ? 0	 	        : ((shift >= 0) ? i << shift : i >> -shift)   where all shifts are logical shifts.  */static voidgfc_conv_intrinsic_ishft (gfc_se * se, gfc_expr * expr){  tree arg;  tree arg2;  tree type;  tree utype;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?