From patchwork Fri Apr 30 08:18:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Uros Bizjak X-Patchwork-Id: 1472068 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=YZhoVQ/K; dkim-atps=neutral Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FWld515tVz9sj0 for ; Fri, 30 Apr 2021 18:18:47 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 383E83857815; Fri, 30 Apr 2021 08:18:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 383E83857815 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1619770725; bh=mo8HkroHOmhzwqkzkX9ttzJ14SDCNpOeReH5C0/ivdg=; h=Date:Subject:To:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=YZhoVQ/KnLaONdquov1l1bW4uWhRd5YtyZ0Vs9plGkWjgQPiQsAaXa9n8PC3rV7Ko 9ER8vNmOlJ3fuy90t7f+VEZ8wCc3ciCk44npeiEFtjZasbKNr4tUvGraTz1Y2gO12J aAxCFvpY/JLy7fQZgwokITstx6Lv5RB77fB7FaLs= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-qt1-x830.google.com (mail-qt1-x830.google.com [IPv6:2607:f8b0:4864:20::830]) by sourceware.org (Postfix) with ESMTPS id 018513857815 for ; Fri, 30 Apr 2021 08:18:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 018513857815 Received: by mail-qt1-x830.google.com with SMTP id n22so11531599qtk.9 for ; Fri, 30 Apr 2021 01:18:41 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=mo8HkroHOmhzwqkzkX9ttzJ14SDCNpOeReH5C0/ivdg=; b=kF7IheEdL1oezzUE25KZwlkWfgABpg/3KJI0O7rGoOdm/ARLnFitX3o2TzXdL42UGZ Dr4VRZPFTSY4v9h1uEnvQs1NqIsOF6QrtWnnstJpXn1vH+rrSzR0OgU1abP5RoRY4AGZ aBIanuYdoAiIbPIoCvy/CVk4m9dNj0Zn6iKNyTHxiopU+3cUSDmq4jm2m+jGIRtr4RY9 FHac+msQpJiZQmBi2xZYxm3eXTurNWWk5kkFYxUX1EbdzcLiFVWKrTHaVsX5K3LY+pJp Nur9daXN3jUPPbwMDKuk+EcNJLBVmmML1csy8K/+qhPvxmotNEO5aI0UqMTsiA7nwir4 mg0A== X-Gm-Message-State: AOAM531B/k+TjUIEq6ouBknQJIb2JVQONXd69Y3/20GRkVa9Y97qyweN 7ABIdwXhkrM9ueXfx3218QvwbpVZSB2ewSBgPvwht7+f06unnA== X-Google-Smtp-Source: ABdhPJygIt/ifqE9KqSmNMVEeWMEOp86SMW0cTRrzKHgs0Upkn0QdA5TFfJxcsXtQ7fGFaT8BnVXcE0Zw0GKcxTGG/k= X-Received: by 2002:ac8:6685:: with SMTP id d5mr3565687qtp.60.1619770721274; Fri, 30 Apr 2021 01:18:41 -0700 (PDT) MIME-Version: 1.0 Date: Fri, 30 Apr 2021 10:18:30 +0200 Message-ID: Subject: [PATCH] i386: Introduce reversed ADC and SBB patterns [PR98060] To: "gcc-patches@gcc.gnu.org" X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Uros Bizjak via Gcc-patches From: Uros Bizjak Reply-To: Uros Bizjak Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" The compiler is able to merge LTU comparisons with PLUS or MINUS pattern to form addition with carry (ADC) and subtraction with borrow (SBB) instructions: op = op + carry [ADC $0, op] op = op - carry [SBB $0, op] The patch introduces reversed ADC and SBB insn patterns: op = op + !carry [SBB $-1, op] op = op - !carry [ADC $-1, op] allowing the compiler to also merge GEU comparisons. 2021-04-30 Uroš Bizjak gcc/ PR target/98060 * config/i386/i386.md (*add3_carry_0r): New insn pattern. (*addsi3_carry_zext_0r): Ditto. (*sub3_carry_0): Ditto. (*subsi3_carry_zext_0r): Ditto. * config/i386/predicates.md (ix86_carry_flag_unset_operator): New predicate. * config/i386/i386.c (ix86_rtx_costs) : Also consider ix86_carry_flag_unset_operator to calculate the cost of adc/sbb insn. gcc/testsuite/ PR target/98060 * gcc.target/i386/pr98060.c: New test. Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}. Pushed to master. Uros. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 68f33f96f5a..2f896efb5e2 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -20057,13 +20057,16 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno, } else if (GET_CODE (XEXP (x, 0)) == PLUS) { + rtx op = XEXP (XEXP (x, 0), 0); + /* Add with carry, ignore the cost of adding a carry flag. */ - if (ix86_carry_flag_operator (XEXP (XEXP (x, 0), 0), mode)) + if (ix86_carry_flag_operator (op, mode) + || ix86_carry_flag_unset_operator (op, mode)) *total = cost->add; else { *total = cost->lea; - *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, + *total += rtx_cost (op, mode, outer_code, opno, speed); } @@ -20081,7 +20084,8 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno, if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) <= UNITS_PER_WORD && GET_CODE (XEXP (x, 0)) == MINUS - && ix86_carry_flag_operator (XEXP (XEXP (x, 0), 1), mode)) + && (ix86_carry_flag_operator (XEXP (XEXP (x, 0), 1), mode) + || ix86_carry_flag_unset_operator (XEXP (XEXP (x, 0), 1), mode))) { *total = cost->add; *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index b7f3e36a70c..bb89eb97c69 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -6773,8 +6773,8 @@ (define_insn "@add3_carry" (define_insn "*add3_carry_0" [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") (plus:SWI - (match_operator:SWI 3 "ix86_carry_flag_operator" - [(match_operand 2 "flags_reg_operand") (const_int 0)]) + (match_operator:SWI 2 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]) (match_operand:SWI 1 "nonimmediate_operand" "0"))) (clobber (reg:CC FLAGS_REG))] "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" @@ -6784,6 +6784,20 @@ (define_insn "*add3_carry_0" (set_attr "pent_pair" "pu") (set_attr "mode" "")]) +(define_insn "*add3_carry_0r" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (plus:SWI + (match_operator:SWI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SWI 1 "nonimmediate_operand" "0"))) + (clobber (reg:CC FLAGS_REG))] + "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" + "sbb{}\t{$-1, %0|%0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "")]) + (define_insn "*addsi3_carry_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI @@ -6814,6 +6828,20 @@ (define_insn "*addsi3_carry_zext_0" (set_attr "pent_pair" "pu") (set_attr "mode" "SI")]) +(define_insn "*addsi3_carry_zext_0r" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (match_operator:SI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SI 1 "register_operand" "0")))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" + "sbb{l}\t{$-1, %k0|%k0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI")]) + ;; There is no point to generate ADCX instruction. ADC is shorter and faster. (define_insn "addcarry" @@ -6916,8 +6944,8 @@ (define_insn "*sub3_carry_0" [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") (minus:SWI (match_operand:SWI 1 "nonimmediate_operand" "0") - (match_operator:SWI 3 "ix86_carry_flag_operator" - [(match_operand 2 "flags_reg_operand") (const_int 0)]))) + (match_operator:SWI 2 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]))) (clobber (reg:CC FLAGS_REG))] "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" "sbb{}\t{$0, %0|%0, 0}" @@ -6926,6 +6954,20 @@ (define_insn "*sub3_carry_0" (set_attr "pent_pair" "pu") (set_attr "mode" "")]) +(define_insn "*sub3_carry_0r" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (minus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operator:SWI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)]))) + (clobber (reg:CC FLAGS_REG))] + "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" + "adc{}\t{$-1, %0|%0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "")]) + (define_insn "*subsi3_carry_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI @@ -6958,6 +7000,21 @@ (define_insn "*subsi3_carry_zext_0" (set_attr "pent_pair" "pu") (set_attr "mode" "SI")]) +(define_insn "*subsi3_carry_zext_0r" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI + (match_operand:SI 1 "register_operand" "0") + (match_operator:SI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)])))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" + "adc{l}\t{$-1, %k0|%k0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI")]) + (define_insn "@sub3_carry_ccc" [(set (reg:CCC FLAGS_REG) (compare:CCC diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 04a03a70b46..6dfbb0873be 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1455,6 +1455,22 @@ (define_predicate "ix86_carry_flag_operator" return code == LTU; }) +;; Return true if OP is a valid comparison operator +;; testing carry flag to be unset. +(define_predicate "ix86_carry_flag_unset_operator" + (match_code "geu,ge") +{ + machine_mode inmode = GET_MODE (XEXP (op, 0)); + enum rtx_code code = GET_CODE (op); + + if (inmode == CCFPmode) + code = ix86_fp_compare_code_to_integer (code); + else if (inmode != CCmode && inmode != CCCmode && inmode != CCGZmode) + return false; + + return code == GEU; +}) + ;; Return true if this comparison only requires testing one flag bit. (define_predicate "ix86_trivial_fp_comparison_operator" (match_code "gt,ge,unlt,unle,uneq,ltgt,ordered,unordered")) diff --git a/gcc/testsuite/gcc.target/i386/pr98060.c b/gcc/testsuite/gcc.target/i386/pr98060.c new file mode 100644 index 00000000000..f82620ceb64 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98060.c @@ -0,0 +1,47 @@ +/* PR target/98060 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-not "set" } } */ +/* { dg-final { scan-assembler-times "adc" 4 } } */ +/* { dg-final { scan-assembler-times "sbb" 4 } } */ + +int r1 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 >= v1); +} + +int r2 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 <= v1); +} + +int r3 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 > v1); +} + +int r4 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 < v1); +} + +int r5 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 >= v1); +} + +int r6 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 <= v1); +} + +int r7 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 > v1); +} + +int r8 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 < v1); +}