;; ALU operations with zero extensions ;; ;; Copyright (C) 2015-2024 Free Software Foundation, Inc. ;; Contributed by Dimitar Dimitrov ;; ;; This file is part of GCC. ;; ;; GCC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; ;; GCC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING3. If not see ;; . ; All PRU ALU instructions automatically zero-extend their source operands, ; and zero-extract the result into the destination register. This is ; described in the machine description by defining a separate pattern ; for each possible combination of zero_extend and mode for input operands. ; ; An unfortunate side effect is that quite a few invalid RTL patterns are ; generated. For example: ; ... (zero_extend:SI (match_operand:SI ...)) ... ; These patterns are harmless since no pass should generate such RTL. This ; shortcut allows us to keep small and concise machine description patterns. (define_subst_attr "alu2_zext" "alu2_zext_subst" "_z" "_noz") (define_subst_attr "alu3_zext_op0" "alu3_zext_op0_subst" "_z0" "_noz0") (define_subst_attr "alu3_zext_op1" "alu3_zext_op1_subst" "_z1" "_noz1") (define_subst_attr "alu3_zext_op2" "alu3_zext_op2_subst" "_z2" "_noz2") (define_subst_attr "alu3_zext" "alu3_zext_subst" "_z" "_noz") (define_subst_attr "lmbd_zext_op1" "lmbd_zext_op1_subst" "_z1" "_noz1") (define_subst_attr "lmbd_zext_op2" "lmbd_zext_op2_subst" "_z2" "_noz2") (define_subst_attr "lmbd_zext" "lmbd_zext_subst" "_z" "_noz") (define_subst_attr "bitalu_zext" "bitalu_zext_subst" "_z" "_noz") (define_code_iterator ALUOP3 [plus minus and ior xor umin umax ashift lshiftrt]) (define_code_iterator ALUOP3_ZEXT0 [and ior xor umin umax lshiftrt]) (define_code_iterator ALUOP2 [neg not]) ;; Arithmetic Operations (define_insn "add_impl_" [(set (match_operand:EQD 0 "register_operand" "=r,r,r") (plus:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "%r,r,r")) (zero_extend:EQD (match_operand:EQS1 2 "nonmemory_operand" "r,,M"))))] "" "@ add\\t%0, %1, %2 add\\t%0, %1, %u2 sub\\t%0, %1, %n2" [(set_attr "type" "alu")]) (define_insn "sub_impl_" [(set (match_operand:EQD 0 "register_operand" "=r,r") (minus:EQD (zero_extend:EQD (match_operand:EQS0 1 "reg_or_ubyte_operand" "r,")) (zero_extend:EQD (match_operand:EQS1 2 "register_operand" "r,r"))))] "" "@ sub\\t%0, %1, %2 rsb\\t%0, %2, %u1" [(set_attr "type" "alu")]) ;; Left Most Bit Detect instruction. (define_insn "pru_lmbd_impl_" [(set (match_operand:EQD 0 "register_operand" "=r") (unspec:EQD [(zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r")) (zero_extend:EQD (match_operand:EQS1 2 "reg_or_ubyte_operand" "r"))] UNSPEC_LMBD))] "" "lmbd\t%0, %1, %2" [(set_attr "type" "alu")]) (define_insn "neg_impl_" [(set (match_operand:EQD 0 "register_operand" "=r") (neg:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r"))))] "" "rsb\\t%0, %1, 0" [(set_attr "type" "alu")]) (define_insn "one_cmpl_impl_" [(set (match_operand:EQD 0 "register_operand" "=r") (not:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r"))))] "" "not\\t%0, %1" [(set_attr "type" "alu")]) ; Specialized IOR/AND patterns for matching setbit/clearbit instructions. ; ; TODO - allow clrbit and setbit to support (1 << REG) constructs (define_insn "clearbit__" [(set (match_operand:EQD 0 "register_operand" "=r") (and:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r")) (match_operand:EQD 2 "single_zero_operand" "n")))] "" "clr\\t%0, %1, %V2" [(set_attr "type" "alu")]) (define_insn "setbit__" [(set (match_operand:EQD 0 "register_operand" "=r") (ior:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r")) (match_operand:EQD 2 "single_one_operand" "n")))] "" "set\\t%0, %1, %T2" [(set_attr "type" "alu")]) ; Regular ALU ops. For all of them it is safe to present the result as ; zero-extended, because there is no carry or shifted-out bits. (define_insn "_impl_" [(set (match_operand:EQD 0 "register_operand" "=r") (LOGICAL:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "%r")) (zero_extend:EQD (match_operand:EQS1 2 "reg_or_ubyte_operand" "r"))))] "" "\\t%0, %1, %u2" [(set_attr "type" "alu")]) ; Shift left ALU op. Cannot present the result as zero-extended because ; of the shifted-out bits. (define_insn "ashl_impl_" [(set (match_operand:EQD 0 "register_operand" "=r") (ashift:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r")) (zero_extend:EQD (match_operand:EQS1 2 "shift_operand" "rL"))))] "" "lsl\\t%0, %1, %2" [(set_attr "type" "alu")]) ; Shift right ALU op. The result can be presented as zero-extended. (define_insn "lshr_impl_" [(set (match_operand:EQD 0 "register_operand" "=r") (lshiftrt:EQD (zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r")) (zero_extend:EQD (match_operand:EQS1 2 "shift_operand" "rL"))))] "" "lsr\\t%0, %1, %2" [(set_attr "type" "alu")]) ;; Substitutions (define_subst "alu2_zext_subst" [(set (match_operand:EQD 0) (ALUOP2:EQD (zero_extend:EQD (match_operand:EQD 1))))] "" [(set (match_dup 0) (ALUOP2:EQD (match_dup 1)))]) (define_subst "bitalu_zext_subst" [(set (match_operand:EQD 0) (ALUOP3:EQD (zero_extend:EQD (match_operand:EQD 1)) (match_operand:EQD 2)))] "" [(set (match_dup 0) (ALUOP3:EQD (match_dup 1) (match_dup 2)))]) (define_subst "alu3_zext_subst" [(set (match_operand:EQD 0) (ALUOP3:EQD (zero_extend:EQD (match_operand:EQD 1)) (zero_extend:EQD (match_operand:EQD 2))))] "" [(set (match_dup 0) (ALUOP3:EQD (match_dup 1) (match_dup 2)))]) (define_subst "alu3_zext_op1_subst" [(set (match_operand:EQD 0) (ALUOP3:EQD (zero_extend:EQD (match_operand:EQD 1)) (zero_extend:EQD (match_operand:EQS1 2))))] "" [(set (match_dup 0) (ALUOP3:EQD (match_dup 1) (zero_extend:EQD (match_dup 2))))]) (define_subst "alu3_zext_op2_subst" [(set (match_operand:EQD 0) (ALUOP3:EQD (zero_extend:EQD (match_operand:EQS0 1)) (zero_extend:EQD (match_operand:EQD 2))))] "" [(set (match_dup 0) (ALUOP3:EQD (zero_extend:EQD (match_dup 1)) (match_dup 2)))]) ;; Some ALU operations with zero-extended inputs are ;; equivalent to doing the same ALU operation in the ;; smaller mode, and then zero-extending the output. (define_subst "alu3_zext_op0_subst" [(set (match_operand:EQD 0) (ALUOP3_ZEXT0:EQD (zero_extend:EQD (match_operand:EQS0 1)) (zero_extend:EQD (match_operand:EQS0 2))))] "GET_MODE_SIZE (mode) < GET_MODE_SIZE (mode)" [(set (match_dup 0) (zero_extend:EQD (ALUOP3_ZEXT0:EQS0 (match_dup 1) (match_dup 2))))]) (define_subst "lmbd_zext_subst" [(set (match_operand:EQD 0) (unspec:EQD [(zero_extend:EQD (match_operand:EQD 1)) (zero_extend:EQD (match_operand:EQD 2))] UNSPEC_LMBD))] "" [(set (match_dup 0) (unspec:EQD [(match_dup 1) (match_dup 2)] UNSPEC_LMBD))]) (define_subst "lmbd_zext_op1_subst" [(set (match_operand:EQD 0) (unspec:EQD [(zero_extend:EQD (match_operand:EQD 1)) (zero_extend:EQD (match_operand:EQS1 2))] UNSPEC_LMBD))] "" [(set (match_dup 0) (unspec:EQD [(match_dup 1) (zero_extend:EQD (match_dup 2))] UNSPEC_LMBD))]) (define_subst "lmbd_zext_op2_subst" [(set (match_operand:EQD 0) (unspec:EQD [(zero_extend:EQD (match_operand:EQD 1)) (zero_extend:EQD (match_operand:EQD 2))] UNSPEC_LMBD))] "" [(set (match_dup 0) (unspec:EQD [(zero_extend:EQD (match_dup 1)) (match_dup 2)] UNSPEC_LMBD))])