1;; GCC machine description for i386 synchronization instructions. 2;; Copyright (C) 2005, 2006 3;; Free Software Foundation, Inc. 4;; 5;; This file is part of GCC. 6;; 7;; GCC is free software; you can redistribute it and/or modify 8;; it under the terms of the GNU General Public License as published by 9;; the Free Software Foundation; either version 2, or (at your option) 10;; any later version. 11;; 12;; GCC is distributed in the hope that it will be useful, 13;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15;; GNU General Public License for more details. 16;; 17;; You should have received a copy of the GNU General Public License 18;; along with GCC; see the file COPYING. If not, write to 19;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, 20;; Boston, MA 02110-1301, USA. 21 22(define_mode_macro IMODE [QI HI SI (DI "TARGET_64BIT")]) 23(define_mode_attr modesuffix [(QI "b") (HI "w") (SI "l") (DI "q")]) 24(define_mode_attr modeconstraint [(QI "q") (HI "r") (SI "r") (DI "r")]) 25(define_mode_attr immconstraint [(QI "i") (HI "i") (SI "i") (DI "e")]) 26 27(define_mode_macro CASMODE [QI HI SI (DI "TARGET_64BIT || TARGET_CMPXCHG8B") 28 (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) 29(define_mode_macro DCASMODE 30 [(DI "!TARGET_64BIT && TARGET_CMPXCHG8B && !flag_pic") 31 (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) 32(define_mode_attr doublemodesuffix [(DI "8") (TI "16")]) 33(define_mode_attr DCASHMODE [(DI "SI") (TI "DI")]) 34 35;; ??? It would be possible to use cmpxchg8b on pentium for DImode 36;; changes. It's complicated because the insn uses ecx:ebx as the 37;; new value; note that the registers are reversed from the order 38;; that they'd be in with (reg:DI 2 ecx). Similarly for TImode 39;; data in 64-bit mode. 40 41(define_expand "sync_compare_and_swap<mode>" 42 [(parallel 43 [(set (match_operand:CASMODE 0 "register_operand" "") 44 (match_operand:CASMODE 1 "memory_operand" "")) 45 (set (match_dup 1) 46 (unspec_volatile:CASMODE 47 [(match_dup 1) 48 (match_operand:CASMODE 2 "register_operand" "") 49 (match_operand:CASMODE 3 "register_operand" "")] 50 UNSPECV_CMPXCHG_1)) 51 (clobber (reg:CC FLAGS_REG))])] 52 "TARGET_CMPXCHG" 53{ 54 if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode) 55 { 56 enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode; 57 rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0); 58 rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 59 GET_MODE_SIZE (hmode)); 60 low = force_reg (hmode, low); 61 high = force_reg (hmode, high); 62 if (<MODE>mode == DImode) 63 emit_insn (gen_sync_double_compare_and_swapdi 64 (operands[0], operands[1], operands[2], low, high)); 65 else if (<MODE>mode == TImode) 66 emit_insn (gen_sync_double_compare_and_swapti 67 (operands[0], operands[1], operands[2], low, high)); 68 else 69 gcc_unreachable (); 70 DONE; 71 } 72}) 73 74(define_insn "*sync_compare_and_swap<mode>" 75 [(set (match_operand:IMODE 0 "register_operand" "=a") 76 (match_operand:IMODE 1 "memory_operand" "+m")) 77 (set (match_dup 1) 78 (unspec_volatile:IMODE 79 [(match_dup 1) 80 (match_operand:IMODE 2 "register_operand" "a") 81 (match_operand:IMODE 3 "register_operand" "<modeconstraint>")] 82 UNSPECV_CMPXCHG_1)) 83 (clobber (reg:CC FLAGS_REG))] 84 "TARGET_CMPXCHG" 85 "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}") 86 87(define_insn "sync_double_compare_and_swap<mode>" 88 [(set (match_operand:DCASMODE 0 "register_operand" "=A") 89 (match_operand:DCASMODE 1 "memory_operand" "+m")) 90 (set (match_dup 1) 91 (unspec_volatile:DCASMODE 92 [(match_dup 1) 93 (match_operand:DCASMODE 2 "register_operand" "A") 94 (match_operand:<DCASHMODE> 3 "register_operand" "b") 95 (match_operand:<DCASHMODE> 4 "register_operand" "c")] 96 UNSPECV_CMPXCHG_1)) 97 (clobber (reg:CC FLAGS_REG))] 98 "" 99 "lock\;cmpxchg<doublemodesuffix>b\t%1") 100 101;; Theoretically we'd like to use constraint "r" (any reg) for operand 102;; 3, but that includes ecx. If operand 3 and 4 are the same (like when 103;; the input is -1LL) GCC might chose to allocate operand 3 to ecx, like 104;; operand 4. This breaks, as the xchg will move the PIC register contents 105;; to %ecx then --> boom. Operands 3 and 4 really need to be different 106;; registers, which in this case means operand 3 must not be ecx. 107;; Instead of playing tricks with fake early clobbers or the like we 108;; just enumerate all regs possible here, which (as this is !TARGET_64BIT) 109;; are just esi and edi. 110(define_insn "*sync_double_compare_and_swapdi_pic" 111 [(set (match_operand:DI 0 "register_operand" "=A") 112 (match_operand:DI 1 "memory_operand" "+W")) 113 (set (match_dup 1) 114 (unspec_volatile:DI 115 [(match_dup 1) 116 (match_operand:DI 2 "register_operand" "A") 117 (match_operand:SI 3 "register_operand" "SD") 118 (match_operand:SI 4 "register_operand" "c")] 119 UNSPECV_CMPXCHG_1)) 120 (clobber (reg:CC FLAGS_REG))] 121 "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic" 122 "xchg{l}\t%%ebx, %3\;lock\;cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3") 123 124(define_expand "sync_compare_and_swap_cc<mode>" 125 [(parallel 126 [(set (match_operand:CASMODE 0 "register_operand" "") 127 (match_operand:CASMODE 1 "memory_operand" "")) 128 (set (match_dup 1) 129 (unspec_volatile:CASMODE 130 [(match_dup 1) 131 (match_operand:CASMODE 2 "register_operand" "") 132 (match_operand:CASMODE 3 "register_operand" "")] 133 UNSPECV_CMPXCHG_1)) 134 (set (match_dup 4) 135 (compare:CCZ 136 (unspec_volatile:CASMODE 137 [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2) 138 (match_dup 2)))])] 139 "TARGET_CMPXCHG" 140{ 141 operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG); 142 ix86_compare_op0 = operands[3]; 143 ix86_compare_op1 = NULL; 144 ix86_compare_emitted = operands[4]; 145 if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode) 146 { 147 enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode; 148 rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0); 149 rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 150 GET_MODE_SIZE (hmode)); 151 low = force_reg (hmode, low); 152 high = force_reg (hmode, high); 153 if (<MODE>mode == DImode) 154 emit_insn (gen_sync_double_compare_and_swap_ccdi 155 (operands[0], operands[1], operands[2], low, high)); 156 else if (<MODE>mode == TImode) 157 emit_insn (gen_sync_double_compare_and_swap_ccti 158 (operands[0], operands[1], operands[2], low, high)); 159 else 160 gcc_unreachable (); 161 DONE; 162 } 163}) 164 165(define_insn "*sync_compare_and_swap_cc<mode>" 166 [(set (match_operand:IMODE 0 "register_operand" "=a") 167 (match_operand:IMODE 1 "memory_operand" "+m")) 168 (set (match_dup 1) 169 (unspec_volatile:IMODE 170 [(match_dup 1) 171 (match_operand:IMODE 2 "register_operand" "a") 172 (match_operand:IMODE 3 "register_operand" "<modeconstraint>")] 173 UNSPECV_CMPXCHG_1)) 174 (set (reg:CCZ FLAGS_REG) 175 (compare:CCZ 176 (unspec_volatile:IMODE 177 [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2) 178 (match_dup 2)))] 179 "TARGET_CMPXCHG" 180 "lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}") 181 182(define_insn "sync_double_compare_and_swap_cc<mode>" 183 [(set (match_operand:DCASMODE 0 "register_operand" "=A") 184 (match_operand:DCASMODE 1 "memory_operand" "+m")) 185 (set (match_dup 1) 186 (unspec_volatile:DCASMODE 187 [(match_dup 1) 188 (match_operand:DCASMODE 2 "register_operand" "A") 189 (match_operand:<DCASHMODE> 3 "register_operand" "b") 190 (match_operand:<DCASHMODE> 4 "register_operand" "c")] 191 UNSPECV_CMPXCHG_1)) 192 (set (reg:CCZ FLAGS_REG) 193 (compare:CCZ 194 (unspec_volatile:DCASMODE 195 [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] 196 UNSPECV_CMPXCHG_2) 197 (match_dup 2)))] 198 "" 199 "lock\;cmpxchg<doublemodesuffix>b\t%1") 200 201;; See above for the explanation of using the constraint "SD" for 202;; operand 3. 203(define_insn "*sync_double_compare_and_swap_ccdi_pic" 204 [(set (match_operand:DI 0 "register_operand" "=A") 205 (match_operand:DI 1 "memory_operand" "+W")) 206 (set (match_dup 1) 207 (unspec_volatile:DI 208 [(match_dup 1) 209 (match_operand:DI 2 "register_operand" "A") 210 (match_operand:SI 3 "register_operand" "SD") 211 (match_operand:SI 4 "register_operand" "c")] 212 UNSPECV_CMPXCHG_1)) 213 (set (reg:CCZ FLAGS_REG) 214 (compare:CCZ 215 (unspec_volatile:DI 216 [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] 217 UNSPECV_CMPXCHG_2) 218 (match_dup 2)))] 219 "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic" 220 "xchg{l}\t%%ebx, %3\;lock\;cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3") 221 222(define_insn "sync_old_add<mode>" 223 [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>") 224 (unspec_volatile:IMODE 225 [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG)) 226 (set (match_dup 1) 227 (plus:IMODE (match_dup 1) 228 (match_operand:IMODE 2 "register_operand" "0"))) 229 (clobber (reg:CC FLAGS_REG))] 230 "TARGET_XADD" 231 "lock\;xadd{<modesuffix>}\t{%0, %1|%1, %0}") 232 233;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space. 234(define_insn "sync_lock_test_and_set<mode>" 235 [(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>") 236 (unspec_volatile:IMODE 237 [(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG)) 238 (set (match_dup 1) 239 (match_operand:IMODE 2 "register_operand" "0"))] 240 "" 241 "xchg{<modesuffix>}\t{%1, %0|%0, %1}") 242 243(define_insn "sync_add<mode>" 244 [(set (match_operand:IMODE 0 "memory_operand" "+m") 245 (unspec_volatile:IMODE 246 [(plus:IMODE (match_dup 0) 247 (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 248 UNSPECV_LOCK)) 249 (clobber (reg:CC FLAGS_REG))] 250 "" 251 "lock\;add{<modesuffix>}\t{%1, %0|%0, %1}") 252 253(define_insn "sync_sub<mode>" 254 [(set (match_operand:IMODE 0 "memory_operand" "+m") 255 (unspec_volatile:IMODE 256 [(minus:IMODE (match_dup 0) 257 (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 258 UNSPECV_LOCK)) 259 (clobber (reg:CC FLAGS_REG))] 260 "" 261 "lock\;sub{<modesuffix>}\t{%1, %0|%0, %1}") 262 263(define_insn "sync_ior<mode>" 264 [(set (match_operand:IMODE 0 "memory_operand" "+m") 265 (unspec_volatile:IMODE 266 [(ior:IMODE (match_dup 0) 267 (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 268 UNSPECV_LOCK)) 269 (clobber (reg:CC FLAGS_REG))] 270 "" 271 "lock\;or{<modesuffix>}\t{%1, %0|%0, %1}") 272 273(define_insn "sync_and<mode>" 274 [(set (match_operand:IMODE 0 "memory_operand" "+m") 275 (unspec_volatile:IMODE 276 [(and:IMODE (match_dup 0) 277 (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 278 UNSPECV_LOCK)) 279 (clobber (reg:CC FLAGS_REG))] 280 "" 281 "lock\;and{<modesuffix>}\t{%1, %0|%0, %1}") 282 283(define_insn "sync_xor<mode>" 284 [(set (match_operand:IMODE 0 "memory_operand" "+m") 285 (unspec_volatile:IMODE 286 [(xor:IMODE (match_dup 0) 287 (match_operand:IMODE 1 "nonmemory_operand" "<modeconstraint><immconstraint>"))] 288 UNSPECV_LOCK)) 289 (clobber (reg:CC FLAGS_REG))] 290 "" 291 "lock\;xor{<modesuffix>}\t{%1, %0|%0, %1}") 292