📄 trans-expr.c
字号:
gfc_init_se (&operand, se); gfc_conv_expr_val (&operand, expr->value.op.op1); gfc_add_block_to_block (&se->pre, &operand.pre); type = gfc_typenode_for_spec (&expr->ts); /* TRUTH_NOT_EXPR is not a "true" unary operator in GCC. We must convert it to a compare to 0 (e.g. EQ_EXPR (op1, 0)). All other unary operators have an equivalent GIMPLE unary operator. */ if (code == TRUTH_NOT_EXPR) se->expr = build2 (EQ_EXPR, type, operand.expr, convert (type, integer_zero_node)); else se->expr = build1 (code, type, operand.expr);}/* Expand power operator to optimal multiplications when a value is raised to a constant integer n. See section 4.6.3, "Evaluation of Powers" of Donald E. Knuth, "Seminumerical Algorithms", Vol. 2, "The Art of Computer Programming", 3rd Edition, 1998. *//* This code is mostly duplicated from expand_powi in the backend. We establish the "optimal power tree" lookup table with the defined size. The items in the table are the exponents used to calculate the index exponents. Any integer n less than the value can get an "addition chain", with the first node being one. */#define POWI_TABLE_SIZE 256/* The table is from builtins.c. */static const unsigned char powi_table[POWI_TABLE_SIZE] = { 0, 1, 1, 2, 2, 3, 3, 4, /* 0 - 7 */ 4, 6, 5, 6, 6, 10, 7, 9, /* 8 - 15 */ 8, 16, 9, 16, 10, 12, 11, 13, /* 16 - 23 */ 12, 17, 13, 18, 14, 24, 15, 26, /* 24 - 31 */ 16, 17, 17, 19, 18, 33, 19, 26, /* 32 - 39 */ 20, 25, 21, 40, 22, 27, 23, 44, /* 40 - 47 */ 24, 32, 25, 34, 26, 29, 27, 44, /* 48 - 55 */ 28, 31, 29, 34, 30, 60, 31, 36, /* 56 - 63 */ 32, 64, 33, 34, 34, 46, 35, 37, /* 64 - 71 */ 36, 65, 37, 50, 38, 48, 39, 69, /* 72 - 79 */ 40, 49, 41, 43, 42, 51, 43, 58, /* 80 - 87 */ 44, 64, 45, 47, 46, 59, 47, 76, /* 88 - 95 */ 48, 65, 49, 66, 50, 67, 51, 66, /* 96 - 103 */ 52, 70, 53, 74, 54, 104, 55, 74, /* 104 - 111 */ 56, 64, 57, 69, 58, 78, 59, 68, /* 112 - 119 */ 60, 61, 61, 80, 62, 75, 63, 68, /* 120 - 127 */ 64, 65, 65, 128, 66, 129, 67, 90, /* 128 - 135 */ 68, 73, 69, 131, 70, 94, 71, 88, /* 136 - 143 */ 72, 128, 73, 98, 74, 132, 75, 121, /* 144 - 151 */ 76, 102, 77, 124, 78, 132, 79, 106, /* 152 - 159 */ 80, 97, 81, 160, 82, 99, 83, 134, /* 160 - 167 */ 84, 86, 85, 95, 86, 160, 87, 100, /* 168 - 175 */ 88, 113, 89, 98, 90, 107, 91, 122, /* 176 - 183 */ 92, 111, 93, 102, 94, 126, 95, 150, /* 184 - 191 */ 96, 128, 97, 130, 98, 133, 99, 195, /* 192 - 199 */ 100, 128, 101, 123, 102, 164, 103, 138, /* 200 - 207 */ 104, 145, 105, 146, 106, 109, 107, 149, /* 208 - 215 */ 108, 200, 109, 146, 110, 170, 111, 157, /* 216 - 223 */ 112, 128, 113, 130, 114, 182, 115, 132, /* 224 - 231 */ 116, 200, 117, 132, 118, 158, 119, 206, /* 232 - 239 */ 120, 240, 121, 162, 122, 147, 123, 152, /* 240 - 247 */ 124, 166, 125, 214, 126, 138, 127, 153, /* 248 - 255 */ };/* If n is larger than lookup table's max index, we use the "window method". */#define POWI_WINDOW_SIZE 3/* Recursive function to expand the power operator. The temporary values are put in tmpvar. The function returns tmpvar[1] ** n. */static treegfc_conv_powi (gfc_se * se, int n, tree * tmpvar){ tree op0; tree op1; tree tmp; int digit; if (n < POWI_TABLE_SIZE) { if (tmpvar[n]) return tmpvar[n]; op0 = gfc_conv_powi (se, n - powi_table[n], tmpvar); op1 = gfc_conv_powi (se, powi_table[n], tmpvar); } else if (n & 1) { digit = n & ((1 << POWI_WINDOW_SIZE) - 1); op0 = gfc_conv_powi (se, n - digit, tmpvar); op1 = gfc_conv_powi (se, digit, tmpvar); } else { op0 = gfc_conv_powi (se, n >> 1, tmpvar); op1 = op0; } tmp = fold_build2 (MULT_EXPR, TREE_TYPE (op0), op0, op1); tmp = gfc_evaluate_now (tmp, &se->pre); if (n < POWI_TABLE_SIZE) tmpvar[n] = tmp; return tmp;}/* Expand lhs ** rhs. rhs is a constant integer. If it expands successfully, return 1. Else return 0 and a call to runtime library functions will have to be built. */static intgfc_conv_cst_int_power (gfc_se * se, tree lhs, tree rhs){ tree cond; tree tmp; tree type; tree vartmp[POWI_TABLE_SIZE]; int n; int sgn; type = TREE_TYPE (lhs); n = abs (TREE_INT_CST_LOW (rhs)); sgn = tree_int_cst_sgn (rhs); if (((FLOAT_TYPE_P (type) && !flag_unsafe_math_optimizations) || optimize_size) && (n > 2 || n < -1)) return 0; /* rhs == 0 */ if (sgn == 0) { se->expr = gfc_build_const (type, integer_one_node); return 1; } /* If rhs < 0 and lhs is an integer, the result is -1, 0 or 1. */ if ((sgn == -1) && (TREE_CODE (type) == INTEGER_TYPE)) { tmp = build2 (EQ_EXPR, boolean_type_node, lhs, fold_convert (TREE_TYPE (lhs), integer_minus_one_node)); cond = build2 (EQ_EXPR, boolean_type_node, lhs, convert (TREE_TYPE (lhs), integer_one_node)); /* If rhs is even, result = (lhs == 1 || lhs == -1) ? 1 : 0. */ if ((n & 1) == 0) { tmp = build2 (TRUTH_OR_EXPR, boolean_type_node, tmp, cond); se->expr = build3 (COND_EXPR, type, tmp, convert (type, integer_one_node), convert (type, integer_zero_node)); return 1; } /* If rhs is odd, result = (lhs == 1) ? 1 : (lhs == -1) ? -1 : 0. */ tmp = build3 (COND_EXPR, type, tmp, convert (type, integer_minus_one_node), convert (type, integer_zero_node)); se->expr = build3 (COND_EXPR, type, cond, convert (type, integer_one_node), tmp); return 1; } memset (vartmp, 0, sizeof (vartmp)); vartmp[1] = lhs; if (sgn == -1) { tmp = gfc_build_const (type, integer_one_node); vartmp[1] = build2 (RDIV_EXPR, type, tmp, vartmp[1]); } se->expr = gfc_conv_powi (se, n, vartmp); return 1;}/* Power op (**). Constant integer exponent has special handling. */static voidgfc_conv_power_op (gfc_se * se, gfc_expr * expr){ tree gfc_int4_type_node; int kind; int ikind; gfc_se lse; gfc_se rse; tree fndecl; tree tmp; gfc_init_se (&lse, se); gfc_conv_expr_val (&lse, expr->value.op.op1); lse.expr = gfc_evaluate_now (lse.expr, &lse.pre); gfc_add_block_to_block (&se->pre, &lse.pre); gfc_init_se (&rse, se); gfc_conv_expr_val (&rse, expr->value.op.op2); gfc_add_block_to_block (&se->pre, &rse.pre); if (expr->value.op.op2->ts.type == BT_INTEGER && expr->value.op.op2->expr_type == EXPR_CONSTANT) if (gfc_conv_cst_int_power (se, lse.expr, rse.expr)) return; gfc_int4_type_node = gfc_get_int_type (4); kind = expr->value.op.op1->ts.kind; switch (expr->value.op.op2->ts.type) { case BT_INTEGER: ikind = expr->value.op.op2->ts.kind; switch (ikind) { case 1: case 2: rse.expr = convert (gfc_int4_type_node, rse.expr); /* Fall through. */ case 4: ikind = 0; break; case 8: ikind = 1; break; case 16: ikind = 2; break; default: gcc_unreachable (); } switch (kind) { case 1: case 2: if (expr->value.op.op1->ts.type == BT_INTEGER) lse.expr = convert (gfc_int4_type_node, lse.expr); else gcc_unreachable (); /* Fall through. */ case 4: kind = 0; break; case 8: kind = 1; break; case 10: kind = 2; break; case 16: kind = 3; break; default: gcc_unreachable (); } switch (expr->value.op.op1->ts.type) { case BT_INTEGER: if (kind == 3) /* Case 16 was not handled properly above. */ kind = 2; fndecl = gfor_fndecl_math_powi[kind][ikind].integer; break; case BT_REAL: fndecl = gfor_fndecl_math_powi[kind][ikind].real; break; case BT_COMPLEX: fndecl = gfor_fndecl_math_powi[kind][ikind].cmplx; break; default: gcc_unreachable (); } break; case BT_REAL: switch (kind) { case 4: fndecl = built_in_decls[BUILT_IN_POWF]; break; case 8: fndecl = built_in_decls[BUILT_IN_POW]; break; case 10: case 16: fndecl = built_in_decls[BUILT_IN_POWL]; break; default: gcc_unreachable (); } break; case BT_COMPLEX: switch (kind) { case 4: fndecl = gfor_fndecl_math_cpowf; break; case 8: fndecl = gfor_fndecl_math_cpow; break; case 10: fndecl = gfor_fndecl_math_cpowl10; break; case 16: fndecl = gfor_fndecl_math_cpowl16; break; default: gcc_unreachable (); } break; default: gcc_unreachable (); break; } tmp = gfc_chainon_list (NULL_TREE, lse.expr); tmp = gfc_chainon_list (tmp, rse.expr); se->expr = fold (gfc_build_function_call (fndecl, tmp));}/* Generate code to allocate a string temporary. */treegfc_conv_string_tmp (gfc_se * se, tree type, tree len){ tree var; tree tmp; tree args; gcc_assert (TREE_TYPE (len) == gfc_charlen_type_node); if (gfc_can_put_var_on_stack (len)) { /* Create a temporary variable to hold the result. */ tmp = fold_build2 (MINUS_EXPR, gfc_charlen_type_node, len, convert (gfc_charlen_type_node, integer_one_node)); tmp = build_range_type (gfc_array_index_type, gfc_index_zero_node, tmp); tmp = build_array_type (gfc_character1_type_node, tmp); var = gfc_create_var (tmp, "str"); var = gfc_build_addr_expr (type, var); } else { /* Allocate a temporary to hold the result. */ var = gfc_create_var (type, "pstr"); args = gfc_chainon_list (NULL_TREE, len); tmp = gfc_build_function_call (gfor_fndecl_internal_malloc, args); tmp = convert (type, tmp); gfc_add_modify_expr (&se->pre, var, tmp); /* Free the temporary afterwards. */ tmp = convert (pvoid_type_node, var); args = gfc_chainon_list (NULL_TREE, tmp); tmp = gfc_build_function_call (gfor_fndecl_internal_free, args); gfc_add_expr_to_block (&se->post, tmp); } return var;}/* Handle a string concatenation operation. A temporary will be allocated to hold the result. */static voidgfc_conv_concat_op (gfc_se * se, gfc_expr * expr){ gfc_se lse; gfc_se rse; tree len; tree type; tree var; tree args; tree tmp; gcc_assert (expr->value.op.op1->ts.type == BT_CHARACTER && expr->value.op.op2->ts.type == BT_CHARACTER); gfc_init_se (&lse, se); gfc_conv_expr (&lse, expr->value.op.op1); gfc_conv_string_parameter (&lse); gfc_init_se (&rse, se); gfc_conv_expr (&rse, expr->value.op.op2); gfc_conv_string_parameter (&rse); gfc_add_block_to_block (&se->pre, &lse.pre); gfc_add_block_to_block (&se->pre, &rse.pre); type = gfc_get_character_type (expr->ts.kind, expr->ts.cl); len = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); if (len == NULL_TREE) { len = fold_build2 (PLUS_EXPR, TREE_TYPE (lse.string_length), lse.string_length, rse.string_length); } type = build_pointer_type (type); var = gfc_conv_string_tmp (se, type, len); /* Do the actual concatenation. */ args = NULL_TREE; args = gfc_chainon_list (args, len); args = gfc_chainon_list (args, var); args = gfc_chainon_list (args, lse.string_length); args = gfc_chainon_list (args, lse.expr); args = gfc_chainon_list (args, rse.string_length); args = gfc_chainon_list (args, rse.expr); tmp = gfc_build_function_call (gfor_fndecl_concat_string, args); gfc_add_expr_to_block (&se->pre, tmp); /* Add the cleanup for the operands. */ gfc_add_block_to_block (&se->pre, &rse.post); gfc_add_block_to_block (&se->pre, &lse.post); se->expr = var; se->string_length = len;}/* Translates an op expression. Common (binary) cases are handled by this function, others are passed on. Recursion is used in either case. We use the fact that (op1.ts == op2.ts) (except for the power operator **). Operators need no special handling for scalarized expressions as long as they call gfc_conv_simple_val to get their operands. Character strings get special handling. */static voidgfc_conv_expr_op (gfc_se * se, gfc_expr * expr){ enum tree_code code; gfc_se lse; gfc_se rse; tree type; tree tmp; int lop; int checkstring; checkstring = 0; lop = 0; switch (expr->value.op.operator) { case INTRINSIC_UPLUS: case INTRINSIC_PARENTHESES: gfc_conv_expr (se, expr->value.op.op1); return; case INTRINSIC_UMINUS: gfc_conv_unary_op (NEGATE_EXPR, se, expr); return; case INTRINSIC_NOT: gfc_conv_unary_op (TRUTH_NOT_EXPR, se, expr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -