keith@EXPO.LCS.MIT.EDU (Keith Packard) (01/22/89)
Version:
gcc version 1.32, ftp'd from prep Sat Jan 21, 1989.
Synopsis:
Unsigned expression indexing case statements can generate incorrect
comparison branches.
Description:
The case statement has added comparisons to reduce the
number of tests. When the comparisons contain -MAXINT,
the sense of the test is inverted.
From:
Keith Packard
keith@expo.lcs.mit.edu
Repeat by:
unsigned long l;
f ()
{
switch (l) {
case 0x80000000:
return 2;
case 0x70000000:
return 0;
case 0x50000000:
return 1;
default:
return 3;
}
}
gcc -O -S test.c
#NO_APP
gcc_compiled.:
.text
.even
.globl _f
_f:
link a6,#0
movel _l,d0
cmpl #1879048192,d0
jeq L4
/*
* this next comparison should be unsigned as the destination
* fork tests for 0x80000000. The sun assembler converts
* this to
bgts L8
*/
jgt L8
cmpl #1342177280,d0
jeq L5
jra L6
L8:
cmpl #-2147483648,d0
jne L6
moveq #2,d0
jra L1
L4:
clrl d0
jra L1
L5:
moveq #1,d0
jra L1
L6:
moveq #3,d0
L1:
unlk a6
rts
.comm _l,4
Fix:
The trouble lies in expand_end_case. It was assuming that the index
expression was of signed type. In the example, this is not so.
Here is an obvious fix; perhaps a more correct solution exists as
well?
*** /tmp/,RCSt1a04922 Sun Jan 22 00:43:05 1989
--- stmt.c Sun Jan 22 00:34:50 1989
***************
*** 2194,2199 ****
--- 2194,2200 ----
rtx before_case;
register struct nesting *thiscase = case_stack;
tree index_expr = thiscase->data.case_stmt.index_expr;
+ int unsigned_case;
do_pending_stack_adjust ();
***************
*** 2218,2223 ****
--- 2219,2227 ----
/* Get upper and lower bounds of case values.
Also convert all the case values to the index expr's data type. */
+ unsigned_case = 0;
+ if (TREE_TYPE (index_expr)->common.unsigned_attr)
+ unsigned_case = 1;
count = 0;
for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
{
***************
*** 2239,2247 ****
}
else
{
! if (INT_CST_LT (n->low, minval))
minval = n->low;
! if (INT_CST_LT (maxval, n->high))
maxval = n->high;
}
/* A range counts double, since it requires two compares. */
--- 2243,2255 ----
}
else
{
! if (unsigned_case ?
! INT_CST_LT_UNSIGNED (n->low, minval) :
! INT_CST_LT (n->low, minval))
minval = n->low;
! if (unsigned_case ?
! INT_CST_LT_UNSIGNED (maxval, n->high) :
! INT_CST_LT (maxval, n->high))
maxval = n->high;
}
/* A range counts double, since it requires two compares. */
***************
*** 2318,2324 ****
default code is emitted. */
balance_case_nodes (&thiscase->data.case_stmt.case_list, 0);
emit_case_nodes (index, thiscase->data.case_stmt.case_list,
! default_label);
emit_jump_if_reachable (default_label);
}
}
--- 2326,2332 ----
default code is emitted. */
balance_case_nodes (&thiscase->data.case_stmt.case_list, 0);
emit_case_nodes (index, thiscase->data.case_stmt.case_list,
! default_label, unsigned_case);
emit_jump_if_reachable (default_label);
}
}
***************
*** 2656,2666 ****
code for out of bound conditions on the current node node. */
static void
! emit_case_nodes (index, node, default_label)
tree index;
case_node_ptr node;
tree default_label;
{
if (node->test_label)
{
/* If this test node requires a label it follows that
--- 2664,2685 ----
code for out of bound conditions on the current node node. */
static void
! emit_case_nodes (index, node, default_label, unsigned_case)
tree index;
case_node_ptr node;
tree default_label;
+ int unsigned_case;
{
+ rtx (*bgt)(), (*blt)(), (*bge)(), (*ble)();
+ extern rtx gen_bgt (), gen_bgtu (),
+ gen_blt (), gen_bltu (),
+ gen_bge (), gen_bgeu (),
+ gen_ble (), gen_bleu ();
+
+ bgt = unsigned_case ? gen_bgtu : gen_bgt;
+ blt = unsigned_case ? gen_bltu : gen_blt;
+ bge = unsigned_case ? gen_bgeu : gen_bge;
+ ble = unsigned_case ? gen_bleu : gen_ble;
if (node->test_label)
{
/* If this test node requires a label it follows that
***************
*** 2683,2689 ****
if (node_is_bounded (node->right))
{
! emit_jump_insn (gen_bgt (label_rtx (node->right->code_label)));
if (node_is_bounded (node->left))
emit_jump (label_rtx (node->left->code_label));
else
--- 2702,2708 ----
if (node_is_bounded (node->right))
{
! emit_jump_insn ((*bgt) (label_rtx (node->right->code_label)));
if (node_is_bounded (node->left))
emit_jump (label_rtx (node->left->code_label));
else
***************
*** 2692,2703 ****
else
{
if (node_is_bounded (node->left))
! emit_jump_insn (gen_blt (label_rtx (node->left->code_label)));
else
{
node->right->test_label =
build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
! emit_jump_insn (gen_bgt (label_rtx (node->right->test_label)));
emit_case_nodes (index, node->left, default_label);
}
emit_case_nodes (index, node->right, default_label);
--- 2711,2722 ----
else
{
if (node_is_bounded (node->left))
! emit_jump_insn ((*blt) (label_rtx (node->left->code_label)));
else
{
node->right->test_label =
build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
! emit_jump_insn ((*bgt) (label_rtx (node->right->test_label)));
emit_case_nodes (index, node->left, default_label);
}
emit_case_nodes (index, node->right, default_label);
***************
*** 2713,2719 ****
if we it avoid only one right child;
it costs too much space to save so little time. */
if (node->right->right && !node_has_low_bound (node))
! emit_jump_insn (gen_blt (default_label));
if (node_is_bounded (node->right))
emit_jump (label_rtx (node->right->code_label));
else
--- 2732,2738 ----
if we it avoid only one right child;
it costs too much space to save so little time. */
if (node->right->right && !node_has_low_bound (node))
! emit_jump_insn ((*blt) (default_label));
if (node_is_bounded (node->right))
emit_jump (label_rtx (node->right->code_label));
else
***************
*** 2741,2747 ****
/* Right hand node is fully bounded so we can
eliminate any testing and branch directly
to the target code. */
! emit_jump_insn (gen_bgt (label_rtx (node->right->code_label)));
}
else
{
--- 2760,2766 ----
/* Right hand node is fully bounded so we can
eliminate any testing and branch directly
to the target code. */
! emit_jump_insn ((*bgt) (label_rtx (node->right->code_label)));
}
else
{
***************
*** 2749,2758 ****
a label to put on the cmp code. */
node->right->test_label =
build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
! emit_jump_insn (gen_bgt (label_rtx (node->right->test_label)));
}
emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! emit_jump_insn (gen_bge (label_rtx (node->code_label)));
if (node_is_bounded (node->left))
{
/* Left hand node is fully bounded so we can
--- 2768,2777 ----
a label to put on the cmp code. */
node->right->test_label =
build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
! emit_jump_insn ((*bgt) (label_rtx (node->right->test_label)));
}
emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! emit_jump_insn ((*bge) (label_rtx (node->code_label)));
if (node_is_bounded (node->left))
{
/* Left hand node is fully bounded so we can
***************
*** 2772,2781 ****
if (!node_has_low_bound (node))
{
emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! emit_jump_insn (gen_blt (default_label));
}
emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, 0);
! emit_jump_insn (gen_ble (label_rtx (node->code_label)));
if (node_is_bounded (node->right))
{
/* Right hand node is fully bounded so we can
--- 2791,2800 ----
if (!node_has_low_bound (node))
{
emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! emit_jump_insn ((*blt) (default_label));
}
emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, 0);
! emit_jump_insn ((*ble) (label_rtx (node->code_label)));
if (node_is_bounded (node->right))
{
/* Right hand node is fully bounded so we can