diff --git a/gcc/config/sparc/constraints.md b/gcc/config/sparc/constraints.md
index 317602c..472490f 100644
--- a/gcc/config/sparc/constraints.md
+++ b/gcc/config/sparc/constraints.md
@@ -19,7 +19,7 @@
 
 ;;; Unused letters:
 ;;;    AB                       
-;;;    a        jkl    q  tuvwxyz
+;;;    a        jkl    q  tuv xyz
 
 
 ;; Register constraints
@@ -44,6 +44,9 @@
 (define_register_constraint "h" "(TARGET_V9 && TARGET_V8PLUS ? I64_REGS : NO_REGS)"
  "64-bit global or out register in V8+ mode")
 
+(define_memory_constraint "w"
+  "A memory with only a base register"
+  (match_operand 0 "mem_noofs_operand"))
 
 ;; Floating-point constant constraints
 
diff --git a/gcc/config/sparc/predicates.md b/gcc/config/sparc/predicates.md
index 43d7168..c886b86 100644
--- a/gcc/config/sparc/predicates.md
+++ b/gcc/config/sparc/predicates.md
@@ -467,6 +467,10 @@
        (match_test "call_address_operand (XEXP (op, 0), mode)")))
 
 
+(define_predicate "mem_noofs_operand"
+  (and (match_code "mem")
+       (match_code "reg" "0")))
+
 ;; Predicates for operators.
 
 ;; Return true if OP is a comparison operator.  This allows the use of
diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h
index fbb2ae8..153c061 100644
--- a/gcc/config/sparc/sparc-protos.h
+++ b/gcc/config/sparc/sparc-protos.h
@@ -104,7 +104,7 @@ extern int v9_regcmp_p (enum rtx_code);
    32 bits of REG are 0 before INSN.  */   
 extern int sparc_check_64 (rtx, rtx);
 extern rtx gen_df_reg (rtx, int);
-extern void sparc_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx);
+extern void sparc_expand_compare_and_swap (rtx op[]);
 extern void sparc_expand_vector_init (rtx, rtx);
 extern void sparc_expand_vec_perm_bmask(enum machine_mode, rtx);
 extern bool sparc_expand_conditional_move (enum machine_mode, rtx *);
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 2de6587..d75fc1a 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -10897,8 +10897,9 @@ sparc_emit_membar_for_model (enum memmodel model,
 /* Expand code to perform a 8 or 16-bit compare and swap by doing 32-bit
    compare and swap on the word containing the byte or half-word.  */
 
-void
-sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+static void
+sparc_expand_compare_and_swap_12 (rtx bool_result, rtx result, rtx mem,
+				  rtx oldval, rtx newval)
 {
   rtx addr1 = force_reg (Pmode, XEXP (mem, 0));
   rtx addr = gen_reg_rtx (Pmode);
@@ -10923,7 +10924,7 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
   set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
   MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
 
-  val = force_reg (SImode, memsi);
+  val = copy_to_reg (memsi);
 
   emit_insn (gen_rtx_SET (VOIDmode, off,
 			  gen_rtx_XOR (SImode, off,
@@ -10969,7 +10970,9 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
   emit_insn (gen_rtx_SET (VOIDmode, newvalue,
 			  gen_rtx_IOR (SImode, newv, val)));
 
-  emit_insn (gen_sync_compare_and_swapsi (res, memsi, oldvalue, newvalue));
+  emit_move_insn (bool_result, const1_rtx);
+
+  emit_insn (gen_atomic_compare_and_swapsi_1 (res, memsi, oldvalue, newvalue));
 
   emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label);
 
@@ -10977,6 +10980,8 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
 			  gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
 				       res)));
 
+  emit_move_insn (bool_result, const0_rtx);
+
   cc = gen_compare_reg_1 (NE, resv, val);
   emit_insn (gen_rtx_SET (VOIDmode, val, resv));
 
@@ -10995,6 +11000,49 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
   emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
 }
 
+/* Expand code to perform a compare-and-swap.  */
+
+void
+sparc_expand_compare_and_swap (rtx operands[])
+{
+  rtx bval, retval, mem, oldval, newval;
+  enum machine_mode mode;
+  enum memmodel model;
+
+  bval = operands[0];
+  retval = operands[1];
+  mem = operands[2];
+  oldval = operands[3];
+  newval = operands[4];
+  model = (enum memmodel) INTVAL (operands[6]);
+  mode = GET_MODE (mem);
+
+  sparc_emit_membar_for_model (model, 3, 1);
+
+  if (reg_overlap_mentioned_p (retval, oldval))
+    oldval = copy_to_reg (oldval);
+
+  if (mode == QImode || mode == HImode)
+    sparc_expand_compare_and_swap_12 (bval, retval, mem, oldval, newval);
+  else
+    {
+      rtx (*gen) (rtx, rtx, rtx, rtx);
+      rtx x;
+
+      if (mode == SImode)
+	gen = gen_atomic_compare_and_swapsi_1;
+      else
+	gen = gen_atomic_compare_and_swapdi_1;
+      emit_insn (gen (retval, mem, oldval, newval));
+
+      x = emit_store_flag (bval, EQ, retval, oldval, mode, 1, 1);
+      if (x != bval)
+	convert_move (bval, x, 1);
+    }
+
+  sparc_emit_membar_for_model (model, 3, 2);
+}
+
 void
 sparc_expand_vec_perm_bmask (enum machine_mode vmode, rtx sel)
 {
diff --git a/gcc/config/sparc/sync.md b/gcc/config/sparc/sync.md
index 7c151c1..d38a828 100644
--- a/gcc/config/sparc/sync.md
+++ b/gcc/config/sparc/sync.md
@@ -147,55 +147,37 @@
   [(set_attr "type" "store,store,fpstore")
    (set_attr "cpu_feature" "v9,*,*")])
 
