📄 trans-expr.c
字号:
return; case INTRINSIC_PLUS: code = PLUS_EXPR; break; case INTRINSIC_MINUS: code = MINUS_EXPR; break; case INTRINSIC_TIMES: code = MULT_EXPR; break; case INTRINSIC_DIVIDE: /* If expr is a real or complex expr, use an RDIV_EXPR. If op1 is an integer, we must round towards zero, so we use a TRUNC_DIV_EXPR. */ if (expr->ts.type == BT_INTEGER) code = TRUNC_DIV_EXPR; else code = RDIV_EXPR; break; case INTRINSIC_POWER: gfc_conv_power_op (se, expr); return; case INTRINSIC_CONCAT: gfc_conv_concat_op (se, expr); return; case INTRINSIC_AND: code = TRUTH_ANDIF_EXPR; lop = 1; break; case INTRINSIC_OR: code = TRUTH_ORIF_EXPR; lop = 1; break; /* EQV and NEQV only work on logicals, but since we represent them as integers, we can use EQ_EXPR and NE_EXPR for them in GIMPLE. */ case INTRINSIC_EQ: case INTRINSIC_EQV: code = EQ_EXPR; checkstring = 1; lop = 1; break; case INTRINSIC_NE: case INTRINSIC_NEQV: code = NE_EXPR; checkstring = 1; lop = 1; break; case INTRINSIC_GT: code = GT_EXPR; checkstring = 1; lop = 1; break; case INTRINSIC_GE: code = GE_EXPR; checkstring = 1; lop = 1; break; case INTRINSIC_LT: code = LT_EXPR; checkstring = 1; lop = 1; break; case INTRINSIC_LE: code = LE_EXPR; checkstring = 1; lop = 1; break; case INTRINSIC_USER: case INTRINSIC_ASSIGN: /* These should be converted into function calls by the frontend. */ gcc_unreachable (); default: fatal_error ("Unknown intrinsic op"); return; } /* The only exception to this is **, which is handled separately anyway. */ gcc_assert (expr->value.op.op1->ts.type == expr->value.op.op2->ts.type); if (checkstring && expr->value.op.op1->ts.type != BT_CHARACTER) checkstring = 0; /* lhs */ gfc_init_se (&lse, se); gfc_conv_expr (&lse, expr->value.op.op1); gfc_add_block_to_block (&se->pre, &lse.pre); /* rhs */ gfc_init_se (&rse, se); gfc_conv_expr (&rse, expr->value.op.op2); gfc_add_block_to_block (&se->pre, &rse.pre); if (checkstring) { gfc_conv_string_parameter (&lse); gfc_conv_string_parameter (&rse); lse.expr = gfc_build_compare_string (lse.string_length, lse.expr, rse.string_length, rse.expr); rse.expr = integer_zero_node; gfc_add_block_to_block (&lse.post, &rse.post); } type = gfc_typenode_for_spec (&expr->ts); if (lop) { /* The result of logical ops is always boolean_type_node. */ tmp = fold_build2 (code, type, lse.expr, rse.expr); se->expr = convert (type, tmp); } else se->expr = fold_build2 (code, type, lse.expr, rse.expr); /* Add the post blocks. */ gfc_add_block_to_block (&se->post, &rse.post); gfc_add_block_to_block (&se->post, &lse.post);}/* If a string's length is one, we convert it to a single character. */static treegfc_to_single_character (tree len, tree str){ gcc_assert (POINTER_TYPE_P (TREE_TYPE (str))); if (INTEGER_CST_P (len) && TREE_INT_CST_LOW (len) == 1 && TREE_INT_CST_HIGH (len) == 0) { str = fold_convert (pchar_type_node, str); return build_fold_indirect_ref (str); } return NULL_TREE;}/* Compare two strings. If they are all single characters, the result is the subtraction of them. Otherwise, we build a library call. */treegfc_build_compare_string (tree len1, tree str1, tree len2, tree str2){ tree sc1; tree sc2; tree type; tree tmp; gcc_assert (POINTER_TYPE_P (TREE_TYPE (str1))); gcc_assert (POINTER_TYPE_P (TREE_TYPE (str2))); type = gfc_get_int_type (gfc_default_integer_kind); sc1 = gfc_to_single_character (len1, str1); sc2 = gfc_to_single_character (len2, str2); /* Deal with single character specially. */ if (sc1 != NULL_TREE && sc2 != NULL_TREE) { sc1 = fold_convert (type, sc1); sc2 = fold_convert (type, sc2); tmp = fold_build2 (MINUS_EXPR, type, sc1, sc2); } else { tmp = NULL_TREE; tmp = gfc_chainon_list (tmp, len1); tmp = gfc_chainon_list (tmp, str1); tmp = gfc_chainon_list (tmp, len2); tmp = gfc_chainon_list (tmp, str2); /* Build a call for the comparison. */ tmp = build_function_call_expr (gfor_fndecl_compare_string, tmp); } return tmp;}static voidgfc_conv_function_val (gfc_se * se, gfc_symbol * sym){ tree tmp; if (sym->attr.dummy) { tmp = gfc_get_symbol_decl (sym); gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE && TREE_CODE (TREE_TYPE (TREE_TYPE (tmp))) == FUNCTION_TYPE); } else { if (!sym->backend_decl) sym->backend_decl = gfc_get_extern_function_decl (sym); tmp = sym->backend_decl; if (!POINTER_TYPE_P (TREE_TYPE (tmp))) { gcc_assert (TREE_CODE (tmp) == FUNCTION_DECL); tmp = gfc_build_addr_expr (NULL, tmp); } } se->expr = tmp;}/* Initialize MAPPING. */voidgfc_init_interface_mapping (gfc_interface_mapping * mapping){ mapping->syms = NULL; mapping->charlens = NULL;}/* Free all memory held by MAPPING (but not MAPPING itself). */voidgfc_free_interface_mapping (gfc_interface_mapping * mapping){ gfc_interface_sym_mapping *sym; gfc_interface_sym_mapping *nextsym; gfc_charlen *cl; gfc_charlen *nextcl; for (sym = mapping->syms; sym; sym = nextsym) { nextsym = sym->next; gfc_free_symbol (sym->new->n.sym); gfc_free (sym->new); gfc_free (sym); } for (cl = mapping->charlens; cl; cl = nextcl) { nextcl = cl->next; gfc_free_expr (cl->length); gfc_free (cl); }}/* Return a copy of gfc_charlen CL. Add the returned structure to MAPPING so that it will be freed by gfc_free_interface_mapping. */static gfc_charlen *gfc_get_interface_mapping_charlen (gfc_interface_mapping * mapping, gfc_charlen * cl){ gfc_charlen *new; new = gfc_get_charlen (); new->next = mapping->charlens; new->length = gfc_copy_expr (cl->length); mapping->charlens = new; return new;}/* A subroutine of gfc_add_interface_mapping. Return a descriptorless array variable that can be used as the actual argument for dummy argument SYM. Add any initialization code to BLOCK. PACKED is as for gfc_get_nodesc_array_type and DATA points to the first element in the passed array. */static treegfc_get_interface_mapping_array (stmtblock_t * block, gfc_symbol * sym, int packed, tree data){ tree type; tree var; type = gfc_typenode_for_spec (&sym->ts); type = gfc_get_nodesc_array_type (type, sym->as, packed); var = gfc_create_var (type, "ifm"); gfc_add_modify_expr (block, var, fold_convert (type, data)); return var;}/* A subroutine of gfc_add_interface_mapping. Set the stride, upper bounds and offset of descriptorless array type TYPE given that it has the same size as DESC. Add any set-up code to BLOCK. */static voidgfc_set_interface_mapping_bounds (stmtblock_t * block, tree type, tree desc){ int n; tree dim; tree offset; tree tmp; offset = gfc_index_zero_node; for (n = 0; n < GFC_TYPE_ARRAY_RANK (type); n++) { GFC_TYPE_ARRAY_STRIDE (type, n) = gfc_conv_array_stride (desc, n); if (GFC_TYPE_ARRAY_UBOUND (type, n) == NULL_TREE) { dim = gfc_rank_cst[n]; tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, gfc_conv_descriptor_ubound (desc, dim), gfc_conv_descriptor_lbound (desc, dim)); tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type, GFC_TYPE_ARRAY_LBOUND (type, n), tmp); tmp = gfc_evaluate_now (tmp, block); GFC_TYPE_ARRAY_UBOUND (type, n) = tmp; } tmp = fold_build2 (MULT_EXPR, gfc_array_index_type, GFC_TYPE_ARRAY_LBOUND (type, n), GFC_TYPE_ARRAY_STRIDE (type, n)); offset = fold_build2 (MINUS_EXPR, gfc_array_index_type, offset, tmp); } offset = gfc_evaluate_now (offset, block); GFC_TYPE_ARRAY_OFFSET (type) = offset;}/* Extend MAPPING so that it maps dummy argument SYM to the value stored in SE. The caller may still use se->expr and se->string_length after calling this function. */voidgfc_add_interface_mapping (gfc_interface_mapping * mapping, gfc_symbol * sym, gfc_se * se){ gfc_interface_sym_mapping *sm; tree desc; tree tmp; tree value; gfc_symbol *new_sym; gfc_symtree *root; gfc_symtree *new_symtree; /* Create a new symbol to represent the actual argument. */ new_sym = gfc_new_symbol (sym->name, NULL); new_sym->ts = sym->ts; new_sym->attr.referenced = 1; new_sym->attr.dimension = sym->attr.dimension; new_sym->attr.pointer = sym->attr.pointer; new_sym->attr.flavor = sym->attr.flavor; /* Create a fake symtree for it. */ root = NULL; new_symtree = gfc_new_symtree (&root, sym->name); new_symtree->n.sym = new_sym; gcc_assert (new_symtree == root); /* Create a dummy->actual mapping. */ sm = gfc_getmem (sizeof (*sm)); sm->next = mapping->syms; sm->old = sym; sm->new = new_symtree; mapping->syms = sm; /* Stabilize the argument's value. */ se->expr = gfc_evaluate_now (se->expr, &se->pre); if (sym->ts.type == BT_CHARACTER) { /* Create a copy of the dummy argument's length. */ new_sym->ts.cl = gfc_get_interface_mapping_charlen (mapping, sym->ts.cl); /* If the length is specified as "*", record the length that the caller is passing. We should use the callee's length in all other cases. */ if (!new_sym->ts.cl->length) { se->string_length = gfc_evaluate_now (se->string_length, &se->pre); new_sym->ts.cl->backend_decl = se->string_length; } } /* Use the passed value as-is if the argument is a function. */ if (sym->attr.flavor == FL_PROCEDURE) value = se->expr; /* If the argument is either a string or a pointer to a string, convert it to a boundless character type. */ else if (!sym->attr.dimension && sym->ts.type == BT_CHARACTER) { tmp = gfc_get_character_type_len (sym->ts.kind, NULL); tmp = build_pointer_type (tmp); if (sym->attr.pointer) tmp = build_pointer_type (tmp); value = fold_convert (tmp, se->expr); if (sym->attr.pointer) value = gfc_build_indirect_ref (value); } /* If the argument is a scalar or a pointer to an array, dereference it. */ else if (!sym->attr.dimension || sym->attr.pointer) value = gfc_build_indirect_ref (se->expr); /* If the argument is an array descriptor, use it to determine information about the actual argument's shape. */ else if (POINTER_TYPE_P (TREE_TYPE (se->expr)) && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (se->expr)))) { /* Get the actual argument's descriptor. */ desc = gfc_build_indirect_ref (se->expr); /* Create the replacement variable. */ tmp = gfc_conv_descriptor_data_get (desc); value = gfc_get_interface_mapping_array (&se->pre, sym, 0, tmp); /* Use DESC to work out the upper bounds, strides and offset. */ gfc_set_interface_mapping_bounds (&se->pre, TREE_TYPE (value), desc); } else /* Otherwise we have a packed array. */ value = gfc_get_interface_mapping_array (&se->pre, sym, 2, se->expr); new_sym->backend_decl = value;}/* Called once all dummy argument mappings have been added to MAPPING, but before the mapping is used to evaluate expressions. Pre-evaluate the length of each argument, adding any initialization code to PRE and any finalization code to POST. */voidgfc_finish_interface_mapping (gfc_interface_mapping * mapping, stmtblock_t * pre, stmtblock_t * post){ gfc_interface_sym_mapping *sym; gfc_expr *expr; gfc_se se; for (sym = mapping->syms; sym; sym = sym->next) if (sym->new->n.sym->ts.type == BT_CHARACTER && !sym->new->n.sym->ts.cl->backend_decl) { expr = sym->new->n.sym->ts.cl->length; gfc_apply_interface_mapping_to_expr (mapping, expr); gfc_init_se (&se, NULL); gfc_conv_expr (&se, expr); se.expr = gfc_evaluate_now (se.expr, &se.pre); gfc_add_block_to_block (pre, &se.pre); gfc_add_block_to_block (post, &se.post); sym->new->n.sym->ts.cl->backend_decl = se.expr; }}/* Like gfc_apply_interface_mapping_to_expr, but applied to constructor C. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -