From patchwork Fri Jul 12 08:08:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1131205 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-504966-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=arm.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="ABrnC305"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45lQXh6rzfz9s8m for ; Fri, 12 Jul 2019 18:08:18 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type; q=dns; s= default; b=k3ThlYLmrwQKJqYK/Wj9y0zz5nO5ZA9lXeAjIMQPngiSHCpv5phlH EcopONeRzy/LwkQgijJIXSg+QL+A7ZZloRQv+h+AwfKl0IpeaJ5CwbJUICeW9FXP 3XELsDM9r5KbN9x3Vt2sCUiKOCJCmPMD051wmx74JkP543KRFE9+3g= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type; s= default; bh=LK9Vo2EvP6+ZpAHXwX1ClFRCKEk=; b=ABrnC305Ehw9ZgbcBovl iICy92XhyRvOVC8RzPS02VoCR19HmIHx043kldZa6Pxbv54mzy03/57QpM7mlB2l rIEq+e2pcuSPndLWJhbriJyWnc3zP88Vxf7o8egR8k8hKU+ILkiNrX2gmsmkxdI/ FuXTx6gzToneyAQluhjcbuo= Received: (qmail 42444 invoked by alias); 12 Jul 2019 08:08:11 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 42435 invoked by uid 89); 12 Jul 2019 08:08:11 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-8.3 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3 autolearn=ham version=3.3.1 spammy=(unknown), sk:signed_ X-HELO: foss.arm.com Received: from foss.arm.com (HELO foss.arm.com) (217.140.110.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 12 Jul 2019 08:08:09 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 90CD8337 for ; Fri, 12 Jul 2019 01:08:07 -0700 (PDT) Received: from localhost (e121540-lin.manchester.arm.com [10.32.98.39]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3495E3F59C for ; Fri, 12 Jul 2019 01:08:07 -0700 (PDT) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: Rewrite some jump.c routines to use flags Date: Fri, 12 Jul 2019 09:08:06 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 This patch rewrites some jump.c routines to operate on flags that describe comparisons rather than handling each comparison code separately. This in turn makes it easier to add some new routines in the next patch. Maybe the change isn't worth it for swap_condition, unsigned_condition and signed_condition, but it does make comparison_dominates_p simpler. The patch also has the effect of making signed_condition accept all FP comparisons, rather than just those that are used for integers. I don't think that's particularly useful, but it doesn't seem harmful either, since all FP comparisons are signed. Tested on aarch64-linux-gnu, aarch64_be-elf and x86_64-linux-gnu. OK to install? Richard 2019-07-12 Richard Sandiford gcc/ * jump.c (FLAGS_EQ, FLAGS_LT, FLAGS_GT, FLAGS_UNORDERED, FLAGS_ORDER) (FLAGS_SIGNED, FLAGS_UNSIGNED, FLAGS_SIGNEDNESS, FLAGS_CAN_TRAP): New defines. (condition_to_flags, flags_to_condition): New functions. (swap_condition, unsigned_condition, signed_condition) (comparison_dominates_p): Use them. Index: gcc/jump.c =================================================================== --- gcc/jump.c 2019-03-08 18:15:26.828777872 +0000 +++ gcc/jump.c 2019-07-12 09:06:52.043241422 +0100 @@ -65,6 +65,95 @@ static void mark_jump_label_asm (rtx, rt static void redirect_exp_1 (rtx *, rtx, rtx, rtx_insn *); static int invert_exp_1 (rtx, rtx_insn *); +/* Flags that describe when a condition is true. */ +const int FLAGS_EQ = 0x1; +const int FLAGS_LT = 0x2; +const int FLAGS_GT = 0x4; +const int FLAGS_UNORDERED = 0x8; +const int FLAGS_ORDER = 0xf; + +/* When describing an existing condition, these flags say whether the + inputs are interpreted as signed and whether they are interpreted as + unsigned. When asking for a new condition, the flags say whether + the comparison must handle signed values and whether it must handle + unsigned values. Floats are treated as signed in both cases. */ +const int FLAGS_SIGNED = 0x10; +const int FLAGS_UNSIGNED = 0x20; +const int FLAGS_SIGNEDNESS = FLAGS_SIGNED | FLAGS_UNSIGNED; + +/* When describing an existing condition, this flag says whether the + comparison traps for NaNs. When asking for a new condition, the flag + says whether the comparison is allowed to trap for NaNs. */ +const int FLAGS_CAN_TRAP = 0x40; + +/* Invoke T (CODE, ORDER, SIGNEDNESS, CAN_TRAP) for each comparison, where: + + - CODE is the rtl comparison code + - ORDER is the OR of the conditions under which CODE returns true + - SIGNEDNESS is the signedness of COND, or 0 if it is sign-agnostic + - CAN_TRAP is true if CODE can trap on some forms of NaN. */ +#define FOR_MAPPING(T) \ + T (EQ, FLAGS_EQ, 0, true) \ + T (NE, ~FLAGS_EQ, 0, true) \ + T (LTGT, FLAGS_LT | FLAGS_GT, 0, true) \ + T (LT, FLAGS_LT, FLAGS_SIGNED, true) \ + T (LE, FLAGS_LT | FLAGS_EQ, FLAGS_SIGNED, true) \ + T (GT, FLAGS_GT, FLAGS_SIGNED, true) \ + T (GE, FLAGS_GT | FLAGS_EQ, FLAGS_SIGNED, true) \ + T (LTU, FLAGS_LT, FLAGS_UNSIGNED, false) \ + T (LEU, FLAGS_LT | FLAGS_EQ, FLAGS_UNSIGNED, false) \ + T (GTU, FLAGS_GT, FLAGS_UNSIGNED, false) \ + T (GEU, FLAGS_GT | FLAGS_EQ, FLAGS_UNSIGNED, false) \ + T (ORDERED, ~FLAGS_UNORDERED, FLAGS_SIGNED, false) \ + T (UNORDERED, FLAGS_UNORDERED, FLAGS_SIGNED, false) \ + T (UNEQ, FLAGS_UNORDERED | FLAGS_EQ, FLAGS_SIGNED, false) \ + T (UNLT, FLAGS_UNORDERED | FLAGS_LT, FLAGS_SIGNED, false) \ + T (UNLE, ~FLAGS_GT, FLAGS_SIGNED, false) \ + T (UNGT, FLAGS_UNORDERED | FLAGS_GT, FLAGS_SIGNED, false) \ + T (UNGE, ~FLAGS_LT, FLAGS_SIGNED, false) + +/* Describe comparison CODE as a bitmask of FLAGS_*. */ + +static unsigned int +condition_to_flags (rtx_code code) +{ +#define CASE(CODE, ORDER, SIGNEDNESS, CAN_TRAP) \ + case CODE: \ + return (((ORDER) & FLAGS_ORDER) \ + | SIGNEDNESS \ + | (CAN_TRAP ? FLAGS_CAN_TRAP : 0)); + + switch (code) + { + FOR_MAPPING (CASE); + default: + gcc_unreachable (); + } + +#undef CASE +} + +/* Return the comparison code that implements FLAGS_* bitmask FLAGS. + Assert on failure if FORCE, otherwise return UNKNOWN. */ + +static rtx_code +flags_to_condition (unsigned int flags, bool force) +{ +#define TEST(CODE, ORDER, SIGNEDNESS, CAN_TRAP) \ + if (((flags ^ (ORDER)) & FLAGS_ORDER) == 0 \ + && (!SIGNEDNESS \ + || (flags & ~SIGNEDNESS & FLAGS_SIGNEDNESS) == 0) \ + && (!CAN_TRAP || (flags & FLAGS_CAN_TRAP) != 0)) \ + return CODE; + + FOR_MAPPING (TEST); + + gcc_assert (!force); + return UNKNOWN; +#undef TEST +} +#undef FOR_MAPPING + /* Worker for rebuild_jump_labels and rebuild_jump_labels_chain. */ static void rebuild_jump_labels_1 (rtx_insn *f, bool count_forced) @@ -583,44 +672,11 @@ reverse_condition_maybe_unordered (enum enum rtx_code swap_condition (enum rtx_code code) { - switch (code) - { - case EQ: - case NE: - case UNORDERED: - case ORDERED: - case UNEQ: - case LTGT: - return code; - - case GT: - return LT; - case GE: - return LE; - case LT: - return GT; - case LE: - return GE; - case GTU: - return LTU; - case GEU: - return LEU; - case LTU: - return GTU; - case LEU: - return GEU; - case UNLT: - return UNGT; - case UNLE: - return UNGE; - case UNGT: - return UNLT; - case UNGE: - return UNLE; - - default: - gcc_unreachable (); - } + unsigned int flags = condition_to_flags (code); + flags = ((flags & ~(FLAGS_GT | FLAGS_LT)) + | (flags & FLAGS_GT ? FLAGS_LT : 0) + | (flags & FLAGS_LT ? FLAGS_GT : 0)); + return flags_to_condition (flags, true); } /* Given a comparison CODE, return the corresponding unsigned comparison. @@ -630,28 +686,8 @@ swap_condition (enum rtx_code code) enum rtx_code unsigned_condition (enum rtx_code code) { - switch (code) - { - case EQ: - case NE: - case GTU: - case GEU: - case LTU: - case LEU: - return code; - - case GT: - return GTU; - case GE: - return GEU; - case LT: - return LTU; - case LE: - return LEU; - - default: - gcc_unreachable (); - } + unsigned int flags = condition_to_flags (code); + return flags_to_condition ((flags & ~FLAGS_SIGNED) | FLAGS_UNSIGNED, true); } /* Similarly, return the signed version of a comparison. */ @@ -659,28 +695,8 @@ unsigned_condition (enum rtx_code code) enum rtx_code signed_condition (enum rtx_code code) { - switch (code) - { - case EQ: - case NE: - case GT: - case GE: - case LT: - case LE: - return code; - - case GTU: - return GT; - case GEU: - return GE; - case LTU: - return LT; - case LEU: - return LE; - - default: - gcc_unreachable (); - } + unsigned int flags = condition_to_flags (code); + return flags_to_condition ((flags & ~FLAGS_UNSIGNED) | FLAGS_SIGNED, true); } /* Return nonzero if CODE1 is more strict than CODE2, i.e., if the @@ -695,74 +711,12 @@ comparison_dominates_p (enum rtx_code co if (code1 == UNKNOWN || code2 == UNKNOWN) return 0; - if (code1 == code2) - return 1; - - switch (code1) - { - case UNEQ: - if (code2 == UNLE || code2 == UNGE) - return 1; - break; - - case EQ: - if (code2 == LE || code2 == LEU || code2 == GE || code2 == GEU - || code2 == ORDERED) - return 1; - break; - - case UNLT: - if (code2 == UNLE || code2 == NE) - return 1; - break; - - case LT: - if (code2 == LE || code2 == NE || code2 == ORDERED || code2 == LTGT) - return 1; - break; - - case UNGT: - if (code2 == UNGE || code2 == NE) - return 1; - break; - - case GT: - if (code2 == GE || code2 == NE || code2 == ORDERED || code2 == LTGT) - return 1; - break; - - case GE: - case LE: - if (code2 == ORDERED) - return 1; - break; - - case LTGT: - if (code2 == NE || code2 == ORDERED) - return 1; - break; - - case LTU: - if (code2 == LEU || code2 == NE) - return 1; - break; - - case GTU: - if (code2 == GEU || code2 == NE) - return 1; - break; - - case UNORDERED: - if (code2 == NE || code2 == UNEQ || code2 == UNLE || code2 == UNLT - || code2 == UNGE || code2 == UNGT) - return 1; - break; - - default: - break; - } - - return 0; + unsigned int flags1 = condition_to_flags (code1); + unsigned int flags2 = condition_to_flags (code2); + /* Make sure that the conditions do not use different sign interpretations + and that FLAGS2 contains every condition that FLAGS1 contains. */ + return (((flags1 | flags2) & FLAGS_SIGNEDNESS) != FLAGS_SIGNEDNESS + && (flags1 & ~flags2 & FLAGS_ORDER) == 0); } /* Return 1 if INSN is an unconditional jump and nothing else. */