@@ -24562,9 +24562,9 @@ emit_unlikely_jump (rtx insn)
void
arm_expand_compare_and_swap (rtx operands[])
{
- rtx bval, rval, mem, oldval, newval, is_weak, mod_s, mod_f;
+ rtx bval, rval, mem, oldval, newval, is_weak, mod_s, mod_f, x;
enum machine_mode mode;
- rtx (*gen) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx);
+ rtx (*gen) (rtx, rtx, rtx, rtx, rtx, rtx, rtx);
bval = operands[0];
rval = operands[1];
@@ -24612,10 +24612,17 @@ arm_expand_compare_and_swap (rtx operands[])
gcc_unreachable ();
}
- emit_insn (gen (bval, rval, mem, oldval, newval, is_weak, mod_s, mod_f));
+ emit_insn (gen (rval, mem, oldval, newval, is_weak, mod_s, mod_f));
if (mode == QImode || mode == HImode)
emit_move_insn (operands[1], gen_lowpart (mode, rval));
+
+ /* In all cases, we arrange for success to be signaled by Z set.
+ This arrangement allows for the boolean result to be used directly
+ in a subsequent branch, post optimization. */
+ x = gen_rtx_REG (CCmode, CC_REGNUM);
+ x = gen_rtx_EQ (SImode, x, const0_rtx);
+ emit_insn (gen_rtx_SET (VOIDmode, bval, x));
}
/* Split a compare and swap pattern. It is IMPLEMENTATION DEFINED whether
@@ -24627,24 +24634,22 @@ arm_expand_compare_and_swap (rtx operands[])
void
arm_split_compare_and_swap (rtx operands[])
{
- rtx bval, rval, mem, oldval, newval;
+ rtx rval, mem, oldval, newval, scratch;
enum machine_mode mode;
enum memmodel mod_s, mod_f;
bool is_weak;
rtx label1, label2, x, cond;
- bval = operands[0];
- rval = operands[1];
- mem = operands[2];
- oldval = operands[3];
- newval = operands[4];
- is_weak = (operands[5] != const0_rtx);
- mod_s = (enum memmodel) INTVAL (operands[6]);
- mod_f = (enum memmodel) INTVAL (operands[7]);
+ rval = operands[0];
+ mem = operands[1];
+ oldval = operands[2];
+ newval = operands[3];
+ is_weak = (operands[4] != const0_rtx);
+ mod_s = (enum memmodel) INTVAL (operands[5]);
+ mod_f = (enum memmodel) INTVAL (operands[6]);
+ scratch = operands[7];
mode = GET_MODE (mem);
- emit_move_insn (bval, const0_rtx);
-
arm_pre_atomic_barrier (mod_s);
label1 = NULL_RTX;
@@ -24664,20 +24669,17 @@ arm_split_compare_and_swap (rtx operands[])
x = gen_cbranchsi4 (x, rval, oldval, label2);
emit_unlikely_jump (x);
- arm_emit_store_exclusive (mode, bval, mem, newval);
+ arm_emit_store_exclusive (mode, scratch, mem, newval);
- /* Thumb1 does not have LDREX, so we do not need to consider that
- when it comes to computing the below. */
- gcc_assert (TARGET_32BIT);
+ /* Weak or strong, we want EQ to be true for success, so that we
+ match the flags that we got from the compare above. Thus we
+ prefer to use TEQ instead of TST here. */
+ emit_insn (gen_xorsi3_compare0_scratch (scratch, const1_rtx));
- if (is_weak)
- emit_insn (gen_xorsi3 (bval, bval, const1_rtx));
- else
+ if (!is_weak)
{
- emit_insn (gen_xorsi3_compare0 (bval, bval, const1_rtx));
-
- cond = gen_rtx_REG (CC_NOOVmode, CC_REGNUM);
- x = gen_rtx_EQ (VOIDmode, cond, const0_rtx);
+ cond = gen_rtx_REG (CCmode, CC_REGNUM);
+ x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
gen_rtx_LABEL_REF (Pmode, label1), pc_rtx);
emit_unlikely_jump (gen_rtx_SET (VOIDmode, pc_rtx, x));
@@ -3062,7 +3062,7 @@
[(set_attr "length" "2")
(set_attr "conds" "set")])
-(define_insn "xorsi3_compare0"
+(define_insn "*xorsi3_compare0"
[(set (reg:CC_NOOV CC_REGNUM)
(compare:CC_NOOV (xor:SI (match_operand:SI 1 "s_register_operand" "r")
(match_operand:SI 2 "arm_rhs_operand" "rI"))
@@ -3074,7 +3074,7 @@
[(set_attr "conds" "set")]
)
-(define_insn "*xorsi3_compare0_scratch"
+(define_insn "xorsi3_compare0_scratch"
[(set (reg:CC_NOOV CC_REGNUM)
(compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r")
(match_operand:SI 1 "arm_rhs_operand" "rI"))
@@ -85,20 +85,20 @@
})
(define_insn_and_split "atomic_compare_and_swap<mode>_1"
- [(set (match_operand:SI 0 "s_register_operand" "=&r") ;; bool out
- (unspec_volatile:SI [(const_int 0)] VUNSPEC_ATOMIC_CAS))
- (set (match_operand:SI 1 "s_register_operand" "=&r") ;; val out
+ [(set (reg:CC_Z CC_REGNUM) ;; bool out
+ (unspec_volatile:CC_Z [(const_int 0)] VUNSPEC_ATOMIC_CAS))
+ (set (match_operand:SI 0 "s_register_operand" "=&r") ;; val out
(zero_extend:SI
- (match_operand:NARROW 2 "mem_noofs_operand" "+Ua"))) ;; memory
- (set (match_dup 2)
+ (match_operand:NARROW 1 "mem_noofs_operand" "+Ua"))) ;; memory
+ (set (match_dup 1)
(unspec_volatile:NARROW
- [(match_operand:SI 3 "arm_add_operand" "rIL") ;; expected
- (match_operand:NARROW 4 "s_register_operand" "r") ;; desired
- (match_operand:SI 5 "const_int_operand") ;; is_weak
- (match_operand:SI 6 "const_int_operand") ;; mod_s
- (match_operand:SI 7 "const_int_operand")] ;; mod_f
+ [(match_operand:SI 2 "arm_add_operand" "rIL") ;; expected
+ (match_operand:NARROW 3 "s_register_operand" "r") ;; desired
+ (match_operand:SI 4 "const_int_operand") ;; is_weak
+ (match_operand:SI 5 "const_int_operand") ;; mod_s
+ (match_operand:SI 6 "const_int_operand")] ;; mod_f
VUNSPEC_ATOMIC_CAS))
- (clobber (reg:CC CC_REGNUM))]
+ (clobber (match_scratch:SI 7 "=&r"))]
"<sync_predtab>"
"#"
"&& reload_completed"
@@ -114,19 +114,19 @@
[(SI "rIL") (DI "rDi")])
(define_insn_and_split "atomic_compare_and_swap<mode>_1"
- [(set (match_operand:SI 0 "s_register_operand" "=&r") ;; bool out
- (unspec_volatile:SI [(const_int 0)] VUNSPEC_ATOMIC_CAS))
- (set (match_operand:SIDI 1 "s_register_operand" "=&r") ;; val out
- (match_operand:SIDI 2 "mem_noofs_operand" "+Ua")) ;; memory
- (set (match_dup 2)
+ [(set (reg:CC_Z CC_REGNUM) ;; bool out
+ (unspec_volatile:CC_Z [(const_int 0)] VUNSPEC_ATOMIC_CAS))
+ (set (match_operand:SIDI 0 "s_register_operand" "=&r") ;; val out
+ (match_operand:SIDI 1 "mem_noofs_operand" "+Ua")) ;; memory
+ (set (match_dup 1)
(unspec_volatile:SIDI
- [(match_operand:SIDI 3 "<cas_cmp_operand>" "<cas_cmp_str>") ;; expect
- (match_operand:SIDI 4 "s_register_operand" "r") ;; desired
- (match_operand:SI 5 "const_int_operand") ;; is_weak
- (match_operand:SI 6 "const_int_operand") ;; mod_s
- (match_operand:SI 7 "const_int_operand")] ;; mod_f
+ [(match_operand:SIDI 2 "<cas_cmp_operand>" "<cas_cmp_str>") ;; expect
+ (match_operand:SIDI 3 "s_register_operand" "r") ;; desired
+ (match_operand:SI 4 "const_int_operand") ;; is_weak
+ (match_operand:SI 5 "const_int_operand") ;; mod_s
+ (match_operand:SI 6 "const_int_operand")] ;; mod_f
VUNSPEC_ATOMIC_CAS))
- (clobber (reg:CC CC_REGNUM))]
+ (clobber (match_scratch:SI 7 "=&r"))]
"<sync_predtab>"
"#"
"&& reload_completed"
@@ -360,7 +360,8 @@
[(match_operand:NARROW 1 "mem_noofs_operand" "Ua")]
VUNSPEC_LL)))]
"TARGET_HAVE_LDREXBH"
- "ldrex<sync_sfx>\t%0, %C1")
+ "ldrex<sync_sfx>%?\t%0, %C1"
+ [(set_attr "predicable" "yes")])
(define_insn "arm_load_exclusivesi"
[(set (match_operand:SI 0 "s_register_operand" "=r")
@@ -368,7 +369,8 @@
[(match_operand:SI 1 "mem_noofs_operand" "Ua")]
VUNSPEC_LL))]
"TARGET_HAVE_LDREX"
- "ldrex\t%0, %C1")
+ "ldrex%?\t%0, %C1"
+ [(set_attr "predicable" "yes")])
(define_insn "arm_load_exclusivedi"
[(set (match_operand:DI 0 "s_register_operand" "=r")
@@ -384,8 +386,9 @@
Note that the 1st register always gets the lowest word in memory. */
gcc_assert ((REGNO (target) & 1) == 0);
operands[2] = gen_rtx_REG (SImode, REGNO (target) + 1);
- return "ldrexd\t%0, %2, %C1";
- })
+ return "ldrexd%?\t%0, %2, %C1";
+ }
+ [(set_attr "predicable" "yes")])
(define_insn "arm_store_exclusive<mode>"
[(set (match_operand:SI 0 "s_register_operand" "=&r")
@@ -405,7 +408,8 @@
Note that the 1st register always gets the lowest word in memory. */
gcc_assert ((REGNO (value) & 1) == 0 || TARGET_THUMB2);
operands[3] = gen_rtx_REG (SImode, REGNO (value) + 1);
- return "strexd\t%0, %2, %3, %C1";
+ return "strexd%?\t%0, %2, %3, %C1";
}
- return "strex<sync_sfx>\t%0, %2, %C1";
- })
+ return "strex<sync_sfx>%?\t%0, %2, %C1";
+ }
+ [(set_attr "predicable" "yes")])