📄 expr.c
字号:
/* Convert language-specific tree expression to rtl instructions, for GNU CHILL compiler. Copyright (C) 1992, 93, 1994, 1998, 1999 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include "config.h"#include "system.h"#include "rtl.h"#include "tree.h"#include "flags.h"#include "expr.h"#include "ch-tree.h"#include "assert.h"#include "lex.h"#include "convert.h"#include "toplev.h"extern char **boolean_code_name;extern int flag_old_strings;extern tree long_unsigned_type_node;extern int ignore_case;extern int special_UC;/* definitions for duration built-ins */#define MILLISECS_MULTIPLIER 1#define SECS_MULTIPLIER MILLISECS_MULTIPLIER * 1000#define MINUTES_MULTIPLIER SECS_MULTIPLIER * 60#define HOURS_MULTIPLIER MINUTES_MULTIPLIER * 60#define DAYS_MULTIPLIER HOURS_MULTIPLIER * 24/* the maximum value for each of the calls */#define MILLISECS_MAX 0xffffffff#define SECS_MAX 4294967#define MINUTES_MAX 71582#define HOURS_MAX 1193#define DAYS_MAX 49/* forward declaration */rtx chill_expand_expr PROTO((tree, rtx, enum machine_mode, enum expand_modifier));/* variable to hold the type the DESCR built-in returns */static tree descr_type = NULL_TREE;/* called from ch-lex.l */voidinit_chill_expand (){ lang_expand_expr = chill_expand_expr;}/* Take the address of something that needs to be passed by reference. */treeforce_addr_of (value) tree value;{ /* FIXME. Move to memory, if needed. */ if (TREE_CODE (value) == INDIRECT_REF) return convert_to_pointer (ptr_type_node, TREE_OPERAND (value, 0)); mark_addressable (value); return build1 (ADDR_EXPR, ptr_type_node, value);}/* Check that EXP has a known type. */treecheck_have_mode (exp, context) tree exp; char *context;{ if (TREE_CODE (exp) != ERROR_MARK && TREE_TYPE (exp) == NULL_TREE) { if (TREE_CODE (exp) == CONSTRUCTOR) error ("tuple without specified mode not allowed in %s", context); else if (TREE_CODE (exp) == COND_EXPR || TREE_CODE (exp) == CASE_EXPR) error ("conditional expression not allowed in %s", context); else error ("internal error: unknown expression mode in %s", context); return error_mark_node; } return exp;}/* Check that EXP is discrete. Handle conversion if flag_old_strings. */treecheck_case_selector (exp) tree exp;{ if (exp != NULL_TREE && TREE_TYPE (exp) != NULL_TREE) exp = convert_to_discrete (exp); if (exp) return exp; error ("CASE selector is not a discrete expression"); return error_mark_node;}treecheck_case_selector_list (list) tree list;{ tree selector, exp, return_list = NULL_TREE; for (selector = list; selector != NULL_TREE; selector = TREE_CHAIN (selector)) { exp = check_case_selector (TREE_VALUE (selector)); if (exp == error_mark_node) { return_list = error_mark_node; break; } return_list = tree_cons (TREE_PURPOSE (selector), exp, return_list); } return nreverse(return_list);}treechill_expand_case_expr (expr) tree expr;{ tree selector_list = TREE_OPERAND (expr, 0), selector; tree alternatives = TREE_OPERAND (expr, 1); tree type = TREE_TYPE (expr); int else_seen = 0; tree result; if (TREE_CODE (selector_list) != TREE_LIST || TREE_CODE (alternatives) != TREE_LIST) abort(); if (TREE_CHAIN (selector_list) != NULL_TREE) abort (); /* make a temp for the case result */ result = decl_temp1 (get_unique_identifier ("CASE_EXPR"), type, 0, NULL_TREE, 0, 0); selector = check_case_selector (TREE_VALUE (selector_list)); expand_start_case (1, selector, TREE_TYPE (selector), "CASE expression"); alternatives = nreverse (alternatives); for ( ; alternatives != NULL_TREE; alternatives = TREE_CHAIN (alternatives)) { tree labels = TREE_PURPOSE (alternatives), t; if (labels == NULL_TREE) { chill_handle_case_default (); else_seen++; } else { tree label; if (labels != NULL_TREE) { for (label = TREE_VALUE (labels); label != NULL_TREE; label = TREE_CHAIN (label)) chill_handle_case_label (TREE_VALUE (label), selector); labels = TREE_CHAIN (labels); if (labels != NULL_TREE) error ("The number of CASE selectors does not match the number " "of CASE label lists"); } } t = build (MODIFY_EXPR, type, result, convert (type, TREE_VALUE (alternatives))); TREE_SIDE_EFFECTS (t) = 1; expand_expr_stmt (t); expand_exit_something (); } if (!else_seen) { chill_handle_case_default (); expand_exit_something ();#if 0 expand_raise ();#endif check_missing_cases (TREE_TYPE (selector)); } expand_end_case (selector); return result;}/* Hook used by expand_expr to expand CHILL-specific tree codes. */rtxchill_expand_expr (exp, target, tmode, modifier) tree exp; rtx target; enum machine_mode tmode; enum expand_modifier modifier;{ tree type = TREE_TYPE (exp); register enum machine_mode mode = TYPE_MODE (type); register enum tree_code code = TREE_CODE (exp); rtx original_target = target; rtx op0, op1; int ignore = target == const0_rtx; char *lib_func; /* name of library routine */ if (ignore) target = 0, original_target = 0; /* No sense saving up arithmetic to be done if it's all in the wrong mode to form part of an address. And force_operand won't know whether to sign-extend or zero-extend. */ if (mode != Pmode && modifier == EXPAND_SUM) modifier = EXPAND_NORMAL; switch (code) { case STRING_EQ_EXPR: case STRING_LT_EXPR: { rtx func = gen_rtx (SYMBOL_REF, Pmode, code == STRING_EQ_EXPR ? "__eqstring" : "__ltstring"); tree exp0 = TREE_OPERAND (exp, 0); tree exp1 = TREE_OPERAND (exp, 1); tree size0, size1; rtx op0, op1, siz0, siz1; if (chill_varying_type_p (TREE_TYPE (exp0))) { exp0 = save_if_needed (exp0); size0 = convert (integer_type_node, build_component_ref (exp0, var_length_id)); exp0 = build_component_ref (exp0, var_data_id); } else size0 = size_in_bytes (TREE_TYPE (exp0)); if (chill_varying_type_p (TREE_TYPE (exp1))) { exp1 = save_if_needed (exp1); size1 = convert (integer_type_node, build_component_ref (exp1, var_length_id)); exp1 = build_component_ref (exp1, var_data_id); } else size1 = size_in_bytes (TREE_TYPE (exp1)); op0 = expand_expr (force_addr_of (exp0), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); op1 = expand_expr (force_addr_of (exp1), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); siz0 = expand_expr (size0, NULL_RTX, VOIDmode, 0); siz1 = expand_expr (size1, NULL_RTX, VOIDmode, 0); return emit_library_call_value (func, target, 0, QImode, 4, op0, GET_MODE (op0), siz0, TYPE_MODE (sizetype), op1, GET_MODE (op1), siz1, TYPE_MODE (sizetype)); } case CASE_EXPR: return expand_expr (chill_expand_case_expr (exp), NULL_RTX, VOIDmode, 0); break; case SLICE_EXPR: { tree func_call; tree array = TREE_OPERAND (exp, 0); tree min_value = TREE_OPERAND (exp, 1); tree length = TREE_OPERAND (exp, 2); tree new_type = TREE_TYPE (exp); tree temp = decl_temp1 (get_unique_identifier ("BITSTRING"), new_type, 0, NULL_TREE, 0, 0); if (! CH_REFERABLE (array) && TYPE_MODE (TREE_TYPE (array)) != BLKmode) array = decl_temp1 (get_unique_identifier ("BSTRINGVAL"), TREE_TYPE (array), 0, array, 0, 0); func_call = build_chill_function_call ( lookup_name (get_identifier ("__psslice")), tree_cons (NULL_TREE, build_chill_addr_expr (temp, (char *)0), tree_cons (NULL_TREE, length, tree_cons (NULL_TREE, force_addr_of (array), tree_cons (NULL_TREE, powersetlen (array), tree_cons (NULL_TREE, convert (integer_type_node, min_value), tree_cons (NULL_TREE, length, NULL_TREE))))))); expand_expr (func_call, const0_rtx, VOIDmode, 0); emit_queue (); return expand_expr (temp, ignore ? const0_rtx : target, VOIDmode, 0); } /* void __concatstring (char *out, char *left, unsigned left_len, char *right, unsigned right_len) */ case CONCAT_EXPR: { tree exp0 = TREE_OPERAND (exp, 0); tree exp1 = TREE_OPERAND (exp, 1); rtx size0 = NULL_RTX, size1 = NULL_RTX; rtx targetx; if (TREE_CODE (exp1) == UNDEFINED_EXPR) { if (TYPE_MODE (TREE_TYPE (exp0)) == BLKmode && TYPE_MODE (TREE_TYPE (exp)) == BLKmode) { rtx temp = expand_expr (exp0, target, tmode, modifier); if (temp == target || target == NULL_RTX) return temp; emit_block_move (target, temp, expr_size (exp0), TYPE_ALIGN (TREE_TYPE(exp0)) / BITS_PER_UNIT); return target; } else { exp0 = force_addr_of (exp0); exp0 = convert (build_pointer_type (TREE_TYPE (exp)), exp0); exp0 = build1 (INDIRECT_REF, TREE_TYPE (exp), exp0); return expand_expr (exp0, NULL_RTX, Pmode, EXPAND_CONST_ADDRESS); } } if (TREE_CODE (type) == ARRAY_TYPE) { /* No need to handle scalars or varying strings here, since that was done in convert or build_concat_expr. */ size0 = expand_expr (size_in_bytes (TREE_TYPE (exp0)), NULL_RTX, Pmode, EXPAND_CONST_ADDRESS); size1 = expand_expr (size_in_bytes (TREE_TYPE (exp1)), NULL_RTX, Pmode, EXPAND_CONST_ADDRESS); /* build a temp for the result, target is its address */ if (target == NULL_RTX) { tree type0 = TREE_TYPE (exp0); tree type1 = TREE_TYPE (exp1); int len0 = int_size_in_bytes (type0); int len1 = int_size_in_bytes (type1); if (len0 < 0 && TYPE_ARRAY_MAX_SIZE (type0) && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type0)) == INTEGER_CST) len0 = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type0)); if (len1 < 0 && TYPE_ARRAY_MAX_SIZE (type1) && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type1)) == INTEGER_CST) len1 = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type1)); if (len0 < 0 || len1 < 0) fatal ("internal error - don't know how much space is needed for concatenation"); target = assign_stack_temp (mode, len0 + len1, 0); preserve_temp_slots (target); } } else if (TREE_CODE (type) == SET_TYPE) { if (target == NULL_RTX) { target = assign_stack_temp (mode, int_size_in_bytes (type), 0); preserve_temp_slots (target); } } else abort (); if (GET_CODE (target) == MEM) targetx = target; else targetx = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0); /* expand 1st operand to a pointer to the array */ op0 = expand_expr (force_addr_of (exp0), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); /* expand 2nd operand to a pointer to the array */ op1 = expand_expr (force_addr_of (exp1), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); if (TREE_CODE (type) == SET_TYPE) { size0 = expand_expr (powersetlen (exp0), NULL_RTX, VOIDmode, 0); size1 = expand_expr (powersetlen (exp1), NULL_RTX, VOIDmode, 0); emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__concatps"), 0, Pmode, 5, XEXP (targetx, 0), Pmode, op0, GET_MODE (op0), convert_to_mode (TYPE_MODE (sizetype), size0, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype), op1, GET_MODE (op1), convert_to_mode (TYPE_MODE (sizetype), size1, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype)); } else { /* copy left, then right array to target */ emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__concatstring"), 0, Pmode, 5, XEXP (targetx, 0), Pmode, op0, GET_MODE (op0), convert_to_mode (TYPE_MODE (sizetype), size0, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype), op1, GET_MODE (op1), convert_to_mode (TYPE_MODE (sizetype), size1, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype)); } if (targetx != target) emit_move_insn (target, targetx); return target; } /* FIXME: the set_length computed below is a compile-time constant; you'll need to re-write that part for VARYING bit arrays, and possibly the set pointer will need to be adjusted to point past the word containing its dynamic length. */ /* void __notpowerset (char *out, char *src, unsigned long bitlength) */ case SET_NOT_EXPR: { tree expr = TREE_OPERAND (exp, 0); tree tsize = powersetlen (expr); rtx targetx; if (TREE_CODE (TREE_TYPE (expr)) != SET_TYPE) tsize = fold (build (MULT_EXPR, sizetype, tsize, size_int (BITS_PER_UNIT))); /* expand 1st operand to a pointer to the set */ op0 = expand_expr (force_addr_of (expr), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); /* build a temp for the result, target is its address */ if (target == NULL_RTX) { target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), int_size_in_bytes (TREE_TYPE (exp)), 0); preserve_temp_slots (target); } if (GET_CODE (target) == MEM) targetx = target; else targetx = assign_stack_temp (GET_MODE (target), GET_MODE_SIZE (GET_MODE (target)), 0); emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__notpowerset"),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -