This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
cse won't pull an expr out of a function call
- To: gcc at gcc dot gnu dot org
- Subject: cse won't pull an expr out of a function call
- From: Zack Weinberg <zack at bitmover dot com>
- Date: Wed, 28 Jul 1999 18:38:34 -0700
While trying to speed up --enable-checking a bit I ran across an
limitation of CSE which I suspect hurts real code, not just debugging
macros.
Consider
return (
(decl->foo == BLAH ? decl : check_failed(decl, BLAH)
)->bar->foo == BLUR
? (decl->foo == BLAH ? decl : check_failed(decl, BLAH)
)->bar
: check_failed(
(decl->foo = BLAH ? decl : check_failed(decl, BLAH)
)->bar,
BLUR)
)->baz;
check_failed is declared noreturn. The expression
(decl->foo == BLAH ? decl : check_failed(decl, BLAH))->bar
appears three times. cse ought to be able to extract it entirely,
so we would get the equivalent of
temp = (decl->foo == BLAH ? decl : check_failed(decl, BLAH))->bar;
return (temp->foo == BLUR ? temp : check_failed(temp, BLUR))->baz;
This doesn't happen. cse fails to extract the instance nested inside
a call to check_failed. We get assembly equivalent to
temp = (decl->foo == BLAH ? decl : check_failed(decl, BLAH))->bar;
return (temp->foo == BLUR ? temp : check_failed(
(decl->foo == BLAH ? decl : check_failed(decl, BLAH))->bar
, BLUR))->baz;
The test case is appended.
zw
struct rtx_def;
enum tree_code { ERROR_MARK, IDENTIFIER_NODE, OP_IDENTIFIER, TREE_LIST,
TREE_VEC, BLOCK, VOID_TYPE, INTEGER_TYPE, REAL_TYPE, COMPLEX_TYPE,
ENUMERAL_TYPE, BOOLEAN_TYPE, CHAR_TYPE, POINTER_TYPE, OFFSET_TYPE,
REFERENCE_TYPE, METHOD_TYPE, FILE_TYPE, ARRAY_TYPE, SET_TYPE, RECORD_TYPE,
UNION_TYPE, QUAL_UNION_TYPE, FUNCTION_TYPE, LANG_TYPE, INTEGER_CST,
REAL_CST, COMPLEX_CST, STRING_CST, FUNCTION_DECL, LABEL_DECL, CONST_DECL,
TYPE_DECL, VAR_DECL, PARM_DECL, RESULT_DECL, FIELD_DECL, NAMESPACE_DECL,
COMPONENT_REF, BIT_FIELD_REF, INDIRECT_REF, BUFFER_REF, ARRAY_REF,
CONSTRUCTOR, COMPOUND_EXPR, MODIFY_EXPR, INIT_EXPR, TARGET_EXPR,
COND_EXPR, BIND_EXPR, CALL_EXPR, METHOD_CALL_EXPR, WITH_CLEANUP_EXPR,
CLEANUP_POINT_EXPR, PLACEHOLDER_EXPR, WITH_RECORD_EXPR, PLUS_EXPR,
MINUS_EXPR, MULT_EXPR, TRUNC_DIV_EXPR, CEIL_DIV_EXPR, FLOOR_DIV_EXPR,
ROUND_DIV_EXPR, TRUNC_MOD_EXPR, CEIL_MOD_EXPR, FLOOR_MOD_EXPR,
ROUND_MOD_EXPR, RDIV_EXPR, EXACT_DIV_EXPR, FIX_TRUNC_EXPR, FIX_CEIL_EXPR,
FIX_FLOOR_EXPR, FIX_ROUND_EXPR, FLOAT_EXPR, EXPON_EXPR, NEGATE_EXPR,
MIN_EXPR, MAX_EXPR, ABS_EXPR, FFS_EXPR, LSHIFT_EXPR, RSHIFT_EXPR,
LROTATE_EXPR, RROTATE_EXPR, BIT_IOR_EXPR, BIT_XOR_EXPR, BIT_AND_EXPR,
BIT_ANDTC_EXPR, BIT_NOT_EXPR, TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR,
TRUTH_AND_EXPR, TRUTH_OR_EXPR, TRUTH_XOR_EXPR, TRUTH_NOT_EXPR, LT_EXPR,
LE_EXPR, GT_EXPR, GE_EXPR, EQ_EXPR, NE_EXPR, IN_EXPR, SET_LE_EXPR,
CARD_EXPR, RANGE_EXPR, CONVERT_EXPR, NOP_EXPR, NON_LVALUE_EXPR, SAVE_EXPR,
UNSAVE_EXPR, RTL_EXPR, ADDR_EXPR, REFERENCE_EXPR, ENTRY_VALUE_EXPR,
COMPLEX_EXPR, CONJ_EXPR, REALPART_EXPR, IMAGPART_EXPR, PREDECREMENT_EXPR,
PREINCREMENT_EXPR, POSTDECREMENT_EXPR, POSTINCREMENT_EXPR, VA_ARG_EXPR,
TRY_CATCH_EXPR, TRY_FINALLY_EXPR, GOTO_SUBROUTINE_EXPR, POPDHC_EXPR,
POPDCC_EXPR, LABEL_EXPR, GOTO_EXPR, RETURN_EXPR, EXIT_EXPR, LOOP_EXPR,
LABELED_BLOCK_EXPR, EXIT_BLOCK_EXPR, EXPR_WITH_FILE_LOCATION, SWITCH_EXPR,
LAST_AND_UNUSED_TREE_CODE };
extern char tree_code_type[256];
extern int tree_code_length[256];
extern char *tree_code_name[256];
typedef union tree_node *tree;
struct tree_common
{
union tree_node *chain;
union tree_node *type;
enum tree_code code : 8;
unsigned side_effects_flag : 1;
unsigned constant_flag : 1;
unsigned permanent_flag : 1;
unsigned addressable_flag : 1;
unsigned volatile_flag : 1;
unsigned readonly_flag : 1;
unsigned unsigned_flag : 1;
unsigned asm_written_flag: 1;
unsigned used_flag : 1;
unsigned raises_flag : 1;
unsigned static_flag : 1;
unsigned public_flag : 1;
unsigned private_flag : 1;
unsigned protected_flag : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
unsigned lang_flag_2 : 1;
unsigned lang_flag_3 : 1;
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
};
extern tree _tree_check_failed (const tree, enum tree_code)
__attribute__ ((__noreturn__));
extern tree _tree_class_check_failed (const tree, char)
__attribute__ ((__noreturn__));
struct tree_identifier
{
char common[sizeof (struct tree_common)];
int length;
char *pointer;
};
struct tree_decl
{
char common[sizeof (struct tree_common)];
char *filename;
int linenum;
unsigned int uid;
union tree_node *size;
int mode : 8;
unsigned external_flag : 1;
unsigned nonlocal_flag : 1;
unsigned regdecl_flag : 1;
unsigned inline_flag : 1;
unsigned bit_field_flag : 1;
unsigned virtual_flag : 1;
unsigned ignored_flag : 1;
unsigned abstract_flag : 1;
unsigned in_system_header_flag : 1;
unsigned common_flag : 1;
unsigned defer_output : 1;
unsigned transparent_union : 1;
unsigned static_ctor_flag : 1;
unsigned static_dtor_flag : 1;
unsigned artificial_flag : 1;
unsigned weak_flag : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
unsigned lang_flag_2 : 1;
unsigned lang_flag_3 : 1;
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
unsigned lang_flag_7 : 1;
unsigned non_addr_const_p : 1;
unsigned no_instrument_function_entry_exit : 1;
unsigned no_check_memory_usage : 1;
unsigned comdat_flag : 1;
union {
int i;
unsigned int u;
} frame_size;
union tree_node *name;
union tree_node *context;
union tree_node *arguments;
union tree_node *result;
union tree_node *initial;
union tree_node *abstract_origin;
union tree_node *assembler_name;
union tree_node *section_name;
union tree_node *machine_attributes;
struct rtx_def *rtl;
struct rtx_def *live_range_rtl;
union {
struct rtx_def *r;
int i;
} saved_insns;
union tree_node *vindex;
int pointer_alias_set;
struct lang_decl *lang_specific;
};
union tree_node
{
struct tree_common common;
struct tree_decl decl;
struct tree_identifier identifier;
};
char *
decl_name(decl)
tree decl;
{
return (
(tree_code_type[decl->common.code] == 'd'
? decl
: _tree_class_check_failed(decl, 'd')
)->decl.name->common.code == IDENTIFIER_NODE
? (tree_code_type[decl->common.code] == 'd'
? decl
: _tree_class_check_failed(decl, 'd'))
: _tree_check_failed(
(tree_code_type[decl->common.code] == 'd'
? decl
: _tree_class_check_failed(decl, 'd')
)->decl.name,
IDENTIFIER_NODE)
)->decl.name->identifier.pointer;