📄 trans-intrinsic.c
字号:
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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -