sync.md revision 169689
1169689Skan;; GCC machine description for i386 synchronization instructions. 2169689Skan;; Copyright (C) 2005, 2006 3169689Skan;; Free Software Foundation, Inc. 4169689Skan;; 5169689Skan;; This file is part of GCC. 6169689Skan;; 7169689Skan;; GCC is free software; you can redistribute it and/or modify 8169689Skan;; it under the terms of the GNU General Public License as published by 9169689Skan;; the Free Software Foundation; either version 2, or (at your option) 10169689Skan;; any later version. 11169689Skan;; 12169689Skan;; GCC is distributed in the hope that it will be useful, 13169689Skan;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14169689Skan;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15169689Skan;; GNU General Public License for more details. 16169689Skan;; 17169689Skan;; You should have received a copy of the GNU General Public License 18169689Skan;; along with GCC; see the file COPYING. If not, write to 19169689Skan;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, 20169689Skan;; Boston, MA 02110-1301, USA. 21169689Skan 22169689Skan(define_mode_macro IMODE [QI HI SI (DI "TARGET_64BIT")]) 23169689Skan(define_mode_attr modesuffix [(QI "b") (HI "w") (SI "l") (DI "q")]) 24169689Skan(define_mode_attr modeconstraint [(QI "q") (HI "r") (SI "r") (DI "r")]) 25169689Skan(define_mode_attr immconstraint [(QI "i") (HI "i") (SI "i") (DI "e")]) 26169689Skan 27169689Skan(define_mode_macro CASMODE [QI HI SI (DI "TARGET_64BIT || TARGET_CMPXCHG8B") 28169689Skan (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) 29169689Skan(define_mode_macro DCASMODE 30169689Skan [(DI "!TARGET_64BIT && TARGET_CMPXCHG8B && !flag_pic") 31169689Skan (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) 32169689Skan(define_mode_attr doublemodesuffix [(DI "8") (TI "16")]) 33169689Skan(define_mode_attr DCASHMODE [(DI "SI") (TI "DI")]) 34169689Skan 35169689Skan;; ??? It would be possible to use cmpxchg8b on pentium for DImode 36169689Skan;; changes. It's complicated because the insn uses ecx:ebx as the 37169689Skan;; new value; note that the registers are reversed from the order 38169689Skan;; that they'd be in with (reg:DI 2 ecx). Similarly for TImode 39169689Skan;; data in 64-bit mode. 40169689Skan 41169689Skan(define_expand "sync_compare_and_swap<mode>" 42169689Skan [(parallel 43169689Skan [(set (match_operand:CASMODE 0 "register_operand" "") 44169689Skan (match_operand:CASMODE 1 "memory_operand" "")) 45169689Skan (set (match_dup 1) 46169689Skan (unspec_volatile:CASMODE 47169689Skan [(match_dup 1) 48169689Skan (match_operand:CASMODE 2 "register_operand" "") 49169689Skan (match_operand:CASMODE 3 "register_operand" "")] 50169689Skan UNSPECV_CMPXCHG_1)) 51169689Skan (clobber (reg:CC FLAGS_REG))])] 52169689Skan "TARGET_CMPXCHG" 53169689Skan{ 54169689Skan if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode) 55169689Skan { 56169689Skan enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode; 57169689Skan rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0); 58169689Skan rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 59169689Skan GET_MODE_SIZE (hmode)); 60169689Skan low = force_reg (hmode, low); 61169689Skan high = force_reg (hmode, high); 62169689Skan if (<MODE>mode == DImode) 63169689Skan emit_insn (gen_sync_double_compare_and_swapdi 64169689Skan (operands[0], operands[1], operands[2], low, high)); 65169689Skan else if (<MODE>mode == TImode) 66169689Skan emit_insn (gen_sync_double_compare_and_swapti 67169689Skan (operands[0], operands[1], operands[2], low, high)); 68169689Skan else 69169689Skan gcc_unreachable (); 70169689Skan DONE; 71169689Skan } 72169689Skan}) 73169689Skan 74169689Skan(define_insn "*sync_compare_and_swap<mode>" 75169689Skan [(set (match_operand:IMODE 0 "register_operand" "=a") 76169689Skan (match_operand:IMODE 1 "memory_operand" "+m")) 77169689Skan (set (match_dup 1) 78169689Skan (unspec_volatile:IMODE 79169689Skan [(match_dup 1) 80169689Skan (match_operand:IMODE 2 "register_operand" "a") 81169689Skan (match_operand:IMODE 3 "register_operand" "<modeconstraint>")] 82169689Skan UNSPECV_CMPXCHG_1)) 83169689Skan (clobber (reg:CC FLAGS_REG))] 84169689Skan "TARGET_CMPXCHG" 85169689Skan "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}") 86169689Skan 87169689Skan(define_insn "sync_double_compare_and_swap<mode>" 88169689Skan [(set (match_operand:DCASMODE 0 "register_operand" "=A") 89169689Skan (match_operand:DCASMODE 1 "memory_operand" "+m")) 90169689Skan (set (match_dup 1) 91169689Skan (unspec_volatile:DCASMODE 92169689Skan [(match_dup 1) 93169689Skan (match_operand:DCASMODE 2 "register_operand" "A") 94169689Skan (match_operand:<DCASHMODE> 3 "register_operand" "b") 95169689Skan (match_operand:<DCASHMODE> 4 "register_operand" "c")] 96169689Skan UNSPECV_CMPXCHG_1)) 97169689Skan (clobber (reg:CC FLAGS_REG))] 98169689Skan "" 99169689Skan "lock\;cmpxchg<doublemodesuffix>b\t%1") 100169689Skan 101169689Skan;; Theoretically we'd like to use constraint "r" (any reg) for operand 102169689Skan;; 3, but that includes ecx. If operand 3 and 4 are the same (like when 103169689Skan;; the input is -1LL) GCC might chose to allocate operand 3 to ecx, like 104169689Skan;; operand 4. This breaks, as the xchg will move the PIC register contents 105169689Skan;; to %ecx then --> boom. Operands 3 and 4 really need to be different 106169689Skan;; registers, which in this case means operand 3 must not be ecx. 107169689Skan;; Instead of playing tricks with fake early clobbers or the like we 108169689Skan;; just enumerate all regs possible here, which (as this is !TARGET_64BIT) 109169689Skan;; are just esi and edi. 110169689Skan(define_insn "*sync_double_compare_and_swapdi_pic" 111169689Skan [(set (match_operand:DI 0 "register_operand" "=A") 112169689Skan (match_operand:DI 1 "memory_operand" "+m")) 113169689Skan (set (match_dup 1) 114169689Skan (unspec_volatile:DI 115169689Skan [(match_dup 1) 116169689Skan (match_operand:DI 2 "register_operand" "A") 117169689Skan (match_operand:SI 3 "register_operand" "SD") 118169689Skan (match_operand:SI 4 "register_operand" "c")] 119169689Skan UNSPECV_CMPXCHG_1)) 120169689Skan (clobber (reg:CC FLAGS_REG))] 121169689Skan "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic" 122169689Skan "xchg{l}\t%%ebx, %3\;lock\;cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3") 123169689Skan 124169689Skan(define_expand "sync_compare_and_swap_cc<mode>" 125169689Skan [(parallel 126169689Skan [(set (match_operand:CASMODE 0 "register_operand" "") 127169689Skan (match_operand:CASMODE 1 "memory_operand" "")) 128169689Skan (set (match_dup 1) 129169689Skan (unspec_volatile:CASMODE 130169689Skan [(match_dup 1) 131169689Skan (match_operand:CASMODE 2 "register_operand" "") 132169689Skan (match_operand:CASMODE 3 "register_operand" "")] 133169689Skan UNSPECV_CMPXCHG_1)) 134169689Skan (set (match_dup 4) 135169689Skan (compare:CCZ 136169689Skan (unspec_volatile:CASMODE 137169689Skan [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2) 138169689Skan (match_dup 2)))])] 139169689Skan "TARGET_CMPXCHG" 140169689Skan{ 141169689Skan operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG); 142169689Skan ix86_compare_op0 = operands[3]; 143169689Skan ix86_compare_op1 = NULL; 144169689Skan ix86_compare_emitted = operands[4]; 145169689Skan if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode) 146169689Skan { 147169689Skan enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode; 148169689Skan rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0); 149169689Skan rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 150169689Skan GET_MODE_SIZE (hmode)); 151169689Skan low = force_reg (hmode, low); 152169689Skan high = force_reg (hmode, high); 153169689Skan if (<MODE>mode == DImode) 154169689Skan emit_insn (gen_sync_double_compare_and_swap_ccdi 155169689Skan (operands[0], operands[1], operands[2], low, high)); 156169689Skan else if (<MODE>mode == TImode) 157169689Skan emit_insn (gen_sync_double_compare_and_swap_ccti 158169689Skan (operands[0], operands[1], operands[2], low, high)); 159169689Skan else 160169689Skan gcc_unreachable (); 161169689Skan DONE; 162169689Skan } 163169689Skan}) 164169689Skan 165169689Skan(define_insn "*sync_compare_and_swap_cc<mode>" 166169689Skan [(set (match_operand:IMODE 0 "register_operand" "=a") 167169689Skan (match_operand:IMODE 1 "memory_operand" "+m")) 168169689Skan (set (match_dup 1) 169169689Skan (unspec_volatile:IMODE 170169689Skan [(match_dup 1) 171169689Skan (match_operand:IMODE 2 "register_operand" "a") 172169689Skan (match_operand:IMODE 3 "register_operand" "<modeconstraint>")] 173169689Skan UNSPECV_CMPXCHG_1)) 174169689Skan (set (reg:CCZ FLAGS_REG) 175169689Skan (compare:CCZ 176169689Skan (unspec_volatile:IMODE 177169689Skan [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2) 178169689Skan (match_dup 2)))] 179169689Skan "TARGET_CMPXCHG" 180169689Skan "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}") 181169689Skan 182169689Skan(define_insn "sync_double_compare_and_swap_cc<mode>" 183169689Skan [(set (match_operand:DCASMODE 0 "register_operand" "=A") 184169689Skan (match_operand:DCASMODE 1 "memory_operand" "+m")) 185169689Skan (set (match_dup 1) 186169689Skan (unspec_volatile:DCASMODE 187169689Skan [(match_dup 1) 188169689Skan (match_operand:DCASMODE 2 "register_operand" "A") 189169689Skan (match_operand:<DCASHMODE> 3 "register_operand" "b") 190169689Skan (match_operand:<DCASHMODE> 4 "register_operand" "c")] 191169689Skan UNSPECV_CMPXCHG_1)) 192169689Skan (set (reg:CCZ FLAGS_REG) 193169689Skan (compare:CCZ 194169689Skan (unspec_volatile:DCASMODE 195169689Skan [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] 196169689Skan UNSPECV_CMPXCHG_2) 197169689Skan (match_dup 2)))] 198169689Skan "" 199169689Skan "lock\;cmpxchg<doublemodesuffix>b\t%1") 200169689Skan 201169689Skan;; See above for the explanation of using the constraint "SD" for 202169689Skan;; operand 3. 203169689Skan(define_insn "*sync_double_compare_and_swap_ccdi_pic" 204169689Skan [(set (match_operand:DI 0 "register_operand" "=A") 205169689Skan (match_operand:DI 1 "memory_operand" "+m")) 206169689Skan (set (match_dup 1) 207169689Skan (unspec_volatile:DI 208169689Skan [(match_dup 1) 209169689Skan (match_operand:DI 2 "register_operand" "A") 210169689Skan (match_operand:SI 3 "register_operand" "SD") 211169689Skan (match_operand:SI 4 "register_operand" "c")] 212169689Skan UNSPECV_CMPXCHG_1)) 213169689Skan (set (reg:CCZ FLAGS_REG) 214169689Skan (compare:CCZ 215169689Skan (unspec_volatile:DI 216169689Skan [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] 217169689Skan UNSPECV_CMPXCHG_2) 218169689Skan (match_dup 2)))] 219169689Skan "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic" 220169689Skan "xchg{l}\t%%ebx, %3\;lock\;cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3") 221169689Skan 222169689Skan(define_insn "sync_old_add<mode>" 223169689Skan [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>") 224169689Skan (unspec_volatile:IMODE 225169689Skan [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG)) 226169689Skan (set (match_dup 1) 227169689Skan (plus:IMODE (match_dup 1) 228169689Skan (match_operand:IMODE 2 "register_operand" "0"))) 229169689Skan (clobber (reg:CC FLAGS_REG))] 230169689Skan "TARGET_XADD" 231169689Skan "lock\;xadd{<modesuffix>}\t{%0, %1|%1, %0}") 232169689Skan 233169689Skan;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space. 234169689Skan(define_insn "sync_lock_test_and_set<mode>" 235169689Skan [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>") 236169689Skan (unspec_volatile:IMODE 237169689Skan [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG)) 238169689Skan (set (match_dup 1) 239169689Skan (match_operand:IMODE 2 "register_operand" "0"))] 240169689Skan "" 241169689Skan "xchg{<modesuffix>}\t{%1, %0|%0, %1}") 242169689Skan 243169689Skan(define_insn "sync_add<mode>" 244169689Skan [(set (match_operand:IMODE 0 "memory_operand" "+m") 245169689Skan (unspec_volatile:IMODE 246169689Skan [(plus:IMODE (match_dup 0) 247169689Skan (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 248169689Skan UNSPECV_LOCK)) 249169689Skan (clobber (reg:CC FLAGS_REG))] 250169689Skan "" 251169689Skan "lock\;add{<modesuffix>}\t{%1, %0|%0, %1}") 252169689Skan 253169689Skan(define_insn "sync_sub<mode>" 254169689Skan [(set (match_operand:IMODE 0 "memory_operand" "+m") 255169689Skan (unspec_volatile:IMODE 256169689Skan [(minus:IMODE (match_dup 0) 257169689Skan (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 258169689Skan UNSPECV_LOCK)) 259169689Skan (clobber (reg:CC FLAGS_REG))] 260169689Skan "" 261169689Skan "lock\;sub{<modesuffix>}\t{%1, %0|%0, %1}") 262169689Skan 263169689Skan(define_insn "sync_ior<mode>" 264169689Skan [(set (match_operand:IMODE 0 "memory_operand" "+m") 265169689Skan (unspec_volatile:IMODE 266169689Skan [(ior:IMODE (match_dup 0) 267169689Skan (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 268169689Skan UNSPECV_LOCK)) 269169689Skan (clobber (reg:CC FLAGS_REG))] 270169689Skan "" 271169689Skan "lock\;or{<modesuffix>}\t{%1, %0|%0, %1}") 272169689Skan 273169689Skan(define_insn "sync_and<mode>" 274169689Skan [(set (match_operand:IMODE 0 "memory_operand" "+m") 275169689Skan (unspec_volatile:IMODE 276169689Skan [(and:IMODE (match_dup 0) 277169689Skan (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 278169689Skan UNSPECV_LOCK)) 279169689Skan (clobber (reg:CC FLAGS_REG))] 280169689Skan "" 281169689Skan "lock\;and{<modesuffix>}\t{%1, %0|%0, %1}") 282169689Skan 283169689Skan(define_insn "sync_xor<mode>" 284169689Skan [(set (match_operand:IMODE 0 "memory_operand" "+m") 285169689Skan (unspec_volatile:IMODE 286169689Skan [(xor:IMODE (match_dup 0) 287169689Skan (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 288169689Skan UNSPECV_LOCK)) 289169689Skan (clobber (reg:CC FLAGS_REG))] 290169689Skan "" 291169689Skan "lock\;xor{<modesuffix>}\t{%1, %0|%0, %1}") 292