From patchwork Fri May 5 09:41:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jie Mei X-Patchwork-Id: 1777518 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=oss-cipunited-com.20200927.dkim.feishu.cn header.i=@oss-cipunited-com.20200927.dkim.feishu.cn header.a=rsa-sha256 header.s=s1 header.b=SVKCPULG; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QCQhr1bR9z20fg for ; Fri, 5 May 2023 19:42:52 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 801D93853D18 for ; Fri, 5 May 2023 09:42:38 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from s01.bc.larksuite.com (s01.bc.larksuite.com [209.127.230.17]) by sourceware.org (Postfix) with UTF8SMTPS id 72D4838555B0 for ; Fri, 5 May 2023 09:41:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 72D4838555B0 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.cipunited.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=oss.cipunited.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=s1; d=oss-cipunited-com.20200927.dkim.feishu.cn; t=1683279706; h=from:subject:mime-version:from:date:message-id:subject:to:cc: reply-to:content-type:mime-version:in-reply-to:message-id; bh=TEA79GEkBfgWBb3CW+LkF8P5pGkrsiaijkFZLuRiA1U=; b=SVKCPULGxdvCE8qHrmyIJmOY22MnqWnaT7dlLACIcd0qB+93TQEsEZAnK9gwOnylNua6L8 Bv1bn+9v7ulCB2k3rwkPeCE+5j0ta6S+zaG0pniU/2FZuauqdZxKAg0wLwctOim1cT9fAr 3l4TxQq1AZImQN/exDjLgW8i1bMD7JNVhsTUK6B/tyYsO3eTChaxV+g5TgQ9QIqJvd9dej 9ORKsfirlVBXjf1s5KosuMubi61ClzDKlpgJkwXUCN5l2uy5GLVpOy97ZuTx/OUfMPMNBN Usa+eqWyOuEnGUYEQ8XLAT/itd/5BHkDV3q9FYkickBPwOP2BiOVYJHvngupgg== To: From: "Jie Mei" Subject: [PATCH 4/8] MIPS: Add bitwise instructions for mips16e2 Date: Fri, 05 May 2023 17:41:36 +0800 Mime-Version: 1.0 X-Mailer: git-send-email 2.40.1 In-Reply-To: X-Lms-Return-Path: References: Message-Id: <2a19881c6313ec07482835d72dd74bdd128601a7.1683273172.git.jie.mei@oss.cipunited.com> X-Spam-Status: No, score=-12.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, HTML_MESSAGE, KAM_NUMSUBJECT, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-Content-Filtered-By: Mailman/MimeDel 2.1.29 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: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" There are shortened bitwise instructions in the mips16e2 ASE, for instance, ANDI, ORI/XORI, EXT, INS etc. . This patch adds these instrutions with corresponding tests. gcc/ChangeLog: * gcc/config/mips/constraints.md(Yz): New constraints for mips16e2. * gcc/config/mips/mips-protos.h(mips_bit_clear_p): Declared new function. (mips_bit_clear_info): Same as above. * gcc/config/mips/mips.cc(mips_bit_clear_info): New function for generating instructions. (mips_bit_clear_p): Same as above. * gcc/config/mips/mips.h(ISA_HAS_EXT_INS): Add clause for ISA_HAS_MIPS16E2. * gcc/config/mips/mips.md(extended_mips16): Generates EXT and INS instructions. (*and3): Generates INS instruction. (*and3_mips16): Generates EXT, INS and ANDI instructions. (ior3): Add logics for ORI instruction. (*ior3_mips16_asmacro): Generates ORI instrucion. (*ior3_mips16): Add logics for XORI instruction. (*xor3_mips16): Generates XORI instrucion. (*extzv): Add logics for EXT instruction. (*insv): Add logics for INS instruction. * gcc/config/mips/predicates.md(bit_clear_operand): New predicate for generating bitwise instructions. (and_reg_operand): Add logics for generating bitwise instructions. gcc/testsuite/ChangeLog: * gcc.target/mips/mips16e2.c: New tests for mips16e2. --- gcc/config/mips/constraints.md | 4 + gcc/config/mips/mips-protos.h | 4 + gcc/config/mips/mips.cc | 67 ++++++++++++++- gcc/config/mips/mips.h | 3 +- gcc/config/mips/mips.md | 91 ++++++++++++++++---- gcc/config/mips/predicates.md | 13 ++- gcc/testsuite/gcc.target/mips/mips16e2.c | 102 +++++++++++++++++++++++ 7 files changed, 263 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/mips16e2.c diff --git a/gcc/config/mips/constraints.md b/gcc/config/mips/constraints.md index 49d1a43c613..22d4d84f074 100644 --- a/gcc/config/mips/constraints.md +++ b/gcc/config/mips/constraints.md @@ -264,6 +264,10 @@ (and (match_code "const_vector") (match_test "op == CONST0_RTX (mode)"))) +(define_constraint "Yz" + "@internal" + (match_operand 0 "bit_clear_operand")) + (define_constraint "YA" "@internal An unsigned 6-bit constant." diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index 20483469105..2791b9f220a 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -388,4 +388,8 @@ extern void mips_register_frame_header_opt (void); extern void mips_expand_vec_cond_expr (machine_mode, machine_mode, rtx *); extern void mips_expand_vec_cmp_expr (rtx *); +extern bool mips_bit_clear_p (enum machine_mode, unsigned HOST_WIDE_INT); +extern void mips_bit_clear_info (enum machine_mode, unsigned HOST_WIDE_INT, + int *, int *); + #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc index be470bbb50d..d86911d10c2 100644 --- a/gcc/config/mips/mips.cc +++ b/gcc/config/mips/mips.cc @@ -3895,6 +3895,10 @@ mips16_constant_cost (int code, HOST_WIDE_INT x) return 0; return -1; + case ZERO_EXTRACT: + /* The bit position and size are immediate operands. */ + return ISA_HAS_EXT_INS ? COSTS_N_INSNS (1) : -1; + default: return -1; } @@ -22753,7 +22757,68 @@ mips_asm_file_end (void) if (NEED_INDICATE_EXEC_STACK) file_end_indicate_exec_stack (); } - + +void +mips_bit_clear_info (enum machine_mode mode, unsigned HOST_WIDE_INT m, + int *start_pos, int *size) +{ + unsigned int shift = 0; + unsigned int change_count = 0; + unsigned int prev_val = 1; + unsigned int curr_val = 0; + unsigned int end_pos = GET_MODE_SIZE (mode) * BITS_PER_UNIT; + + for (shift = 0 ; shift < (GET_MODE_SIZE (mode) * BITS_PER_UNIT) ; shift++) + { + curr_val = (unsigned int)((m & (unsigned int)(1 << shift)) >> shift); + if (curr_val != prev_val) + { + change_count++; + switch (change_count) + { + case 1: + *start_pos = shift; + break; + case 2: + end_pos = shift; + break; + default: + gcc_unreachable (); + } + } + prev_val = curr_val; + } + *size = (end_pos - *start_pos); +} + +bool +mips_bit_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT m) +{ + unsigned int shift = 0; + unsigned int change_count = 0; + unsigned int prev_val = 1; + unsigned int curr_val = 0; + + if (mode != SImode && mode != VOIDmode) + return false; + + if (!ISA_HAS_EXT_INS) + return false; + + for (shift = 0 ; shift < (UNITS_PER_WORD * BITS_PER_UNIT) ; shift++) + { + curr_val = (unsigned int)((m & (unsigned int)(1 << shift)) >> shift); + if (curr_val != prev_val) + change_count++; + prev_val = curr_val; + } + + if (change_count == 2) + return true; + + return false; +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 8a6e43407c5..cab5ff422a8 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -1266,7 +1266,8 @@ struct mips_cpu_info { #define ISA_HAS_SEB_SEH (mips_isa_rev >= 2 && !TARGET_MIPS16) /* ISA includes the MIPS32/64 rev 2 ext and ins instructions. */ -#define ISA_HAS_EXT_INS (mips_isa_rev >= 2 && !TARGET_MIPS16) +#define ISA_HAS_EXT_INS ((mips_isa_rev >= 2 && !TARGET_MIPS16) \ + || ISA_HAS_MIPS16E2) /* ISA has instructions for accessing top part of 64-bit fp regs. */ #define ISA_HAS_MXHC1 (!TARGET_FLOAT32 \ diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 9de5013aad1..9f652310aa2 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -461,7 +461,7 @@ (if_then_else (ior ;; In general, constant-pool loads are extended ;; instructions. We don't yet optimize for 16-bit ;; PC-relative references. - (eq_attr "move_type" "sll0,loadpool") + (eq_attr "move_type" "sll0,loadpool,ext_ins") (eq_attr "jal" "direct") (eq_attr "got" "load")) (const_string "yes") @@ -3312,12 +3312,13 @@ ;; register =op1 x (define_insn "*and3" - [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d") - (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d") - (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))] + [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d,d") + (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d,0") + (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d,Yz")))] "!TARGET_MIPS16 && and_operands_ok (mode, operands[1], operands[2])" { int len; + int pos; switch (which_alternative) { @@ -3342,20 +3343,28 @@ case 7: case 8: return "and\t%0,%1,%2"; + case 9: + mips_bit_clear_info (mode, INTVAL (operands[2]), &pos, &len); + operands[1] = GEN_INT (pos); + operands[2] = GEN_INT (len); + return "ins\t%0,$0,%1,%2"; default: gcc_unreachable (); } } - [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical") - (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*") + [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical,ext_ins") + (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*,*") (set_attr "mode" "")]) (define_insn "*and3_mips16" - [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d") - (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%W,W,W,d,0") - (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d")))] + [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d,d") + (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%W,W,W,d,0,d,0,0?") + (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d,Yx,Yz,K")))] "TARGET_MIPS16 && and_operands_ok (mode, operands[1], operands[2])" { + int len; + int pos; + switch (which_alternative) { case 0: @@ -3371,12 +3380,32 @@ return "#"; case 4: return "and\t%0,%2"; + case 5: + len = low_bitmask_len (mode, INTVAL (operands[2])); + operands[2] = GEN_INT (len); + return "ext\t%0,%1,0,%2"; + case 6: + mips_bit_clear_info (mode, INTVAL (operands[2]), &pos, &len); + operands[1] = GEN_INT (pos); + operands[2] = GEN_INT (len); + return "ins\t%0,$0,%1,%2"; + case 7: + return "andi\t%0,%x2"; default: gcc_unreachable (); } } - [(set_attr "move_type" "load,load,load,shift_shift,logical") - (set_attr "mode" "")]) + [(set_attr "move_type" "load,load,load,shift_shift,logical,ext_ins,ext_ins,andi") + (set_attr "mode" "") + (set_attr "extended_mips16" "no,no,no,no,no,yes,yes,yes") + (set (attr "enabled") + (cond [(and (eq_attr "alternative" "7") + (not (match_test "ISA_HAS_MIPS16E2"))) + (const_string "no") + (and (eq_attr "alternative" "0,1") + (match_test "!GENERATE_MIPS16E")) + (const_string "no")] + (const_string "yes")))]) (define_expand "ior3" [(set (match_operand:GPR 0 "register_operand") @@ -3384,7 +3413,7 @@ (match_operand:GPR 2 "uns_arith_operand")))] "" { - if (TARGET_MIPS16) + if (TARGET_MIPS16 && !ISA_HAS_MIPS16E2) operands[2] = force_reg (mode, operands[2]); }) @@ -3401,11 +3430,23 @@ (set_attr "compression" "micromips,*,*") (set_attr "mode" "")]) +(define_insn "*ior3_mips16_asmacro" + [(set (match_operand:GPR 0 "register_operand" "=d,d") + (ior:GPR (match_operand:GPR 1 "register_operand" "%0,0") + (match_operand:GPR 2 "uns_arith_operand" "d,K")))] + "ISA_HAS_MIPS16E2" + "@ + or\t%0,%2 + ori\t%0,%x2" + [(set_attr "alu_type" "or") + (set_attr "mode" "") + (set_attr "extended_mips16" "*,yes")]) + (define_insn "*ior3_mips16" [(set (match_operand:GPR 0 "register_operand" "=d") (ior:GPR (match_operand:GPR 1 "register_operand" "%0") (match_operand:GPR 2 "register_operand" "d")))] - "TARGET_MIPS16" + "TARGET_MIPS16 && !ISA_HAS_MIPS16E2" "or\t%0,%2" [(set_attr "alu_type" "or") (set_attr "mode" "")]) @@ -3430,19 +3471,31 @@ (set_attr "compression" "micromips,*,*") (set_attr "mode" "")]) +;; We increase statically the cost of the output register for XORI +;; to counterweight LRA cost calculation as XORI tends to be chosen +;; frequently hurting the code size. The reason of not choosing CMPI is +;; that LRA tends to add up the cost of the T register as it is in a small +;; class and a possible reload. In reality, the use of T register comes for +;; free in a number of cases as we don't need any MIPS16 registers. (define_insn "*xor3_mips16" - [(set (match_operand:GPR 0 "register_operand" "=d,t,t,t") - (xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d,d") - (match_operand:GPR 2 "uns_arith_operand" "d,Uub8,K,d")))] + [(set (match_operand:GPR 0 "register_operand" "=d,t,t,t,d?") + (xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d,d,0") + (match_operand:GPR 2 "uns_arith_operand" "d,Uub8,K,d,K")))] "TARGET_MIPS16" "@ xor\t%0,%2 cmpi\t%1,%2 cmpi\t%1,%2 - cmp\t%1,%2" + cmp\t%1,%2 + xori\t%0,%x2" [(set_attr "alu_type" "xor") (set_attr "mode" "") - (set_attr "extended_mips16" "no,no,yes,no")]) + (set_attr "extended_mips16" "no,no,yes,no,yes") + (set (attr "enabled") + (cond [(and (eq_attr "alternative" "4") + (not (match_test "ISA_HAS_MIPS16E2"))) + (const_string "no")] + (const_string "yes")))]) (define_insn "*nor3" [(set (match_operand:GPR 0 "register_operand" "=d") @@ -4342,6 +4395,7 @@ INTVAL (operands[3]))" "ext\t%0,%1,%3,%2" [(set_attr "type" "arith") + (set_attr "extended_mips16" "yes") (set_attr "mode" "")]) (define_insn "*extzv_truncsi_exts" @@ -4392,6 +4446,7 @@ INTVAL (operands[2]))" "ins\t%0,%z3,%2,%1" [(set_attr "type" "arith") + (set_attr "extended_mips16" "yes") (set_attr "mode" "")]) ;; Combiner pattern for cins (clear and insert bit field). We can diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md index 9ffaed689a3..a49c1952d3f 100644 --- a/gcc/config/mips/predicates.md +++ b/gcc/config/mips/predicates.md @@ -170,6 +170,10 @@ (and (match_code "const_int") (match_test "UINTVAL (op) == 0xffffffff"))) +(define_predicate "bit_clear_operand" + (and (match_code "const_int") + (match_test "mips_bit_clear_p (mode, INTVAL (op))"))) + (define_predicate "and_load_operand" (ior (match_operand 0 "qi_mask_operand") (match_operand 0 "hi_mask_operand") @@ -184,8 +188,15 @@ (ior (match_operand 0 "register_operand") (and (not (match_test "TARGET_MIPS16")) (match_operand 0 "const_uns_arith_operand")) + (and (match_test "ISA_HAS_MIPS16E2") + (match_operand 0 "const_uns_arith_operand") + (not (match_operand 0 "hi_mask_operand")) + (not (match_operand 0 "qi_mask_operand"))) + (and (match_test "ISA_HAS_MIPS16E2") + (match_operand 0 "const_uns_arith_operand")) (match_operand 0 "low_bitmask_operand") - (match_operand 0 "si_mask_operand"))) + (match_operand 0 "si_mask_operand") + (match_operand 0 "bit_clear_operand"))) (define_predicate "and_operand" (ior (match_operand 0 "and_load_operand") diff --git a/gcc/testsuite/gcc.target/mips/mips16e2.c b/gcc/testsuite/gcc.target/mips/mips16e2.c new file mode 100644 index 00000000000..ce8b4f1819b --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/mips16e2.c @@ -0,0 +1,102 @@ +/* { dg-options "-mno-abicalls -mgpopt -G8 -mabi=32 -mips16 -mmips16e2" } */ +/* { dg-skip-if "per-function expected output" { *-*-* } { "-flto" } { "" } } */ + +/* ANDI is a two operand instruction. Hence, it won't be generated if src and + * dest are in different registers. */ + +/* { dg-final { scan-assembler "test01:.*\tandi\t.*test01\n" } } */ +unsigned int +test01 (unsigned int a) +{ + return ((a + 0x2) & 0x3ff); +} + +/* Test EXT */ + +/* { dg-final { scan-assembler "test02:.*\text\t.*test02\n" } } */ +struct +{ + unsigned int a:9; + unsigned int d:31; + unsigned int e:9; + unsigned int f:10; +} t02; + +unsigned int +test02 (void) +{ + return t02.f; +} + +/* Use EXT when ANDing with low-order bitmasks. */ + +/* { dg-final { scan-assembler "test03:.*\text\t.*test03\n" } } */ +/* { dg-final { scan-assembler-not "test03.*\tandi?\t.*test03\n" } } */ +unsigned int +test03 (unsigned int x) +{ + return (x & 0x1fffffff); +} + +/* Test INS */ + +/* { dg-final { scan-assembler "test04:.*\tins\t.*test04\n" } } */ +struct +{ + unsigned int i : 9; + unsigned int j : 15; + unsigned int k : 4; +} s04; + +void +test04 (void) +{ + s04.j = 1; +} + +/* Use INS with hardcoded $0. */ + +/* { dg-final { scan-assembler "test05:.*\tins\t\\\$.*,\\\$0.*test05\n" } } */ +struct +{ + unsigned int i : 8; + unsigned int j : 9; + unsigned int k : 10; +} __attribute__ ((packed)) s05 __attribute__((aligned(1))); + +void +test05 (void) +{ + s05.k = 0; +} + +/* Use INS when ANDing to clear only one consecutive chunk of bits. */ + +/* { dg-final { scan-assembler "test06:.*\tins\t\\\$.*,\\\$0,11,5.*test06\n" } } */ +/* { dg-final { scan-assembler-not "test06:.*\tandi?\t.*test06\n" } } */ +unsigned int +test06 (unsigned int x) +{ + return (x & 0xffff07ff); +} + +/* ORI is a two operand instruction. Hence, it won't be generated if src and + dest are in different registers. */ + +/* { dg-final { scan-assembler "test07:.*\tori\t.*test07\n" } } */ +unsigned int +test07 (unsigned int a) +{ + return (a + 0x2) | 0x7f0; +} + +/* XORI is a two operand instruction. Hence, it won't be generated if src and + dest are in different registers. */ + +/* { dg-final { scan-assembler "test08:.*\txori\t.*test08\n" } } */ +unsigned int +test08 (unsigned int a) +{ + return ((a + 0x2) ^ 0x3f0); +} +