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