📄 trans-intrinsic.c
字号:
tmp = fold_build2 (TRUTH_XOR_EXPR, boolean_type_node, testa, testb); se->expr = fold_build3 (COND_EXPR, type, tmp, build1 (NEGATE_EXPR, type, arg), arg);}/* Test for the presence of an optional argument. */static voidgfc_conv_intrinsic_present (gfc_se * se, gfc_expr * expr){ gfc_expr *arg; arg = expr->value.function.actual->expr; gcc_assert (arg->expr_type == EXPR_VARIABLE); se->expr = gfc_conv_expr_present (arg->symtree->n.sym); se->expr = convert (gfc_typenode_for_spec (&expr->ts), se->expr);}/* Calculate the double precision product of two single precision values. */static voidgfc_conv_intrinsic_dprod (gfc_se * se, gfc_expr * expr){ tree arg; tree arg2; tree type; arg = gfc_conv_intrinsic_function_args (se, expr); arg2 = TREE_VALUE (TREE_CHAIN (arg)); arg = TREE_VALUE (arg); /* Convert the args to double precision before multiplying. */ type = gfc_typenode_for_spec (&expr->ts); arg = convert (type, arg); arg2 = convert (type, arg2); se->expr = build2 (MULT_EXPR, type, arg, arg2);}/* Return a length one character string containing an ascii character. */static voidgfc_conv_intrinsic_char (gfc_se * se, gfc_expr * expr){ tree arg; tree var; tree type; arg = gfc_conv_intrinsic_function_args (se, expr); arg = TREE_VALUE (arg); /* We currently don't support character types != 1. */ gcc_assert (expr->ts.kind == 1); type = gfc_character1_type_node; var = gfc_create_var (type, "char"); arg = convert (type, arg); gfc_add_modify_expr (&se->pre, var, arg); se->expr = gfc_build_addr_expr (build_pointer_type (type), var); se->string_length = integer_one_node;}static voidgfc_conv_intrinsic_ctime (gfc_se * se, gfc_expr * expr){ tree var; tree len; tree tmp; tree arglist; tree type; tree cond; tree gfc_int8_type_node = gfc_get_int_type (8); type = build_pointer_type (gfc_character1_type_node); var = gfc_create_var (type, "pstr"); len = gfc_create_var (gfc_int8_type_node, "len"); tmp = gfc_conv_intrinsic_function_args (se, expr); arglist = gfc_chainon_list (NULL_TREE, gfc_build_addr_expr (NULL, var)); arglist = gfc_chainon_list (arglist, gfc_build_addr_expr (NULL, len)); arglist = chainon (arglist, tmp); tmp = gfc_build_function_call (gfor_fndecl_ctime, arglist); gfc_add_expr_to_block (&se->pre, tmp); /* Free the temporary afterwards, if necessary. */ cond = build2 (GT_EXPR, boolean_type_node, len, build_int_cst (TREE_TYPE (len), 0)); arglist = gfc_chainon_list (NULL_TREE, var); tmp = gfc_build_function_call (gfor_fndecl_internal_free, arglist); tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ()); gfc_add_expr_to_block (&se->post, tmp); se->expr = var; se->string_length = len;}static voidgfc_conv_intrinsic_fdate (gfc_se * se, gfc_expr * expr){ tree var; tree len; tree tmp; tree arglist; tree type; tree cond; tree gfc_int4_type_node = gfc_get_int_type (4); type = build_pointer_type (gfc_character1_type_node); var = gfc_create_var (type, "pstr"); len = gfc_create_var (gfc_int4_type_node, "len"); tmp = gfc_conv_intrinsic_function_args (se, expr); arglist = gfc_chainon_list (NULL_TREE, gfc_build_addr_expr (NULL, var)); arglist = gfc_chainon_list (arglist, gfc_build_addr_expr (NULL, len)); arglist = chainon (arglist, tmp); tmp = gfc_build_function_call (gfor_fndecl_fdate, arglist); gfc_add_expr_to_block (&se->pre, tmp); /* Free the temporary afterwards, if necessary. */ cond = build2 (GT_EXPR, boolean_type_node, len, build_int_cst (TREE_TYPE (len), 0)); arglist = gfc_chainon_list (NULL_TREE, var); tmp = gfc_build_function_call (gfor_fndecl_internal_free, arglist); tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ()); gfc_add_expr_to_block (&se->post, tmp); se->expr = var; se->string_length = len;}/* Return a character string containing the tty name. */static voidgfc_conv_intrinsic_ttynam (gfc_se * se, gfc_expr * expr){ tree var; tree len; tree tmp; tree arglist; tree type; tree cond; tree gfc_int4_type_node = gfc_get_int_type (4); type = build_pointer_type (gfc_character1_type_node); var = gfc_create_var (type, "pstr"); len = gfc_create_var (gfc_int4_type_node, "len"); tmp = gfc_conv_intrinsic_function_args (se, expr); arglist = gfc_chainon_list (NULL_TREE, gfc_build_addr_expr (NULL, var)); arglist = gfc_chainon_list (arglist, gfc_build_addr_expr (NULL, len)); arglist = chainon (arglist, tmp); tmp = gfc_build_function_call (gfor_fndecl_ttynam, arglist); gfc_add_expr_to_block (&se->pre, tmp); /* Free the temporary afterwards, if necessary. */ cond = build2 (GT_EXPR, boolean_type_node, len, build_int_cst (TREE_TYPE (len), 0)); arglist = gfc_chainon_list (NULL_TREE, var); tmp = gfc_build_function_call (gfor_fndecl_internal_free, arglist); tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ()); gfc_add_expr_to_block (&se->post, tmp); se->expr = var; se->string_length = len;}/* Get the minimum/maximum value of all the parameters. minmax (a1, a2, a3, ...) { if (a2 .op. a1) mvar = a2; else mvar = a1; if (a3 .op. mvar) mvar = a3; ... return mvar } *//* TODO: Mismatching types can occur when specific names are used. These should be handled during resolution. */static voidgfc_conv_intrinsic_minmax (gfc_se * se, gfc_expr * expr, int op){ tree limit; tree tmp; tree mvar; tree val; tree thencase; tree elsecase; tree arg; tree type; arg = gfc_conv_intrinsic_function_args (se, expr); type = gfc_typenode_for_spec (&expr->ts); limit = TREE_VALUE (arg); if (TREE_TYPE (limit) != type) limit = convert (type, limit); /* Only evaluate the argument once. */ if (TREE_CODE (limit) != VAR_DECL && !TREE_CONSTANT (limit)) limit = gfc_evaluate_now(limit, &se->pre); mvar = gfc_create_var (type, "M"); elsecase = build2_v (MODIFY_EXPR, mvar, limit); for (arg = TREE_CHAIN (arg); arg != NULL_TREE; arg = TREE_CHAIN (arg)) { val = TREE_VALUE (arg); if (TREE_TYPE (val) != type) val = convert (type, val); /* Only evaluate the argument once. */ if (TREE_CODE (val) != VAR_DECL && !TREE_CONSTANT (val)) val = gfc_evaluate_now(val, &se->pre); thencase = build2_v (MODIFY_EXPR, mvar, convert (type, val)); tmp = build2 (op, boolean_type_node, val, limit); tmp = build3_v (COND_EXPR, tmp, thencase, elsecase); gfc_add_expr_to_block (&se->pre, tmp); elsecase = build_empty_stmt (); limit = mvar; } se->expr = mvar;}/* Create a symbol node for this intrinsic. The symbol from the frontend has the generic name. */static gfc_symbol *gfc_get_symbol_for_expr (gfc_expr * expr){ gfc_symbol *sym; /* TODO: Add symbols for intrinsic function to the global namespace. */ gcc_assert (strlen (expr->value.function.name) <= GFC_MAX_SYMBOL_LEN - 5); sym = gfc_new_symbol (expr->value.function.name, NULL); sym->ts = expr->ts; sym->attr.external = 1; sym->attr.function = 1; sym->attr.always_explicit = 1; sym->attr.proc = PROC_INTRINSIC; sym->attr.flavor = FL_PROCEDURE; sym->result = sym; if (expr->rank > 0) { sym->attr.dimension = 1; sym->as = gfc_get_array_spec (); sym->as->type = AS_ASSUMED_SHAPE; sym->as->rank = expr->rank; } /* TODO: proper argument lists for external intrinsics. */ return sym;}/* Generate a call to an external intrinsic function. */static voidgfc_conv_intrinsic_funcall (gfc_se * se, gfc_expr * expr){ gfc_symbol *sym; gcc_assert (!se->ss || se->ss->expr == expr); if (se->ss) gcc_assert (expr->rank > 0); else gcc_assert (expr->rank == 0); sym = gfc_get_symbol_for_expr (expr); gfc_conv_function_call (se, sym, expr->value.function.actual); gfc_free (sym);}/* ANY and ALL intrinsics. ANY->op == NE_EXPR, ALL->op == EQ_EXPR. Implemented as any(a) { forall (i=...) if (a[i] != 0) return 1 end forall return 0 } all(a) { forall (i=...) if (a[i] == 0) return 0 end forall return 1 } */static voidgfc_conv_intrinsic_anyall (gfc_se * se, gfc_expr * expr, int op){ tree resvar; stmtblock_t block; stmtblock_t body; tree type; tree tmp; tree found; gfc_loopinfo loop; gfc_actual_arglist *actual; gfc_ss *arrayss; gfc_se arrayse; tree exit_label; if (se->ss) { gfc_conv_intrinsic_funcall (se, expr); return; } actual = expr->value.function.actual; type = gfc_typenode_for_spec (&expr->ts); /* Initialize the result. */ resvar = gfc_create_var (type, "test"); if (op == EQ_EXPR) tmp = convert (type, boolean_true_node); else tmp = convert (type, boolean_false_node); gfc_add_modify_expr (&se->pre, resvar, tmp); /* Walk the arguments. */ arrayss = gfc_walk_expr (actual->expr); gcc_assert (arrayss != gfc_ss_terminator); /* Initialize the scalarizer. */ gfc_init_loopinfo (&loop); exit_label = gfc_build_label_decl (NULL_TREE); TREE_USED (exit_label) = 1; gfc_add_ss_to_loop (&loop, arrayss); /* Initialize the loop. */ gfc_conv_ss_startstride (&loop); gfc_conv_loop_setup (&loop); gfc_mark_ss_chain_used (arrayss, 1); /* Generate the loop body. */ gfc_start_scalarized_body (&loop, &body); /* If the condition matches then set the return value. */ gfc_start_block (&block); if (op == EQ_EXPR) tmp = convert (type, boolean_false_node); else tmp = convert (type, boolean_true_node); gfc_add_modify_expr (&block, resvar, tmp); /* And break out of the loop. */ tmp = build1_v (GOTO_EXPR, exit_label); gfc_add_expr_to_block (&block, tmp); found = gfc_finish_block (&block); /* Check this element. */ gfc_init_se (&arrayse, NULL); gfc_copy_loopinfo_to_se (&arrayse, &loop); arrayse.ss = arrayss; gfc_conv_expr_val (&arrayse, actual->expr); gfc_add_block_to_block (&body, &arrayse.pre); tmp = build2 (op, boolean_type_node, arrayse.expr, build_int_cst (TREE_TYPE (arrayse.expr), 0)); tmp = build3_v (COND_EXPR, tmp, found, build_empty_stmt ()); gfc_add_expr_to_block (&body, tmp); gfc_add_block_to_block (&body, &arrayse.post); gfc_trans_scalarizing_loops (&loop, &body); /* Add the exit label. */ tmp = build1_v (LABEL_EXPR, exit_label); gfc_add_expr_to_block (&loop.pre, tmp); 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;}/* COUNT(A) = Number of true elements in A. */static voidgfc_conv_intrinsic_count (gfc_se * se, gfc_expr * expr){ tree resvar; tree type; stmtblock_t body; tree tmp; gfc_loopinfo loop; gfc_actual_arglist *actual; gfc_ss *arrayss; gfc_se arrayse; if (se->ss) { gfc_conv_intrinsic_funcall (se, expr); return; } actual = expr->value.function.actual; type = gfc_typenode_for_spec (&expr->ts); /* Initialize the result. */ resvar = gfc_create_var (type, "count"); gfc_add_modify_expr (&se->pre, resvar, build_int_cst (type, 0)); /* Walk the arguments. */ arrayss = gfc_walk_expr (actual->expr); gcc_assert (arrayss != gfc_ss_terminator); /* Initialize the scalarizer. */ gfc_init_loopinfo (&loop); gfc_add_ss_to_loop (&loop, arrayss); /* Initialize the loop. */ gfc_conv_ss_startstride (&loop); gfc_conv_loop_setup (&loop); gfc_mark_ss_chain_used (arrayss, 1); /* Generate the loop body. */ gfc_start_scalarized_body (&loop, &body); tmp = build2 (PLUS_EXPR, TREE_TYPE (resvar), resvar, build_int_cst (TREE_TYPE (resvar), 1)); tmp = build2_v (MODIFY_EXPR, resvar, tmp); gfc_init_se (&arrayse, NULL); gfc_copy_loopinfo_to_se (&arrayse, &loop); arrayse.ss = arrayss; gfc_conv_expr_val (&arrayse, actual->expr); tmp = build3_v (COND_EXPR, arrayse.expr, tmp, build_empty_stmt ()); gfc_add_block_to_block (&body, &arrayse.pre); gfc_add_expr_to_block (&body, tmp); gfc_add_block_to_block (&body, &arrayse.post); 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;}/* Inline implementation of the sum and product intrinsics. */static voidgfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, int op){ tree resvar; tree type; stmtblock_t body; stmtblock_t block; tree tmp; 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; if (se->ss) { gfc_conv_intrinsic_funcall (se, expr); return; } type = gfc_typenode_for_spec (&expr->ts); /* Initialize the result. */ resvar = gfc_create_var (type, "val"); if (op == PLUS_EXPR)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -