;; builtin definitions for DEC VAX.
;; Copyright (C) 2007-2025 Free Software Foundation, Inc.
;;
;; 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
;; .
(define_constants
[
(VUNSPEC_LOCK 100) ; sync lock operations
]
)
(define_mode_attr width [(QI "8") (HI "16") (SI "32")])
(define_mode_attr bb_mem [(QI "m") (HI "Q") (SI "Q")])
(define_int_iterator bit [0 1])
(define_int_attr ccss [(0 "cc") (1 "ss")])
(define_code_iterator any_extend [sign_extend zero_extend])
(define_expand "ffs2"
[(set (match_operand:SI 0 "nonimmediate_operand" "")
(ffs:SI (match_operand:VAXint 1 "general_operand" "")))]
""
"
{
rtx label = gen_label_rtx ();
rtx label_ref = gen_rtx_LABEL_REF (VOIDmode, label);
rtx cond = gen_rtx_NE (VOIDmode, operands[1], const0_rtx);
rtx target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, label_ref, pc_rtx);
emit_insn (gen_ctz2_ccz (operands[0], operands[1]));
emit_jump_insn (gen_rtx_SET (pc_rtx, target));
emit_insn (gen_neg2 (operands[0], const1_rtx));
emit_label (label);
emit_insn (gen_add3 (operands[0], operands[0], const1_rtx));
DONE;
}")
(define_insn_and_split "ctz2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rQ")
(ctz:SI (match_operand:VAXint 1 "general_operand" "nrQT")))]
""
"#"
"reload_completed"
[(parallel
[(set (match_dup 0)
(ctz:SI (match_dup 1)))
(clobber (reg:CC VAX_PSL_REGNUM))])]
"")
(define_insn "*ctz2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rQ")
(ctz:SI (match_operand:VAXint 1 "general_operand" "nrQT")))
(clobber (reg:CC VAX_PSL_REGNUM))]
"reload_completed"
"ffs $0,$,%1,%0")
(define_insn_and_split "ctz2_ccz"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rQ")
(ctz:SI (match_operand:VAXint 1 "general_operand" "nrQT")))]
""
"#"
"reload_completed"
[(parallel
[(set (reg:CCZ VAX_PSL_REGNUM)
(compare:CCZ (match_dup 1)
(const_int 0)))
(set (match_dup 0)
(ctz:SI (match_dup 1)))])]
"")
(define_insn "*ctz2_ccz"
[(set (reg:CCZ VAX_PSL_REGNUM)
(compare:CCZ (match_operand:VAXint 1 "general_operand" "nrQT")
(const_int 0)))
(set (match_operand:SI 0 "nonimmediate_operand" "=rQ")
(ctz:SI (match_dup 1)))]
"reload_completed"
"ffs $0,$,%1,%0")
;; Our FFS hardware instruction supports any field width,
;; so handle narrower inputs directly as well.
(define_peephole2
[(parallel
[(set (match_operand:SI 0 "register_operand")
(any_extend:SI (match_operand:VAXintQH 1 "general_operand")))
(clobber (reg:CC VAX_PSL_REGNUM))])
(parallel
[(set (match_operand:SI 2 "nonimmediate_operand")
(ctz:SI (match_dup 0)))
(clobber (reg:CC VAX_PSL_REGNUM))])]
"rtx_equal_p (operands[0], operands[2]) || peep2_reg_dead_p (2, operands[0])"
[(parallel
[(set (match_dup 2)
(ctz:SI (match_dup 1)))
(clobber (reg:CC VAX_PSL_REGNUM))])]
"")
;; The FFS hardware instruction sets the Z condition code based on
;; the input field rather than the output operand, so the compare
;; elimination pass cannot handle it. Try to get rid of the extra
;; operation by hand.
;;
;; The "ctz2_ccz" patterns require their `operands[1]' not to
;; have a mode dependent address, so all we need to verify is that
;; the two operands are not the same, in which case it's the FFS
;; output rather than input that condition codes are checked for.
(define_peephole2
[(parallel
[(set (match_operand:SI 0 "nonimmediate_operand")
(ctz:SI (match_operand:VAXint 1 "general_operand")))
(clobber (reg:CC VAX_PSL_REGNUM))])
(set (reg:CCZ VAX_PSL_REGNUM)
(compare:CCZ (match_dup 1)
(const_int 0)))]
"!rtx_equal_p (operands[0], operands[1])"
[(parallel
[(set (reg:CCZ VAX_PSL_REGNUM)
(compare:CCZ (match_dup 1)
(const_int 0)))
(set (match_dup 0)
(ctz:SI (match_dup 1)))])]
"")
;; This effectively combines the two peepholes above,
;; matching the sequence produced by `ffs2'.
(define_peephole2
[(parallel
[(set (match_operand:SI 0 "register_operand")
(any_extend:SI (match_operand:VAXintQH 1 "general_operand")))
(clobber (reg:CC VAX_PSL_REGNUM))])
(parallel
[(set (match_operand:SI 2 "nonimmediate_operand")
(ctz:SI (match_dup 0)))
(clobber (reg:CC VAX_PSL_REGNUM))])
(set (reg:CCZ VAX_PSL_REGNUM)
(compare:CCZ (match_dup 0)
(const_int 0)))]
"!rtx_equal_p (operands[0], operands[2])
&& peep2_reg_dead_p (3, operands[0])"
[(parallel
[(set (reg:CCZ VAX_PSL_REGNUM)
(compare:CCZ (match_dup 1)
(const_int 0)))
(set (match_dup 2)
(ctz:SI (match_dup 1)))])]
"")
(define_expand "sync_lock_test_and_set"
[(match_operand:VAXint 0 "nonimmediate_operand" "=&g")
(match_operand:VAXint 1 "memory_operand" "+m")
(match_operand:VAXint 2 "const_int_operand" "n")]
""
"
{
rtx label;
if (operands[2] != const1_rtx)
FAIL;
label = gen_label_rtx ();
emit_move_insn (operands[0], const1_rtx);
emit_jump_insn (gen_jbbssi (operands[1], const0_rtx, label));
emit_move_insn (operands[0], const0_rtx);
emit_label (label);
DONE;
}")
(define_expand "sync_lock_release"
[(match_operand:VAXint 0 "memory_operand" "+m")
(match_operand:VAXint 1 "const_int_operand" "n")]
""
"
{
rtx label;
if (operands[1] != const0_rtx)
FAIL;
label = gen_label_rtx ();
emit_jump_insn (gen_jbbcci (operands[0], const0_rtx, label));
emit_label (label);
DONE;
}")
(define_insn "jbbi"
[(unspec_volatile
[(set (pc)
(if_then_else
(eq (zero_extract:SI
(match_operand:VAXint 0 "any_memory_operand" "+")
(const_int 1)
(match_operand:SI 1 "general_operand" "nrmT"))
(const_int bit))
(label_ref (match_operand 2 "" ""))
(pc)))
(set (zero_extract:SI (match_dup 0)
(const_int 1)
(match_dup 1))
(const_int bit))]
VUNSPEC_LOCK)]
""
"jbi %1,%0,%l2")