diff mbox

[rs6000,testsuite] Fix PR target/64579, __TM_end __builtin_tend failed to return transactional state

Message ID 1429816564.21947.110.camel@otta
State New
Headers show

Commit Message

Peter Bergner April 23, 2015, 7:16 p.m. UTC
On Wed, 2015-04-22 at 17:16 -0500, Segher Boessenkool wrote:
> On Wed, Apr 22, 2015 at 08:43:10AM -0500, Peter Bergner wrote:
> > > Maybe you can fold tabortdc with tabortwc now?  Use one UNSPEC name
> > > for both, :GPR and <wd>?
> > 
> > Wouldn't that change the tabortwc pattern to use DImode rather
> > than SImode when compiled with -m64 or -m32 -mpowerpc64?
> > I'm not sure we want that.
> 
> The GPR mode iterator creates two patterns, one for SI and one for DI,
> and the tabortwc would be the one for SI if you use <wd>.

Ok, I combined the tabortdc and tabortwc patterns, as well as the
tabortdci and tabortwci patterns.  Thanks for the suggestion.



> I'm still a bit worried about putting a reg in the RTL (while the instruction
> doesn't actually use one), but perhaps it's harmless.

Ok, I created a separate ttest define_insn that hard codes the operands.
I switched to using r1 rather than r0 as the second operand, for the
reason that there could be code that sets r0 directly before this insn
and I didn't want to create a unneeded read-after-write dependency.
I thought r1 should be safe to use, since it's only updated in the
prologue/epilogue and should be constant for the life of the function.



> > > > +/* { dg-final { scan-assembler-times "tabortdci\\." 1 { target lp64 } } } */
> > > 
> > > This skips this test on -m32 -mpowerpc64, is that on purpose?
> > 
> > Ummm, not exactly.  :-)   Not that many people test that though.
> > I'll see if I can find a replacement for lp64 that covers that case.
> 
> Maybe just { powerpc64 } works?

powerpc64 doesn't work.  It tells us whether the target will execute
64-bit instructions or not.  When you run on a 64-bit host, then both
32-bit binaries and 64-bit binaries will gladly execute the 64-bit
category extsw instruction just fine.  This doesn't tell us that the
target has underlying 64-bit registers for its use or not.  Given that,
I think we should just leave this as lp64.

Updated patch below passed bootstrap and regtesting with no
regressions, so how does this look for trunk?

I'd also like to backport this to the open release branches so 
everything matches. Is that ok once I've verified bootstrap and
regtesting on each branch?


Peter



gcc/
	PR target/64579
	* config/rs6000/htm.md: Remove all define_expands.
	(UNSPECV_HTM_TABORTDC, UNSPECV_HTM_TABORTDCI, UNSPECV_HTM_TABORTWC,
	UNSPECV_HTM_TABORTWCI): Remove.
	(UNSPECV_HTM_TABORTXC, UNSPECV_HTM_TABORTXCI, UNSPECV_HTM_TTEST): New.
	(tabort_internal, tbegin_internal, tcheck_internal, tend_internal,
	trechkpt_internal, treclaim_internal, tsr_internal): Rename from this...
	(tabort, tbegin, tcheck, tend, trechkpt, treclaim, tsr): ...to this.
	(tabortdc_internal, tabortdci_internal, tabortwc_internal,
	tabortwci_internal): Remove define_insns.
	(tabort<wd>c, tabort<wd>ci): New define_insns.
	(tabort): Use gpc_reg_operand.
	(tcheck): Remove operand.
	(htm_mfspr_<mode>, htm_mtspr_<mode>): Use GPR mode macro.
	* config/rs6000/htmxlintrin.h (__TM_end): Use _HTM_TRANSACTIONAL as
	expected value.
	* config/rs6000/rs6000-builtin.def (BU_HTM_SPR0): Remove.
	(BU_HTM_SPR1): Rename to BU_HTM_V1.  Remove use of RS6000_BTC_SPR.
	(tabort, tabortdc, tabortdci, tabortwc, tabortwci, tbegin,
	tcheck, tend, tendall, trechkpt, treclaim, tresume, tsuspend,
	tsr, ttest): Pass in the RS6000_BTC_CR attribute.
	(get_tfhar, set_tfhar, get_tfiar, set_tfiar, get_texasr, set_texasr,
	get_texasru, set_texasru): Pass in the RS6000_BTC_SPR attribute.
	(tcheck): Remove builtin argument.
	* config/rs6000/rs6000.c (rs6000_htm_spr_icode): Use TARGET_POWERPC64
	not TARGET_64BIT.
	(htm_expand_builtin): Fix usage of expandedp.  Disallow usage of the
	tabortdc and tabortdci builtins when not in 64-bit mode.
	Modify code to handle the loss of the HTM define_expands.
	Emit code to copy the CR register to TARGET.
	(htm_init_builtins): Modify code to handle the loss of the HTM
	define_expands.
	* config/rs6000/rs6000.h (RS6000_BTC_32BIT): Delete.
	(RS6000_BTC_64BIT): Likewise.
	(RS6000_BTC_CR): New macro.
	* doc/extend.texi: Update documentation for htm builtins.

gcc/testsuite/

	PR target/64579
	* gcc.target/powerpc/htm-1.c: New test.
	* gcc.target/powerpc/htm-builtin-1.c (__builtin_tabortdc): Only test
	on 64-bit compiles.
	(__builtin_tabortdci): Likewise.
	(__builtin_tcheck): Remove operand.
	* lib/target-supports.exp (check_htm_hw_available): New function.

Comments

