;; Machine Description for MIPS based processor synchronization ;; instructions. ;; Copyright (C) 2007, 2008, 2009 ;; 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 ;; . ;; Atomic fetch bitwise operations. (define_code_iterator fetchop_bit [ior xor and]) ;; Atomic HI and QI operations (define_code_iterator atomic_hiqi_op [plus minus ior xor and]) ;; Atomic memory operations. (define_expand "memory_barrier" [(set (match_dup 0) (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))] "GENERATE_SYNC" { operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); MEM_VOLATILE_P (operands[0]) = 1; }) (define_insn "*memory_barrier" [(set (match_operand:BLK 0 "" "") (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))] "GENERATE_SYNC" "%|sync%-") (define_insn "sync_compare_and_swap" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ") (match_operand:GPR 3 "arith_operand" "I,d")] UNSPEC_COMPARE_AND_SWAP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_COMPARE_AND_SWAP ("", "li")); else return mips_output_sync_loop (MIPS_COMPARE_AND_SWAP ("", "move")); } [(set_attr "length" "32")]) (define_expand "sync_compare_and_swap" [(match_operand:SHORT 0 "register_operand") (match_operand:SHORT 1 "memory_operand") (match_operand:SHORT 2 "general_operand") (match_operand:SHORT 3 "general_operand")] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_6 = gen_compare_and_swap_12; mips_expand_atomic_qihi (generator, operands[0], operands[1], operands[2], operands[3]); DONE; }) ;; Helper insn for mips_expand_atomic_qihi. (define_insn "compare_and_swap_12" [(set (match_operand:SI 0 "register_operand" "=&d,&d") (match_operand:SI 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d") (match_operand:SI 3 "register_operand" "d,d") (match_operand:SI 4 "reg_or_0_operand" "dJ,dJ") (match_operand:SI 5 "reg_or_0_operand" "d,J")] UNSPEC_COMPARE_AND_SWAP_12))] "GENERATE_LL_SC" { if (which_alternative == 0) return (mips_output_sync_loop (MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_NONZERO_OP))); else return (mips_output_sync_loop (MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_ZERO_OP))); } [(set_attr "length" "40,36")]) (define_insn "sync_add" [(set (match_operand:GPR 0 "memory_operand" "+R,R") (unspec_volatile:GPR [(plus:GPR (match_dup 0) (match_operand:GPR 1 "arith_operand" "I,d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_OP ("", "addiu")); else return mips_output_sync_loop (MIPS_SYNC_OP ("", "addu")); } [(set_attr "length" "28")]) (define_expand "sync_" [(set (match_operand:SHORT 0 "memory_operand") (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT (match_dup 0) (match_operand:SHORT 1 "general_operand"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_4 = gen_sync__12; mips_expand_atomic_qihi (generator, NULL, operands[0], operands[1], NULL); DONE; }) ;; Helper insn for sync_ (define_insn "sync__12" [(set (match_operand:SI 0 "memory_operand" "+R") (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d") (atomic_hiqi_op:SI (match_dup 0) (match_operand:SI 3 "register_operand" "dJ"))] UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 4 "=&d"))] "GENERATE_LL_SC" { return (mips_output_sync_loop (MIPS_SYNC_OP_12 ("", MIPS_SYNC_OP_12_AND))); } [(set_attr "length" "40")]) (define_expand "sync_old_" [(parallel [ (set (match_operand:SHORT 0 "register_operand") (match_operand:SHORT 1 "memory_operand")) (set (match_dup 1) (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT (match_dup 1) (match_operand:SHORT 2 "general_operand"))] UNSPEC_SYNC_OLD_OP))])] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_5 = gen_sync_old__12; mips_expand_atomic_qihi (generator, operands[0], operands[1], operands[2], NULL); DONE; }) ;; Helper insn for sync_old_ (define_insn "sync_old__12" [(set (match_operand:SI 0 "register_operand" "=&d") (match_operand:SI 1 "memory_operand" "+R")) (set (match_dup 1) (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d") (match_operand:SI 3 "register_operand" "d") (atomic_hiqi_op:SI (match_dup 0) (match_operand:SI 4 "register_operand" "dJ"))] UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 5 "=&d"))] "GENERATE_LL_SC" { return (mips_output_sync_loop (MIPS_SYNC_OLD_OP_12 ("", MIPS_SYNC_OLD_OP_12_AND))); } [(set_attr "length" "40")]) (define_expand "sync_new_" [(parallel [ (set (match_operand:SHORT 0 "register_operand") (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT (match_operand:SHORT 1 "memory_operand") (match_operand:SHORT 2 "general_operand"))] UNSPEC_SYNC_NEW_OP)) (set (match_dup 1) (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)] UNSPEC_SYNC_NEW_OP))])] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_5 = gen_sync_new__12; mips_expand_atomic_qihi (generator, operands[0], operands[1], operands[2], NULL); DONE; }) ;; Helper insn for sync_new_ (define_insn "sync_new__12" [(set (match_operand:SI 0 "register_operand" "=&d") (unspec_volatile:SI [(match_operand:SI 1 "memory_operand" "+R") (match_operand:SI 2 "register_operand" "d") (match_operand:SI 3 "register_operand" "d") (atomic_hiqi_op:SI (match_dup 0) (match_operand:SI 4 "register_operand" "dJ"))] UNSPEC_SYNC_NEW_OP_12)) (set (match_dup 1) (unspec_volatile:SI [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] "GENERATE_LL_SC" { return (mips_output_sync_loop (MIPS_SYNC_NEW_OP_12 ("", MIPS_SYNC_NEW_OP_12_AND))); } [(set_attr "length" "40")]) (define_expand "sync_nand" [(set (match_operand:SHORT 0 "memory_operand") (unspec_volatile:SHORT [(match_dup 0) (match_operand:SHORT 1 "general_operand")] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_4 = gen_sync_nand_12; mips_expand_atomic_qihi (generator, NULL, operands[0], operands[1], NULL); DONE; }) ;; Helper insn for sync_nand (define_insn "sync_nand_12" [(set (match_operand:SI 0 "memory_operand" "+R") (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d") (match_dup 0) (match_operand:SI 3 "register_operand" "dJ")] UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 4 "=&d"))] "GENERATE_LL_SC" { return (mips_output_sync_loop (MIPS_SYNC_OP_12 ("and", MIPS_SYNC_OP_12_XOR))); } [(set_attr "length" "40")]) (define_expand "sync_old_nand" [(parallel [ (set (match_operand:SHORT 0 "register_operand") (match_operand:SHORT 1 "memory_operand")) (set (match_dup 1) (unspec_volatile:SHORT [(match_dup 1) (match_operand:SHORT 2 "general_operand")] UNSPEC_SYNC_OLD_OP))])] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_5 = gen_sync_old_nand_12; mips_expand_atomic_qihi (generator, operands[0], operands[1], operands[2], NULL); DONE; }) ;; Helper insn for sync_old_nand (define_insn "sync_old_nand_12" [(set (match_operand:SI 0 "register_operand" "=&d") (match_operand:SI 1 "memory_operand" "+R")) (set (match_dup 1) (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d") (match_operand:SI 3 "register_operand" "d") (match_operand:SI 4 "register_operand" "dJ")] UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 5 "=&d"))] "GENERATE_LL_SC" { return (mips_output_sync_loop (MIPS_SYNC_OLD_OP_12 ("and", MIPS_SYNC_OLD_OP_12_XOR))); } [(set_attr "length" "40")]) (define_expand "sync_new_nand" [(parallel [ (set (match_operand:SHORT 0 "register_operand") (unspec_volatile:SHORT [(match_operand:SHORT 1 "memory_operand") (match_operand:SHORT 2 "general_operand")] UNSPEC_SYNC_NEW_OP)) (set (match_dup 1) (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)] UNSPEC_SYNC_NEW_OP))])] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_5 = gen_sync_new_nand_12; mips_expand_atomic_qihi (generator, operands[0], operands[1], operands[2], NULL); DONE; }) ;; Helper insn for sync_new_nand (define_insn "sync_new_nand_12" [(set (match_operand:SI 0 "register_operand" "=&d") (unspec_volatile:SI [(match_operand:SI 1 "memory_operand" "+R") (match_operand:SI 2 "register_operand" "d") (match_operand:SI 3 "register_operand" "d") (match_operand:SI 4 "register_operand" "dJ")] UNSPEC_SYNC_NEW_OP_12)) (set (match_dup 1) (unspec_volatile:SI [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] "GENERATE_LL_SC" { return (mips_output_sync_loop (MIPS_SYNC_NEW_OP_12 ("and", MIPS_SYNC_NEW_OP_12_XOR))); } [(set_attr "length" "40")]) (define_insn "sync_sub" [(set (match_operand:GPR 0 "memory_operand" "+R") (unspec_volatile:GPR [(minus:GPR (match_dup 0) (match_operand:GPR 1 "register_operand" "d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { return mips_output_sync_loop (MIPS_SYNC_OP ("", "subu")); } [(set_attr "length" "28")]) (define_insn "sync_old_add" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(plus:GPR (match_dup 1) (match_operand:GPR 2 "arith_operand" "I,d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_OLD_OP ("", "addiu")); else return mips_output_sync_loop (MIPS_SYNC_OLD_OP ("", "addu")); } [(set_attr "length" "28")]) (define_insn "sync_old_sub" [(set (match_operand:GPR 0 "register_operand" "=&d") (match_operand:GPR 1 "memory_operand" "+R")) (set (match_dup 1) (unspec_volatile:GPR [(minus:GPR (match_dup 1) (match_operand:GPR 2 "register_operand" "d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { return mips_output_sync_loop (MIPS_SYNC_OLD_OP ("", "subu")); } [(set_attr "length" "28")]) (define_insn "sync_new_add" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R") (match_operand:GPR 2 "arith_operand" "I,d"))) (set (match_dup 1) (unspec_volatile:GPR [(plus:GPR (match_dup 1) (match_dup 2))] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_NEW_OP ("", "addiu")); else return mips_output_sync_loop (MIPS_SYNC_NEW_OP ("", "addu")); } [(set_attr "length" "28")]) (define_insn "sync_new_sub" [(set (match_operand:GPR 0 "register_operand" "=&d") (minus:GPR (match_operand:GPR 1 "memory_operand" "+R") (match_operand:GPR 2 "register_operand" "d"))) (set (match_dup 1) (unspec_volatile:GPR [(minus:GPR (match_dup 1) (match_dup 2))] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" { return mips_output_sync_loop (MIPS_SYNC_NEW_OP ("", "subu")); } [(set_attr "length" "28")]) (define_insn "sync_" [(set (match_operand:GPR 0 "memory_operand" "+R,R") (unspec_volatile:GPR [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d") (match_dup 0))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_OP ("", "")); else return mips_output_sync_loop (MIPS_SYNC_OP ("", "")); } [(set_attr "length" "28")]) (define_insn "sync_old_" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d") (match_dup 1))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return (mips_output_sync_loop (MIPS_SYNC_OLD_OP ("", ""))); else return mips_output_sync_loop (MIPS_SYNC_OLD_OP ("", "")); } [(set_attr "length" "28")]) (define_insn "sync_new_" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d") (match_dup 1))] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return (mips_output_sync_loop (MIPS_SYNC_NEW_OP ("", ""))); else return mips_output_sync_loop (MIPS_SYNC_NEW_OP ("", "")); } [(set_attr "length" "28")]) (define_insn "sync_nand" [(set (match_operand:GPR 0 "memory_operand" "+R,R") (unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_NAND ("", "andi")); else return mips_output_sync_loop (MIPS_SYNC_NAND ("", "and")); } [(set_attr "length" "32")]) (define_insn "sync_old_nand" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_OLD_NAND ("", "andi")); else return mips_output_sync_loop (MIPS_SYNC_OLD_NAND ("", "and")); } [(set_attr "length" "32")]) (define_insn "sync_new_nand" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_NEW_NAND ("", "andi")); else return mips_output_sync_loop (MIPS_SYNC_NEW_NAND ("", "and")); } [(set_attr "length" "32")]) (define_insn "sync_lock_test_and_set" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")] UNSPEC_SYNC_EXCHANGE))] "GENERATE_LL_SC" { if (which_alternative == 0) return mips_output_sync_loop (MIPS_SYNC_EXCHANGE ("", "li")); else return mips_output_sync_loop (MIPS_SYNC_EXCHANGE ("", "move")); } [(set_attr "length" "24")]) (define_expand "sync_lock_test_and_set" [(match_operand:SHORT 0 "register_operand") (match_operand:SHORT 1 "memory_operand") (match_operand:SHORT 2 "general_operand")] "GENERATE_LL_SC" { union mips_gen_fn_ptrs generator; generator.fn_5 = gen_test_and_set_12; mips_expand_atomic_qihi (generator, operands[0], operands[1], operands[2], NULL); DONE; }) (define_insn "test_and_set_12" [(set (match_operand:SI 0 "register_operand" "=&d,&d") (match_operand:SI 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d") (match_operand:SI 3 "register_operand" "d,d") (match_operand:SI 4 "arith_operand" "d,J")] UNSPEC_SYNC_EXCHANGE_12))] "GENERATE_LL_SC" { if (which_alternative == 0) return (mips_output_sync_loop (MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_NONZERO_OP))); else return (mips_output_sync_loop (MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_ZERO_OP))); } [(set_attr "length" "28,24")])