-;;;;;;;;
-
-(define_expand "sync_compare_and_swap<mode>"
-  [(match_operand:I12MODE 0 "register_operand" "")
-   (match_operand:I12MODE 1 "memory_operand" "")
-   (match_operand:I12MODE 2 "register_operand" "")
-   (match_operand:I12MODE 3 "register_operand" "")]
+(define_expand "atomic_compare_and_swap<mode>"
+  [(match_operand:SI 0 "register_operand" "")		;; bool output
+   (match_operand:I 1 "register_operand" "")		;; val output
+   (match_operand:I 2 "mem_noofs_operand" "")		;; memory
+   (match_operand:I 3 "register_operand" "")		;; expected
+   (match_operand:I 4 "register_operand" "")		;; 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
   "TARGET_V9"
 {
-  sparc_expand_compare_and_swap_12 (operands[0], operands[1],
-				    operands[2], operands[3]);
+  sparc_expand_compare_and_swap (operands);
   DONE;
 })
 
-(define_expand "sync_compare_and_swap<mode>"
-  [(parallel
-     [(set (match_operand:I48MODE 0 "register_operand" "")
-	   (match_operand:I48MODE 1 "memory_operand" ""))
-      (set (match_dup 1)
-	   (unspec_volatile:I48MODE
-	     [(match_operand:I48MODE 2 "register_operand" "")
-	      (match_operand:I48MODE 3 "register_operand" "")]
-	     UNSPECV_CAS))])]
-  "TARGET_V9"
-{
-  if (!REG_P (XEXP (operands[1], 0)))
-    {
-      rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
-      operands[1] = replace_equiv_address (operands[1], addr);
-    }
-  emit_insn (gen_memory_barrier ());
-})
-
-(define_insn "*sync_compare_and_swap<mode>"
+(define_insn "atomic_compare_and_swap<mode>_1"
   [(set (match_operand:I48MODE 0 "register_operand" "=r")
-	(mem:I48MODE (match_operand 1 "register_operand" "r")))
-   (set (mem:I48MODE (match_dup 1))
+	(match_operand:I48MODE 1 "mem_noofs_operand" "+w"))
+   (set (match_dup 1)
 	(unspec_volatile:I48MODE
 	  [(match_operand:I48MODE 2 "register_operand" "r")
 	   (match_operand:I48MODE 3 "register_operand" "0")]
 	  UNSPECV_CAS))]
   "TARGET_V9 && (<MODE>mode == SImode || TARGET_ARCH64)"
-  "cas<modesuffix>\t[%1], %2, %0"
+  "cas<modesuffix>\t%1, %2, %0"
   [(set_attr "type" "multi")])
 
-(define_insn "*sync_compare_and_swapdi_v8plus"
+(define_insn "*atomic_compare_and_swapdi_v8plus"
   [(set (match_operand:DI 0 "register_operand" "=h")
-	(mem:DI (match_operand 1 "register_operand" "r")))
-   (set (mem:DI (match_dup 1))
+	(match_operand:DI 1 "mem_noofs_operand" "+w"))
+   (set (match_dup 1)
 	(unspec_volatile:DI
 	  [(match_operand:DI 2 "register_operand" "h")
 	   (match_operand:DI 3 "register_operand" "0")]
@@ -210,12 +192,14 @@
     output_asm_insn ("srl\t%L2, 0, %L2", operands);
   output_asm_insn ("sllx\t%H2, 32, %H3", operands);
   output_asm_insn ("or\t%L2, %H3, %H3", operands);
-  output_asm_insn ("casx\t[%1], %H3, %L3", operands);
+  output_asm_insn ("casx\t%1, %H3, %L3", operands);
   return "srlx\t%L3, 32, %H3";
 }
   [(set_attr "type" "multi")
    (set_attr "length" "8")])
 
+;;;;;;;;
+
 (define_expand "sync_lock_test_and_set<mode>"
   [(match_operand:I12MODE 0 "register_operand" "")
    (match_operand:I12MODE 1 "memory_operand" "")