Segher Boessenkool April 24, 2015, 3:34 p.m. UTC | #1
On Thu, Apr 23, 2015 at 02:16:04PM -0500, Peter Bergner wrote:
> Ok, I created a separate ttest define_insn that hard codes the operands.
> I switched to using r1 rather than r0 as the second operand, for the
> reason that there could be code that sets r0 directly before this insn
> and I didn't want to create a unneeded read-after-write dependency.
> I thought r1 should be safe to use, since it's only updated in the
> prologue/epilogue and should be constant for the life of the function.

GPR1 is very likely already read before as well :-)

> > Maybe just { powerpc64 } works?
> 
> powerpc64 doesn't work.  It tells us whether the target will execute
> 64-bit instructions or not.

Ah yes, it is more like a "powerpc64_hw".  Oh well.

All looks great to me now, thanks for the changes,


Segher
David Edelsohn April 24, 2015, 3:40 p.m. UTC | #2
On Fri, Apr 24, 2015 at 11:34 AM, Segher Boessenkool
<segher@kernel.crashing.org> wrote:
> On Thu, Apr 23, 2015 at 02:16:04PM -0500, Peter Bergner wrote:
>> Ok, I created a separate ttest define_insn that hard codes the operands.
>> I switched to using r1 rather than r0 as the second operand, for the
>> reason that there could be code that sets r0 directly before this insn
>> and I didn't want to create a unneeded read-after-write dependency.
>> I thought r1 should be safe to use, since it's only updated in the
>> prologue/epilogue and should be constant for the life of the function.
>
> GPR1 is very likely already read before as well :-)
>
>> > Maybe just { powerpc64 } works?
>>
>> powerpc64 doesn't work.  It tells us whether the target will execute
>> 64-bit instructions or not.
>
> Ah yes, it is more like a "powerpc64_hw".  Oh well.
>
> All looks great to me now, thanks for the changes,

Okay for me.

Thanks, David
Peter Bergner April 27, 2015, 3:21 p.m. UTC | #3
On Fri, 2015-04-24 at 11:40 -0400, David Edelsohn wrote:
> On Fri, Apr 24, 2015 at 11:34 AM, Segher Boessenkool
> > All looks great to me now, thanks for the changes,
> 
> Okay for me.

In back porting my patch, I see that the patch doesn't apply
cleanly to the 4.8/4.9 branch code.  Looking at why, I see that it's
because the 4.8/4.9 code doesn't have the following change from
Segher.  I think we want this patch back ported too, don't we?

2014-09-11  Segher Boessenkool  <segher@kernel.crashing.org>

       * config/rs6000/htm.md (tabort, tabortdc, tabortdci, tabortwc,
       tabortwci, tbegin, tcheck, tend, trechkpt, treclaim, tsr): Use xor
       instead of minus.
       * config/rs6000/vector.md (cr6_test_for_zero_reverse,
       cr6_test_for_lt_reverse): Ditto.

If so, I can back port it and test it along with mine.  Otherwise, I'll
just work around it.  Let me know what you want me to do.

Peter
diff mbox

Patch

