;; ALU operations with zero extensions ;; ;; Copyright (C) 2015-2021 Free Software Foundation, Inc. ;; Contributed by Dimitar Dimitrov dimitar@dinux.eu ;; ;; 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 ;; http://www.gnu.org/licenses/.

; 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_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 ALUOP2 [neg not])

;; Arithmetic Operations

(define_insn “add_implEQD:modeEQS0:modeEQS1:mode_<alu3_zext><alu3_zext_op1><alu3_zext_op2>” [(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,EQS1:ubyte_constr,M”))))] "" “@ add\t%0, %1, %2 add\t%0, %1, %u2 sub\t%0, %1, %n2” [(set_attr “type” “alu”)])

(define_insn “sub_implEQD:modeEQS0:modeEQS1:mode_<alu3_zext><alu3_zext_op1><alu3_zext_op2>” [(set (match_operand:EQD 0 “register_operand” “=r,r”) (minus:EQD (zero_extend:EQD (match_operand:EQS0 1 “reg_or_ubyte_operand” “r,EQS0:ubyte_constr”)) (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_implEQD:modeEQS0:modeEQS1:mode_<lmbd_zext><lmbd_zext_op1><lmbd_zext_op2>” [(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” “rEQS1:ubyte_constr”))] UNSPEC_LMBD))] "" “lmbd\t%0, %1, %2” [(set_attr “type” “alu”)])

(define_insn “neg_implEQD:modeEQS0:mode_<alu2_zext>” [(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_implEQD:modeEQS0:mode_<alu2_zext>” [(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_EQD:modeEQS0:mode_<bitalu_zext>” [(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_EQD:modeEQS0:mode_<bitalu_zext>” [(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 (define_insn “implEQD:modeEQS0:modeEQS1:mode<alu3_zext><alu3_zext_op1><alu3_zext_op2>” [(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” “rEQS1:ubyte_constr”))))] "" “<logical_asm>\t%0, %1, %u2” [(set_attr “type” “alu”)])

; Shift ALU ops (define_insn “<shift_op>implEQD:modeEQS0:modeEQS1:mode<alu3_zext><alu3_zext_op1><alu3_zext_op2>” [(set (match_operand:EQD 0 “register_operand” “=r”) (SHIFT:EQD (zero_extend:EQD (match_operand:EQS0 1 “register_operand” “r”)) (zero_extend:EQD (match_operand:EQS1 2 “shift_operand” “rL”))))] "" “<shift_asm>\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)))])

(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))])