Index: gcc/config/rs6000/htm.md
===================================================================
--- gcc/config/rs6000/htm.md	(revision 222127)
+++ gcc/config/rs6000/htm.md	(working copy)
@@ -32,197 +32,52 @@  (define_constants
 
 (define_c_enum "unspecv"
   [UNSPECV_HTM_TABORT
-   UNSPECV_HTM_TABORTDC
-   UNSPECV_HTM_TABORTDCI
-   UNSPECV_HTM_TABORTWC
-   UNSPECV_HTM_TABORTWCI
+   UNSPECV_HTM_TABORTXC
+   UNSPECV_HTM_TABORTXCI
    UNSPECV_HTM_TBEGIN
    UNSPECV_HTM_TCHECK
    UNSPECV_HTM_TEND
    UNSPECV_HTM_TRECHKPT
    UNSPECV_HTM_TRECLAIM
    UNSPECV_HTM_TSR
+   UNSPECV_HTM_TTEST
    UNSPECV_HTM_MFSPR
    UNSPECV_HTM_MTSPR
   ])
 
 
-(define_expand "tabort"
-  [(set (match_dup 2)
-	(unspec_volatile:CC [(match_operand:SI 1 "int_reg_operand" "")]
-			    UNSPECV_HTM_TABORT))
-   (set (match_dup 3)
-	(eq:SI (match_dup 2)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 3)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[2] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[3] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tabort_internal"
+(define_insn "tabort"
   [(set (match_operand:CC 1 "cc_reg_operand" "=x")
-	(unspec_volatile:CC [(match_operand:SI 0 "int_reg_operand" "r")]
+	(unspec_volatile:CC [(match_operand:SI 0 "gpc_reg_operand" "r")]
 			    UNSPECV_HTM_TABORT))]
   "TARGET_HTM"
   "tabort. %0"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "tabortdc"
-  [(set (match_dup 4)
-	(unspec_volatile:CC [(match_operand 1 "u5bit_cint_operand" "n")
-			     (match_operand:SI 2 "gpc_reg_operand" "r")
-			     (match_operand:SI 3 "gpc_reg_operand" "r")]
-			    UNSPECV_HTM_TABORTDC))
-   (set (match_dup 5)
-	(eq:SI (match_dup 4)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 5)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[4] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[5] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tabortdc_internal"
-  [(set (match_operand:CC 3 "cc_reg_operand" "=x")
-	(unspec_volatile:CC [(match_operand 0 "u5bit_cint_operand" "n")
-			     (match_operand:SI 1 "gpc_reg_operand" "r")
-			     (match_operand:SI 2 "gpc_reg_operand" "r")]
-			    UNSPECV_HTM_TABORTDC))]
-  "TARGET_HTM"
-  "tabortdc. %0,%1,%2"
-  [(set_attr "type" "htm")
-   (set_attr "length" "4")])
-
-(define_expand "tabortdci"
-  [(set (match_dup 4)
-	(unspec_volatile:CC [(match_operand 1 "u5bit_cint_operand" "n")
-			     (match_operand:SI 2 "gpc_reg_operand" "r")
-			     (match_operand 3 "s5bit_cint_operand" "n")]
-			    UNSPECV_HTM_TABORTDCI))
-   (set (match_dup 5)
-	(eq:SI (match_dup 4)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 5)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[4] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[5] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tabortdci_internal"
+(define_insn "tabort<wd>c"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x")
 	(unspec_volatile:CC [(match_operand 0 "u5bit_cint_operand" "n")
-			     (match_operand:SI 1 "gpc_reg_operand" "r")
-			     (match_operand 2 "s5bit_cint_operand" "n")]
-			    UNSPECV_HTM_TABORTDCI))]
+			     (match_operand:GPR 1 "gpc_reg_operand" "r")
+			     (match_operand:GPR 2 "gpc_reg_operand" "r")]
+			    UNSPECV_HTM_TABORTXC))]
   "TARGET_HTM"
-  "tabortdci. %0,%1,%2"
-  [(set_attr "type" "htm")
-   (set_attr "length" "4")])
-
-(define_expand "tabortwc"
-  [(set (match_dup 4)
-	(unspec_volatile:CC [(match_operand 1 "u5bit_cint_operand" "n")
-			     (match_operand:SI 2 "gpc_reg_operand" "r")
-			     (match_operand:SI 3 "gpc_reg_operand" "r")]
-			    UNSPECV_HTM_TABORTWC))
-   (set (match_dup 5)
-	(eq:SI (match_dup 4)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 5)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[4] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[5] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tabortwc_internal"
-  [(set (match_operand:CC 3 "cc_reg_operand" "=x")
-	(unspec_volatile:CC [(match_operand 0 "u5bit_cint_operand" "n")
-			     (match_operand:SI 1 "gpc_reg_operand" "r")
-			     (match_operand:SI 2 "gpc_reg_operand" "r")]
-			    UNSPECV_HTM_TABORTWC))]
-  "TARGET_HTM"
-  "tabortwc. %0,%1,%2"
+  "tabort<wd>c. %0,%1,%2"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "tabortwci"
-  [(set (match_dup 4)
-	(unspec_volatile:CC [(match_operand 1 "u5bit_cint_operand" "n")
-			     (match_operand:SI 2 "gpc_reg_operand" "r")
-			     (match_operand 3 "s5bit_cint_operand" "n")]
-			    UNSPECV_HTM_TABORTWCI))
-   (set (match_dup 5)
-	(eq:SI (match_dup 4)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 5)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[4] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[5] = gen_reg_rtx (SImode);
-})
-
-(define_expand "ttest"
-  [(set (match_dup 1)
-	(unspec_volatile:CC [(const_int 0)
-			     (reg:SI 0)
-			     (const_int 0)]
-			    UNSPECV_HTM_TABORTWCI))
-   (set (subreg:CC (match_dup 2) 0) (match_dup 1))
-   (set (match_dup 3) (lshiftrt:SI (match_dup 2) (const_int 28)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(and:SI (match_dup 3)
-		(const_int 15)))]
-  "TARGET_HTM"
-{
-  operands[1] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[2] = gen_reg_rtx (SImode);
-  operands[3] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tabortwci_internal"
+(define_insn "tabort<wd>ci"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x")
 	(unspec_volatile:CC [(match_operand 0 "u5bit_cint_operand" "n")
-			     (match_operand:SI 1 "gpc_reg_operand" "r")
+			     (match_operand:GPR 1 "gpc_reg_operand" "r")
 			     (match_operand 2 "s5bit_cint_operand" "n")]
-			    UNSPECV_HTM_TABORTWCI))]
+			    UNSPECV_HTM_TABORTXCI))]
   "TARGET_HTM"
-  "tabortwci. %0,%1,%2"
+  "tabort<wd>ci. %0,%1,%2"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "tbegin"
-  [(set (match_dup 2)
-	(unspec_volatile:CC [(match_operand 1 "const_0_to_1_operand" "n")]
-			    UNSPECV_HTM_TBEGIN))
-   (set (match_dup 3)
-	(eq:SI (match_dup 2)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 3)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[2] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[3] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tbegin_internal"
+(define_insn "tbegin"
   [(set (match_operand:CC 1 "cc_reg_operand" "=x")
 	(unspec_volatile:CC [(match_operand 0 "const_0_to_1_operand" "n")]
 			    UNSPECV_HTM_TBEGIN))]
@@ -231,48 +86,16 @@  (define_insn "*tbegin_internal"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "tcheck"
-  [(set (match_dup 2)
-	(unspec_volatile:CC [(match_operand 1 "u3bit_cint_operand" "n")]
-			    UNSPECV_HTM_TCHECK))
-   (set (match_dup 3)
-	(eq:SI (match_dup 2)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 3)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[2] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[3] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tcheck_internal"
-  [(set (match_operand:CC 1 "cc_reg_operand" "=x")
-	(unspec_volatile:CC [(match_operand 0 "u3bit_cint_operand" "n")]
+(define_insn "tcheck"
+  [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+	(unspec_volatile:CC [(const_int 0)]
 			    UNSPECV_HTM_TCHECK))]
   "TARGET_HTM"
   "tcheck %0"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "tend"
-  [(set (match_dup 2)
-	(unspec_volatile:CC [(match_operand 1 "const_0_to_1_operand" "n")]
-			    UNSPECV_HTM_TEND))
-   (set (match_dup 3)
-	(eq:SI (match_dup 2)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 3)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[2] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[3] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tend_internal"
+(define_insn "tend"
   [(set (match_operand:CC 1 "cc_reg_operand" "=x")
 	(unspec_volatile:CC [(match_operand 0 "const_0_to_1_operand" "n")]
 			    UNSPECV_HTM_TEND))]
@@ -281,23 +104,7 @@  (define_insn "*tend_internal"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "trechkpt"
-  [(set (match_dup 1)
-	(unspec_volatile:CC [(const_int 0)]
-			    UNSPECV_HTM_TRECHKPT))
-   (set (match_dup 2)
-	(eq:SI (match_dup 1)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 2)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[1] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[2] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*trechkpt_internal"
+(define_insn "trechkpt"
   [(set (match_operand:CC 0 "cc_reg_operand" "=x")
 	(unspec_volatile:CC [(const_int 0)]
 			    UNSPECV_HTM_TRECHKPT))]
@@ -306,23 +113,7 @@  (define_insn "*trechkpt_internal"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "treclaim"
-  [(set (match_dup 2)
-	(unspec_volatile:CC [(match_operand:SI 1 "gpc_reg_operand" "r")]
-			    UNSPECV_HTM_TRECLAIM))
-   (set (match_dup 3)
-	(eq:SI (match_dup 2)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 3)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[2] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[3] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*treclaim_internal"
+(define_insn "treclaim"
   [(set (match_operand:CC 1 "cc_reg_operand" "=x")
 	(unspec_volatile:CC [(match_operand:SI 0 "gpc_reg_operand" "r")]
 			    UNSPECV_HTM_TRECLAIM))]
@@ -331,23 +122,7 @@  (define_insn "*treclaim_internal"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
-(define_expand "tsr"
-  [(set (match_dup 2)
-	(unspec_volatile:CC [(match_operand 1 "const_0_to_1_operand" "n")]
-			    UNSPECV_HTM_TSR))
-   (set (match_dup 3)
-	(eq:SI (match_dup 2)
-	       (const_int 0)))
-   (set (match_operand:SI 0 "int_reg_operand" "")
-	(xor:SI (match_dup 3)
-		(const_int 1)))]
-  "TARGET_HTM"
-{
-  operands[2] = gen_rtx_REG (CCmode, CR0_REGNO);
-  operands[3] = gen_reg_rtx (SImode);
-})
-
-(define_insn "*tsr_internal"
+(define_insn "tsr"
   [(set (match_operand:CC 1 "cc_reg_operand" "=x")
 	(unspec_volatile:CC [(match_operand 0 "const_0_to_1_operand" "n")]
 			    UNSPECV_HTM_TSR))]
@@ -356,21 +131,30 @@  (define_insn "*tsr_internal"
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
+(define_insn "ttest"
+  [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+	(unspec_volatile:CC [(const_int 0)]
+			    UNSPECV_HTM_TTEST))]
+  "TARGET_HTM"
+  "tabortwci. 0,1,0"
+  [(set_attr "type" "htm")
+   (set_attr "length" "4")])
+
 (define_insn "htm_mfspr_<mode>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
-        (unspec_volatile:P [(match_operand 1 "u10bit_cint_operand" "n")
-			    (match_operand:P 2 "htm_spr_reg_operand" "")]
-			   UNSPECV_HTM_MFSPR))]
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+        (unspec_volatile:GPR [(match_operand 1 "u10bit_cint_operand" "n")
+			      (match_operand:GPR 2 "htm_spr_reg_operand" "")]
+			     UNSPECV_HTM_MFSPR))]
   "TARGET_HTM"
   "mfspr %0,%1";
   [(set_attr "type" "htm")
    (set_attr "length" "4")])
 
 (define_insn "htm_mtspr_<mode>"
-  [(set (match_operand:P 2 "htm_spr_reg_operand" "")
-        (unspec_volatile:P [(match_operand:P 0 "gpc_reg_operand" "r")
-			    (match_operand 1 "u10bit_cint_operand" "n")]
-                           UNSPECV_HTM_MTSPR))]
+  [(set (match_operand:GPR 2 "htm_spr_reg_operand" "")
+        (unspec_volatile:GPR [(match_operand:GPR 0 "gpc_reg_operand" "r")
+			      (match_operand 1 "u10bit_cint_operand" "n")]
+			     UNSPECV_HTM_MTSPR))]
   "TARGET_HTM"
   "mtspr %1,%0";
   [(set_attr "type" "htm")
Index: gcc/config/rs6000/htmxlintrin.h
===================================================================
--- gcc/config/rs6000/htmxlintrin.h	(revision 222127)
+++ gcc/config/rs6000/htmxlintrin.h	(working copy)
@@ -81,7 +81,8 @@  extern __inline long
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 __TM_end (void)
 {
-  if (__builtin_expect (__builtin_tend (0), 1))
+  unsigned char status = _HTM_STATE (__builtin_tend (0));
+  if (__builtin_expect (status, _HTM_TRANSACTIONAL))
     return 1;
   return 0;
 }
Index: gcc/config/rs6000/rs6000-builtin.def
===================================================================
--- gcc/config/rs6000/rs6000-builtin.def	(revision 222127)
+++ gcc/config/rs6000/rs6000-builtin.def	(working copy)
@@ -456,21 +456,12 @@ 
 		     | RS6000_BTC_TERNARY),				\
 		    CODE_FOR_ ## ICODE)			/* ICODE */
 
-#define BU_HTM_SPR0(ENUM, NAME, ATTR, ICODE)				\
-  RS6000_BUILTIN_H (HTM_BUILTIN_ ## ENUM,		/* ENUM */	\
-		    "__builtin_" NAME,			/* NAME */	\
-		    RS6000_BTM_HTM,			/* MASK */	\
-		    (RS6000_BTC_ ## ATTR		/* ATTR */	\
-		     | RS6000_BTC_SPR),					\
-		    CODE_FOR_ ## ICODE)			/* ICODE */
-
-#define BU_HTM_SPR1(ENUM, NAME, ATTR, ICODE)				\
+#define BU_HTM_V1(ENUM, NAME, ATTR, ICODE)				\
   RS6000_BUILTIN_H (HTM_BUILTIN_ ## ENUM,		/* ENUM */	\
 		    "__builtin_" NAME,			/* NAME */	\
 		    RS6000_BTM_HTM,			/* MASK */	\
 		    (RS6000_BTC_ ## ATTR		/* ATTR */	\
 		     | RS6000_BTC_UNARY					\
-		     | RS6000_BTC_SPR					\
 		     | RS6000_BTC_VOID),				\
 		    CODE_FOR_ ## ICODE)			/* ICODE */
 
@@ -1633,30 +1624,30 @@  BU_CRYPTO_OVERLOAD_3 (VSHASIGMA, "vshasi
 
 
 /* HTM functions.  */
-BU_HTM_1  (TABORT,	"tabort",	MISC,	tabort)
-BU_HTM_3  (TABORTDC,	"tabortdc",	MISC,	tabortdc)
-BU_HTM_3  (TABORTDCI,	"tabortdci",	MISC,	tabortdci)
-BU_HTM_3  (TABORTWC,	"tabortwc",	MISC,	tabortwc)
-BU_HTM_3  (TABORTWCI,	"tabortwci",	MISC,	tabortwci)
-BU_HTM_1  (TBEGIN,	"tbegin",	MISC,	tbegin)
-BU_HTM_1  (TCHECK,	"tcheck",	MISC,	tcheck)
-BU_HTM_1  (TEND,	"tend",		MISC,	tend)
-BU_HTM_0  (TENDALL,	"tendall",	MISC,	tend)
-BU_HTM_0  (TRECHKPT,	"trechkpt",	MISC,	trechkpt)
-BU_HTM_1  (TRECLAIM,	"treclaim",	MISC,	treclaim)
-BU_HTM_0  (TRESUME,	"tresume",	MISC,	tsr)
-BU_HTM_0  (TSUSPEND,	"tsuspend",	MISC,	tsr)
-BU_HTM_1  (TSR,		"tsr",		MISC,	tsr)
-BU_HTM_0  (TTEST,	"ttest",	MISC,	ttest)
-
-BU_HTM_SPR0 (GET_TFHAR,		"get_tfhar",	MISC,	nothing)
-BU_HTM_SPR1 (SET_TFHAR,		"set_tfhar",	MISC,	nothing)
-BU_HTM_SPR0 (GET_TFIAR,		"get_tfiar",	MISC,	nothing)
-BU_HTM_SPR1 (SET_TFIAR,		"set_tfiar",	MISC,	nothing)
-BU_HTM_SPR0 (GET_TEXASR,	"get_texasr",	MISC,	nothing)
-BU_HTM_SPR1 (SET_TEXASR,	"set_texasr",	MISC,	nothing)
-BU_HTM_SPR0 (GET_TEXASRU,	"get_texasru",	MISC,	nothing)
-BU_HTM_SPR1 (SET_TEXASRU,	"set_texasru",	MISC,	nothing)
+BU_HTM_1  (TABORT,	"tabort",	CR,	tabort)
+BU_HTM_3  (TABORTDC,	"tabortdc",	CR,	tabortdc)
+BU_HTM_3  (TABORTDCI,	"tabortdci",	CR,	tabortdci)
+BU_HTM_3  (TABORTWC,	"tabortwc",	CR,	tabortwc)
+BU_HTM_3  (TABORTWCI,	"tabortwci",	CR,	tabortwci)
+BU_HTM_1  (TBEGIN,	"tbegin",	CR,	tbegin)
+BU_HTM_0  (TCHECK,	"tcheck",	CR,	tcheck)
+BU_HTM_1  (TEND,	"tend",		CR,	tend)
+BU_HTM_0  (TENDALL,	"tendall",	CR,	tend)
+BU_HTM_0  (TRECHKPT,	"trechkpt",	CR,	trechkpt)
+BU_HTM_1  (TRECLAIM,	"treclaim",	CR,	treclaim)
+BU_HTM_0  (TRESUME,	"tresume",	CR,	tsr)
+BU_HTM_0  (TSUSPEND,	"tsuspend",	CR,	tsr)
+BU_HTM_1  (TSR,		"tsr",		CR,	tsr)
+BU_HTM_0  (TTEST,	"ttest",	CR,	ttest)
+
+BU_HTM_0  (GET_TFHAR,	"get_tfhar",	SPR,	nothing)
+BU_HTM_V1 (SET_TFHAR,	"set_tfhar",	SPR,	nothing)
+BU_HTM_0  (GET_TFIAR,	"get_tfiar",	SPR,	nothing)
+BU_HTM_V1 (SET_TFIAR,	"set_tfiar",	SPR,	nothing)
+BU_HTM_0  (GET_TEXASR,	"get_texasr",	SPR,	nothing)
+BU_HTM_V1 (SET_TEXASR,	"set_texasr",	SPR,	nothing)
+BU_HTM_0  (GET_TEXASRU,	"get_texasru",	SPR,	nothing)
+BU_HTM_V1 (SET_TEXASRU,	"set_texasru",	SPR,	nothing)
 
 
 /* 3 argument paired floating point builtins.  */
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 222127)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -12655,9 +12655,9 @@  static inline enum insn_code
 rs6000_htm_spr_icode (bool nonvoid)
 {
   if (nonvoid)
-    return (TARGET_64BIT) ? CODE_FOR_htm_mfspr_di : CODE_FOR_htm_mfspr_si;
+    return (TARGET_POWERPC64) ? CODE_FOR_htm_mfspr_di : CODE_FOR_htm_mfspr_si;
   else
-    return (TARGET_64BIT) ? CODE_FOR_htm_mtspr_di : CODE_FOR_htm_mtspr_si;
+    return (TARGET_POWERPC64) ? CODE_FOR_htm_mtspr_di : CODE_FOR_htm_mtspr_si;
 }
 
 /* Expand the HTM builtin in EXP and store the result in TARGET.
@@ -12671,7 +12671,17 @@  htm_expand_builtin (tree exp, rtx target
   const struct builtin_description *d;
   size_t i;
 
-  *expandedp = false;
+  *expandedp = true;
+
+  if (!TARGET_POWERPC64
+      && (fcode == HTM_BUILTIN_TABORTDC
+	  || fcode == HTM_BUILTIN_TABORTDCI))
+    {
+      size_t uns_fcode = (size_t)fcode;
+      const char *name = rs6000_builtin_info[uns_fcode].name;
+      error ("builtin %s is only valid in 64-bit mode", name);
+      return const0_rtx;
+    }
 
   /* Expand the HTM builtins.  */
   d = bdesc_htm;
@@ -12684,26 +12694,29 @@  htm_expand_builtin (tree exp, rtx target
 	call_expr_arg_iterator iter;
 	unsigned attr = rs6000_builtin_info[fcode].attr;
 	enum insn_code icode = d->icode;
+	const struct insn_operand_data *insn_op;
+	bool uses_spr = (attr & RS6000_BTC_SPR);
+	rtx cr = NULL_RTX;
 
-	if (attr & RS6000_BTC_SPR)
+	if (uses_spr)
 	  icode = rs6000_htm_spr_icode (nonvoid);
+	insn_op = &insn_data[icode].operand[0];
 
 	if (nonvoid)
 	  {
-	    machine_mode tmode = insn_data[icode].operand[0].mode;
+	    machine_mode tmode = (uses_spr) ? insn_op->mode : SImode;
 	    if (!target
 		|| GET_MODE (target) != tmode
-		|| !(*insn_data[icode].operand[0].predicate) (target, tmode))
+		|| (uses_spr && !(*insn_op->predicate) (target, tmode)))
 	      target = gen_reg_rtx (tmode);
-	    op[nopnds++] = target;
+	    if (uses_spr)
+	      op[nopnds++] = target;
 	  }
 
 	FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
 	{
-	  const struct insn_operand_data *insn_op;
-
 	  if (arg == error_mark_node || nopnds >= MAX_HTM_OPERANDS)
-	    return NULL_RTX;
+	    return const0_rtx;
 
 	  insn_op = &insn_data[icode].operand[nopnds];
 
@@ -12750,10 +12763,17 @@  htm_expand_builtin (tree exp, rtx target
 
 	/* If this builtin accesses SPRs, then pass in the appropriate
 	   SPR number and SPR regno as the last two operands.  */
-	if (attr & RS6000_BTC_SPR)
+	if (uses_spr)
 	  {
-	    op[nopnds++] = gen_rtx_CONST_INT (Pmode, htm_spr_num (fcode));
-	    op[nopnds++] = gen_rtx_REG (Pmode, htm_spr_regno (fcode));
+	    machine_mode mode = (TARGET_POWERPC64) ? DImode : SImode;
+	    op[nopnds++] = gen_rtx_CONST_INT (mode, htm_spr_num (fcode));
+	    op[nopnds++] = gen_rtx_REG (mode, htm_spr_regno (fcode));
+	  }
+	/* If this builtin accesses a CR, then pass in a scratch
+	   CR as the last operand.  */
+	else if (attr & RS6000_BTC_CR)
+	  { cr = gen_reg_rtx (CCmode);
+	    op[nopnds++] = cr;
 	  }
 
 #ifdef ENABLE_CHECKING
@@ -12766,7 +12786,7 @@  htm_expand_builtin (tree exp, rtx target
 	  expected_nopnds = 3;
 	if (!(attr & RS6000_BTC_VOID))
 	  expected_nopnds += 1;
-	if (attr & RS6000_BTC_SPR)
+	if (uses_spr)
 	  expected_nopnds += 2;
 
 	gcc_assert (nopnds == expected_nopnds && nopnds <= MAX_HTM_OPERANDS);
@@ -12793,12 +12813,41 @@  htm_expand_builtin (tree exp, rtx target
 	  return NULL_RTX;
 	emit_insn (pat);
 
-	*expandedp = true;
+	if (attr & RS6000_BTC_CR)
+	  {
+	    if (fcode == HTM_BUILTIN_TBEGIN)
+	      {
+		/* Emit code to set TARGET to true or false depending on
+		   whether the tbegin. instruction successfully or failed
+		   to start a transaction.  We do this by placing the 1's
+		   complement of CR's EQ bit into TARGET.  */
+		rtx scratch = gen_reg_rtx (SImode);
+		emit_insn (gen_rtx_SET (VOIDmode, scratch,
+					gen_rtx_EQ (SImode, cr,
+						     const0_rtx)));
+		emit_insn (gen_rtx_SET (VOIDmode, target,
+					gen_rtx_XOR (SImode, scratch,
+						     GEN_INT (1))));
+	      }
+	    else
+	      {
+		/* Emit code to copy the 4-bit condition register field
+		   CR into the least significant end of register TARGET.  */
+		rtx scratch1 = gen_reg_rtx (SImode);
+		rtx scratch2 = gen_reg_rtx (SImode);
+		rtx subreg = simplify_gen_subreg (CCmode, scratch1, SImode, 0);
+		emit_insn (gen_movcc (subreg, cr));
+		emit_insn (gen_lshrsi3 (scratch2, scratch1, GEN_INT (28)));
+		emit_insn (gen_andsi3 (target, scratch2, GEN_INT (0xf)));
+	      }
+	  }
+
 	if (nonvoid)
 	  return target;
 	return const0_rtx;
       }
 
+  *expandedp = false;
   return NULL_RTX;
 }
 
@@ -15287,8 +15336,31 @@  htm_init_builtins (void)
       bool void_func = (attr & RS6000_BTC_VOID);
       int attr_args = (attr & RS6000_BTC_TYPE_MASK);
       int nopnds = 0;
-      tree argtype = (attr & RS6000_BTC_SPR) ? long_unsigned_type_node
-					     : unsigned_type_node;
+      tree gpr_type_node;
+      tree rettype;
+      tree argtype;
+
+      if (TARGET_32BIT && TARGET_POWERPC64)
+	gpr_type_node = long_long_unsigned_type_node;
+      else
+	gpr_type_node = long_unsigned_type_node;
+
+      if (attr & RS6000_BTC_SPR)
+	{
+	  rettype = gpr_type_node;
+	  argtype = gpr_type_node;
+	}
+      else if (d->code == HTM_BUILTIN_TABORTDC
+	       || d->code == HTM_BUILTIN_TABORTDCI)
+	{
+	  rettype = unsigned_type_node;
+	  argtype = gpr_type_node;
+	}
+      else
+	{
+	  rettype = unsigned_type_node;
+	  argtype = unsigned_type_node;
+	}
 
       if ((mask & builtin_mask) != mask)
 	{
@@ -15305,7 +15377,7 @@  htm_init_builtins (void)
 	  continue;
 	}
 
-      op[nopnds++] = (void_func) ? void_type_node : argtype;
+      op[nopnds++] = (void_func) ? void_type_node : rettype;
 
       if (attr_args == RS6000_BTC_UNARY)
 	op[nopnds++] = argtype;
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 222127)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -2573,9 +2573,8 @@  extern int frame_pointer_needed;
 /* Miscellaneous information.  */
 #define RS6000_BTC_SPR		0x01000000	/* function references SPRs.  */
 #define RS6000_BTC_VOID		0x02000000	/* function has no return value.  */
-#define RS6000_BTC_OVERLOADED	0x04000000	/* function is overloaded.  */
-#define RS6000_BTC_32BIT	0x08000000	/* function references SPRs.  */
-#define RS6000_BTC_64BIT	0x10000000	/* function references SPRs.  */
+#define RS6000_BTC_CR		0x04000000	/* function references a CR.  */
+#define RS6000_BTC_OVERLOADED	0x08000000	/* function is overloaded.  */
 #define RS6000_BTC_MISC_MASK	0x1f000000	/* Mask of the misc info.  */
 
 /* Convenience macros to document the instruction type.  */
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 222127)
+++ gcc/doc/extend.texi	(working copy)
@@ -15121,10 +15121,15 @@  The following low level built-in functio
 @option{-mhtm} or @option{-mcpu=CPU} where CPU is `power8' or later.
 They all generate the machine instruction that is part of the name.
 
-The HTM built-ins return true or false depending on their success and
-their arguments match exactly the type and order of the associated
-hardware instruction's operands.  Refer to the ISA manual for a
-description of each instruction's operands.
+The HTM builtins (with the exception of @code{__builtin_tbegin}) return
+the full 4-bit condition register value set by their associated hardware
+instruction.  The header file @code{htmintrin.h} defines some macros that can
+be used to decipher the return value.  The @code{__builtin_tbegin} builtin
+returns a simple true or false value depending on whether a transaction was
+successfully started or not.  The arguments of the builtins match exactly the
+type and order of the associated hardware instruction's operands, except for
+the @code{__builtin_tcheck} builtin, which does not take any input arguments.
+Refer to the ISA manual for a description of each instruction's operands.
 
 @smallexample
 unsigned int __builtin_tbegin (unsigned int)
@@ -15136,7 +15141,7 @@  unsigned int __builtin_tabortdci (unsign
 unsigned int __builtin_tabortwc (unsigned int, unsigned int, unsigned int)
 unsigned int __builtin_tabortwci (unsigned int, unsigned int, int)
 
-unsigned int __builtin_tcheck (unsigned int)
+unsigned int __builtin_tcheck (void)
 unsigned int __builtin_treclaim (unsigned int)
 unsigned int __builtin_trechkpt (void)
 unsigned int __builtin_tsr (unsigned int)
@@ -15271,7 +15276,7 @@  TM_buff_type TM_buff;
 
 while (1)
   @{
-    if (__TM_begin (TM_buff))
+    if (__TM_begin (TM_buff) == _HTM_TBEGIN_STARTED)
       @{
         /* Transaction State Initiated.  */
         if (is_locked (lock))
Index: gcc/testsuite/gcc.target/powerpc/htm-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/htm-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/htm-1.c	(working copy)
@@ -0,0 +1,52 @@ 
+/* { dg-do run { target { powerpc*-*-* && htm_hw } } } */
+/* { dg-require-effective-target powerpc_htm_ok } */
+/* { dg-options "-mhtm" } */
+
+/* Program to test PowerPC HTM instructions.  */
+
+#include <stdlib.h>
+#include <htmintrin.h>
+
+int
+main (void)
+{
+  long i;
+  unsigned long mask = 0;
+
+repeat:
+  if (__builtin_tbegin (0))
+    {
+      mask++;
+    }
+  else
+    abort();
+
+  if (mask == 1)
+    {
+      __builtin_tsuspend ();
+
+      if (_HTM_STATE (__builtin_tcheck ()) != _HTM_SUSPENDED)
+	abort ();
+
+      __builtin_tresume ();
+
+      if (_HTM_STATE (__builtin_tcheck ()) != _HTM_TRANSACTIONAL)
+	abort ();
+    }
+  else
+    mask++;
+
+  if (_HTM_STATE (__builtin_tendall ()) != _HTM_TRANSACTIONAL)
+    abort ();
+
+  if (mask == 1)
+    goto repeat;
+
+  if (_HTM_STATE (__builtin_tendall ()) != _HTM_NONTRANSACTIONAL)
+    abort ();
+
+  if (mask != 3)
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/powerpc/htm-builtin-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/htm-builtin-1.c	(revision 222127)
+++ gcc/testsuite/gcc.target/powerpc/htm-builtin-1.c	(working copy)
@@ -6,8 +6,8 @@ 
 /* { dg-final { scan-assembler-times "tbegin\\." 1 } } */
 /* { dg-final { scan-assembler-times "tend\\." 2 } } */
 /* { dg-final { scan-assembler-times "tabort\\." 2 } } */
-/* { dg-final { scan-assembler-times "tabortdc\\." 1 } } */
-/* { dg-final { scan-assembler-times "tabortdci\\." 1 } } */
+/* { dg-final { scan-assembler-times "tabortdc\\." 1 { target lp64 } } } */
+/* { dg-final { scan-assembler-times "tabortdci\\." 1 { target lp64 } } } */
 /* { dg-final { scan-assembler-times "tabortwc\\." 1 } } */
 /* { dg-final { scan-assembler-times "tabortwci\\." 2 } } */
 /* { dg-final { scan-assembler-times "tcheck" 1 } } */
@@ -25,12 +25,14 @@  void use_builtins (long *p, char code, l
   p[3] = __builtin_tabort (0);
   p[4] = __builtin_tabort (code);
 
+#ifdef __powerpc64__
   p[5] = __builtin_tabortdc (0xf, a[5], b[5]);
   p[6] = __builtin_tabortdci (0xf, a[6], 13);
+#endif
   p[7] = __builtin_tabortwc (0xf, a[7], b[7]);
   p[8] = __builtin_tabortwci (0xf, a[8], 13);
 
-  p[9] = __builtin_tcheck (5);
+  p[9] = __builtin_tcheck ();
   p[10] = __builtin_trechkpt ();
   p[11] = __builtin_treclaim (0);
   p[12] = __builtin_tresume ();
Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp	(revision 222127)
+++ gcc/testsuite/lib/target-supports.exp	(working copy)
@@ -3279,6 +3279,25 @@  proc check_effective_target_powerpc_htm_
     }
 }
 
+# Return 1 if the target supports executing HTM hardware instructions,
+# 0 otherwise.  Cache the result.
+
+proc check_htm_hw_available { } {
+    return [check_cached_effective_target htm_hw_available {
+	# For now, disable on Darwin
+	if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] || [istarget *-*-darwin*]} {
+	    expr 0
+	} else {
+	    check_runtime_nocache htm_hw_available {
+		int main()
+		{
+		  __builtin_ttest ();
+		  return 0;
+		}
+	    } "-mhtm"
+	}
+    }]
+}
 # Return 1 if this is a PowerPC target supporting -mcpu=cell.
 
 proc check_effective_target_powerpc_ppu_ok { } {
@@ -5278,6 +5297,7 @@  proc is-effective-target { arg } {
 	  "p8vector_hw"    { set selected [check_p8vector_hw_available] }
 	  "ppc_recip_hw"   { set selected [check_ppc_recip_hw_available] }
 	  "dfp_hw"         { set selected [check_dfp_hw_available] }
+	  "htm_hw"         { set selected [check_htm_hw_available] }
 	  "named_sections" { set selected [check_named_sections_available] }
 	  "gc_sections"    { set selected [check_gc_sections_available] }
 	  "cxa_atexit"     { set selected [check_cxa_atexit_available] }
@@ -5301,6 +5321,7 @@  proc is-effective-target-keyword { arg }
 	  "p8vector_hw"    { return 1 }
 	  "ppc_recip_hw"   { return 1 }
 	  "dfp_hw"         { return 1 }
+	  "htm_hw"         { return 1 }
 	  "named_sections" { return 1 }
 	  "gc_sections"    { return 1 }
 	  "cxa_atexit"     { return 1 }