Commit 2561451d by Andreas Krebbel

[multiple changes]

2013-11-20  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
	    Dominik Vogt  <vogt@linux.vnet.ibm.com>

	* config/s390/s390.c (s390_canonicalize_comparison): Don't fold
	int comparisons with an out of range condition code.
	(s390_optimize_nonescaping_tx): Skip empty BBs.
	Generate the new tbegin RTX when removing the FPR clobbers (with
	two SETs).
	(s390_expand_tbegin): Fix the retry loop counter.  Copy CC to the
	result before doing the retry calculations.
	(s390_init_builtins): Make tbegin "returns_twice" and tabort
	"noreturn".
	* config/s390/s390.md (UNSPECV_TBEGIN_TDB): New constant used for
	the TDB setting part of an tbegin.
	("tbegin_1", "tbegin_nofloat_1"): Add a set for the TDB.
	("tx_assist"): Set unused argument to an immediate zero instead of
	loading zero into a GPR and pass it as argument.
	* config/s390/htmxlintrin.h (__TM_simple_begin, __TM_begin):
	Remove inline and related attributes.
	(__TM_nesting_depth, __TM_is_user_abort, __TM_is_named_user_abort)
	(__TM_is_illegal, __TM_is_footprint_exceeded)
	(__TM_is_nested_too_deep, __TM_is_conflict): Fix format value
	check.

2013-11-20  Dominik Vogt  <vogt@linux.vnet.ibm.com>

	* gcc.target/s390/htm-1.c: Rename to ...
	* gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c: ... this
	one.
	* gcc.target/s390/htm-xl-intrin-1.c: Rename to ...
	* gcc.target/s390/htm-builtins-compile-3.c: ... this one.
	* gcc.target/s390/htm-builtins-compile-2.c: New testcase.
	* gcc.target/s390/htm-builtins-1.c: New testcase.
	* gcc.target/s390/htm-builtins-2.c: New testcase.
	* gcc.target/s390/s390.exp: Add check for htm machine.

From-SVN: r205099
parent 5d1a0108
2013-11-20 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
Dominik Vogt <vogt@linux.vnet.ibm.com>
* config/s390/s390.c (s390_canonicalize_comparison): Don't fold
int comparisons with an out of range condition code.
(s390_optimize_nonescaping_tx): Skip empty BBs.
Generate the new tbegin RTX when removing the FPR clobbers (with
two SETs).
(s390_expand_tbegin): Fix the retry loop counter. Copy CC to the
result before doing the retry calculations.
(s390_init_builtins): Make tbegin "returns_twice" and tabort
"noreturn".
* config/s390/s390.md (UNSPECV_TBEGIN_TDB): New constant used for
the TDB setting part of an tbegin.
("tbegin_1", "tbegin_nofloat_1"): Add a set for the TDB.
("tx_assist"): Set unused argument to an immediate zero instead of
loading zero into a GPR and pass it as argument.
* config/s390/htmxlintrin.h (__TM_simple_begin, __TM_begin):
Remove inline and related attributes.
(__TM_nesting_depth, __TM_is_user_abort, __TM_is_named_user_abort)
(__TM_is_illegal, __TM_is_footprint_exceeded)
(__TM_is_nested_too_deep, __TM_is_conflict): Fix format value
check.
2013-11-20 Richard Biener <rguenther@suse.de>
PR lto/59035
......@@ -33,13 +33,20 @@ extern "C" {
the IBM XL compiler. For documentation please see the "z/OS XL
C/C++ Programming Guide" publicly available on the web. */
extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
/* FIXME: __TM_simple_begin and __TM_begin should be marked
__always_inline__ as well but this currently produces an error
since the tbegin builtins are "returns_twice" and setjmp_call_p
(calls.c) therefore identifies the functions as calling setjmp.
The tree inliner currently refuses to inline functions calling
setjmp. */
long
__TM_simple_begin ()
{
return __builtin_tbegin_nofloat (0);
}
extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
long
__TM_begin (void* const tdb)
{
return __builtin_tbegin_nofloat (tdb);
......@@ -78,7 +85,7 @@ __TM_nesting_depth (void* const tdb_ptr)
if (depth != 0)
return depth;
if (tdb->format == 0)
if (tdb->format != 1)
return 0;
return tdb->nesting_depth;
}
......@@ -90,7 +97,7 @@ __TM_is_user_abort (void* const tdb_ptr)
{
struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
if (tdb->format == 0)
if (tdb->format != 1)
return 0;
return !!(tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE);
......@@ -101,7 +108,7 @@ __TM_is_named_user_abort (void* const tdb_ptr, unsigned char* code)
{
struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
if (tdb->format == 0)
if (tdb->format != 1)
return 0;
if (tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE)
......@@ -117,7 +124,7 @@ __TM_is_illegal (void* const tdb_ptr)
{
struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
return (tdb->format == 0
return (tdb->format == 1
&& (tdb->abort_code == 4 /* unfiltered program interruption */
|| tdb->abort_code == 11 /* restricted instruction */));
}
......@@ -127,7 +134,7 @@ __TM_is_footprint_exceeded (void* const tdb_ptr)
{
struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
return (tdb->format == 0
return (tdb->format == 1
&& (tdb->abort_code == 7 /* fetch overflow */
|| tdb->abort_code == 8 /* store overflow */));
}
......@@ -137,7 +144,7 @@ __TM_is_nested_too_deep (void* const tdb_ptr)
{
struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
return tdb->format == 0 && tdb->abort_code == 13; /* depth exceeded */
return tdb->format == 1 && tdb->abort_code == 13; /* depth exceeded */
}
extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
......@@ -145,7 +152,7 @@ __TM_is_conflict (void* const tdb_ptr)
{
struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
return (tdb->format == 0
return (tdb->format == 1
&& (tdb->abort_code == 9 /* fetch conflict */
|| tdb->abort_code == 10 /* store conflict */));
}
......
......@@ -900,7 +900,8 @@ s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
{
/* For CCRAWmode put the required cc mask into the second
operand. */
if (GET_MODE (XVECEXP (*op0, 0, 0)) == CCRAWmode)
if (GET_MODE (XVECEXP (*op0, 0, 0)) == CCRAWmode
&& INTVAL (*op1) >= 0 && INTVAL (*op1) <= 3)
*op1 = gen_rtx_CONST_INT (VOIDmode, 1 << (3 - INTVAL (*op1)));
*op0 = XVECEXP (*op0, 0, 0);
*code = new_code;
......@@ -7973,6 +7974,9 @@ s390_optimize_nonescaping_tx (void)
{
bb = BASIC_BLOCK (bb_index);
if (!bb)
continue;
FOR_BB_INSNS (bb, insn)
{
rtx ite, cc, pat, target;
......@@ -8086,7 +8090,10 @@ s390_optimize_nonescaping_tx (void)
if (!result)
return;
PATTERN (tbegin_insn) = XVECEXP (PATTERN (tbegin_insn), 0, 0);
PATTERN (tbegin_insn) = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2,
XVECEXP (PATTERN (tbegin_insn), 0, 0),
XVECEXP (PATTERN (tbegin_insn), 0, 1)));
INSN_CODE (tbegin_insn) = -1;
df_insn_rescan (tbegin_insn);
......@@ -9798,6 +9805,7 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
const int CC3 = 1 << 0;
rtx abort_label = gen_label_rtx ();
rtx leave_label = gen_label_rtx ();
rtx retry_plus_two = gen_reg_rtx (SImode);
rtx retry_reg = gen_reg_rtx (SImode);
rtx retry_label = NULL_RTX;
rtx jump;
......@@ -9806,16 +9814,17 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
if (retry != NULL_RTX)
{
emit_move_insn (retry_reg, retry);
emit_insn (gen_addsi3 (retry_plus_two, retry_reg, const2_rtx));
emit_insn (gen_addsi3 (retry_reg, retry_reg, const1_rtx));
retry_label = gen_label_rtx ();
emit_label (retry_label);
}
if (clobber_fprs_p)
emit_insn (gen_tbegin_1 (tdb,
gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK)));
emit_insn (gen_tbegin_1 (gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK), tdb));
else
emit_insn (gen_tbegin_nofloat_1 (tdb,
gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK)));
emit_insn (gen_tbegin_nofloat_1 (gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK),
tdb));
jump = s390_emit_jump (abort_label,
gen_rtx_NE (VOIDmode,
......@@ -9836,6 +9845,10 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
/* Abort handler code. */
emit_label (abort_label);
emit_move_insn (dest, gen_rtx_UNSPEC (SImode,
gen_rtvec (1, gen_rtx_REG (CCRAWmode,
CC_REGNUM)),
UNSPEC_CC_TO_INT));
if (retry != NULL_RTX)
{
rtx count = gen_reg_rtx (SImode);
......@@ -9847,7 +9860,7 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
add_int_reg_note (jump, REG_BR_PROB, very_unlikely);
/* CC2 - transient failure. Perform retry with ppa. */
emit_move_insn (count, retry);
emit_move_insn (count, retry_plus_two);
emit_insn (gen_subsi3 (count, count, retry_reg));
emit_insn (gen_tx_assist (count));
jump = emit_jump_insn (gen_doloop_si64 (retry_label,
......@@ -9857,10 +9870,6 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
LABEL_NUSES (retry_label) = 1;
}
emit_move_insn (dest, gen_rtx_UNSPEC (SImode,
gen_rtvec (1, gen_rtx_REG (CCRAWmode,
CC_REGNUM)),
UNSPEC_CC_TO_INT));
emit_label (leave_label);
}
......@@ -9899,6 +9908,9 @@ static void
s390_init_builtins (void)
{
tree ftype, uint64_type;
tree returns_twice_attr = tree_cons (get_identifier ("returns_twice"),
NULL, NULL);
tree noreturn_attr = tree_cons (get_identifier ("noreturn"), NULL, NULL);
/* void foo (void) */
ftype = build_function_type_list (void_type_node, NULL_TREE);
......@@ -9909,17 +9921,17 @@ s390_init_builtins (void)
ftype = build_function_type_list (void_type_node, integer_type_node,
NULL_TREE);
add_builtin_function ("__builtin_tabort", ftype,
S390_BUILTIN_TABORT, BUILT_IN_MD, NULL, NULL_TREE);
S390_BUILTIN_TABORT, BUILT_IN_MD, NULL, noreturn_attr);
add_builtin_function ("__builtin_tx_assist", ftype,
S390_BUILTIN_TX_ASSIST, BUILT_IN_MD, NULL, NULL_TREE);
/* int foo (void *) */
ftype = build_function_type_list (integer_type_node, ptr_type_node, NULL_TREE);
add_builtin_function ("__builtin_tbegin", ftype, S390_BUILTIN_TBEGIN,
BUILT_IN_MD, NULL, NULL_TREE);
BUILT_IN_MD, NULL, returns_twice_attr);
add_builtin_function ("__builtin_tbegin_nofloat", ftype,
S390_BUILTIN_TBEGIN_NOFLOAT,
BUILT_IN_MD, NULL, NULL_TREE);
BUILT_IN_MD, NULL, returns_twice_attr);
/* int foo (void *, int) */
ftype = build_function_type_list (integer_type_node, ptr_type_node,
......@@ -9927,11 +9939,11 @@ s390_init_builtins (void)
add_builtin_function ("__builtin_tbegin_retry", ftype,
S390_BUILTIN_TBEGIN_RETRY,
BUILT_IN_MD,
NULL, NULL_TREE);
NULL, returns_twice_attr);
add_builtin_function ("__builtin_tbegin_retry_nofloat", ftype,
S390_BUILTIN_TBEGIN_RETRY_NOFLOAT,
BUILT_IN_MD,
NULL, NULL_TREE);
NULL, returns_twice_attr);
/* int foo (void) */
ftype = build_function_type_list (integer_type_node, NULL_TREE);
......
......@@ -155,6 +155,7 @@
; Transactional Execution support
UNSPECV_TBEGIN
UNSPECV_TBEGIN_TDB
UNSPECV_TBEGINC
UNSPECV_TEND
UNSPECV_TABORT
......@@ -9997,9 +9998,10 @@
(define_insn "tbegin_1"
[(set (reg:CCRAW CC_REGNUM)
(unspec_volatile:CCRAW [(match_operand:BLK 0 "memory_operand" "=Q")
(match_operand 1 "const_int_operand" " D")]
(unspec_volatile:CCRAW [(match_operand 0 "const_int_operand" "D")]
UNSPECV_TBEGIN))
(set (match_operand:BLK 1 "memory_operand" "=Q")
(unspec_volatile:BLK [(match_dup 0)] UNSPECV_TBEGIN_TDB))
(clobber (reg:DF 16))
(clobber (reg:DF 17))
(clobber (reg:DF 18))
......@@ -10018,18 +10020,19 @@
(clobber (reg:DF 31))]
; CONST_OK_FOR_CONSTRAINT_P does not work with D constraint since D is
; not supposed to be used for immediates (see genpreds.c).
"TARGET_HTM && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 0xffff"
"tbegin\t%0,%x1"
"TARGET_HTM && INTVAL (operands[0]) >= 0 && INTVAL (operands[0]) <= 0xffff"
"tbegin\t%1,%x0"
[(set_attr "op_type" "SIL")])
; Same as above but without the FPR clobbers
(define_insn "tbegin_nofloat_1"
[(set (reg:CCRAW CC_REGNUM)
(unspec_volatile:CCRAW [(match_operand:BLK 0 "memory_operand" "=Q")
(match_operand 1 "const_int_operand" " D")]
UNSPECV_TBEGIN))]
"TARGET_HTM && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 0xffff"
"tbegin\t%0,%x1"
(unspec_volatile:CCRAW [(match_operand 0 "const_int_operand" "D")]
UNSPECV_TBEGIN))
(set (match_operand:BLK 1 "memory_operand" "=Q")
(unspec_volatile:BLK [(match_dup 0)] UNSPECV_TBEGIN_TDB))]
"TARGET_HTM && INTVAL (operands[0]) >= 0 && INTVAL (operands[0]) <= 0xffff"
"tbegin\t%1,%x0"
[(set_attr "op_type" "SIL")])
......@@ -10113,15 +10116,12 @@
; Transaction perform processor assist
(define_expand "tx_assist"
[(set (match_dup 1) (const_int 0))
(unspec_volatile [(match_operand:SI 0 "register_operand" "")
(match_dup 1)
[(unspec_volatile [(match_operand:SI 0 "register_operand" "")
(reg:SI GPR0_REGNUM)
(const_int 1)]
UNSPECV_PPA)]
"TARGET_HTM"
{
operands[1] = gen_reg_rtx (SImode);
})
"")
(define_insn "*ppa"
[(unspec_volatile [(match_operand:SI 0 "register_operand" "d")
......@@ -10129,5 +10129,5 @@
(match_operand 2 "const_int_operand" "I")]
UNSPECV_PPA)]
"TARGET_HTM && INTVAL (operands[2]) < 16"
"ppa\t%0,%1,1"
"ppa\t%0,%1,%2"
[(set_attr "op_type" "RRF")])
2013-11-20 Dominik Vogt <vogt@linux.vnet.ibm.com>
* gcc.target/s390/htm-1.c: Rename to ...
* gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c: ... this
one.
* gcc.target/s390/htm-xl-intrin-1.c: Rename to ...
* gcc.target/s390/htm-builtins-compile-3.c: ... this one.
* gcc.target/s390/htm-builtins-compile-2.c: New testcase.
* gcc.target/s390/htm-builtins-1.c: New testcase.
* gcc.target/s390/htm-builtins-2.c: New testcase.
* gcc.target/s390/s390.exp: Add check for htm machine.
2013-11-19 Joshua J Cogliati <jrincayc@yahoo.com>
PR c/53001
......
/* This checks the availability of the low-level builtins introduced
for transactional execution. */
/* { dg-do compile } */
/* { dg-options "-O3 -march=zEC12 -mzarch" } */
#include <stdint.h>
#include <htmintrin.h>
int global = 0;
uint64_t g;
struct __htm_tdb global_tdb;
int
foo (struct __htm_tdb* tdb, int reg, int *mem, uint64_t *mem64)
{
int cc;
int n;
cc = __builtin_tbegin (0);
cc = __builtin_tbegin (tdb);
cc = __builtin_tbegin (&global_tdb);
cc = __builtin_tbegin_nofloat (0);
cc = __builtin_tbegin_nofloat (&global_tdb);
cc = __builtin_tbegin_retry (0, 42);
cc = __builtin_tbegin_retry (0, reg);
cc = __builtin_tbegin_retry (0, *mem);
cc = __builtin_tbegin_retry (0, global);
cc = __builtin_tbegin_retry (tdb, 42);
cc = __builtin_tbegin_retry (&global_tdb, 42);
cc = __builtin_tbegin_retry_nofloat (0, 42);
cc = __builtin_tbegin_retry_nofloat (0, reg);
cc = __builtin_tbegin_retry_nofloat (0, *mem);
cc = __builtin_tbegin_retry_nofloat (0, global);
cc = __builtin_tbegin_retry_nofloat (&global_tdb, 42);
__builtin_tbeginc ();
n = __builtin_tx_nesting_depth();
__builtin_non_tx_store(&g, 23);
__builtin_non_tx_store(mem64, 23);
__builtin_non_tx_store(&g, reg);
__builtin_non_tx_store(&g, *mem);
__builtin_non_tx_store(&g, global);
__builtin_tabort (42 + 255);
__builtin_tabort (reg);
/* { dg-final { scan-assembler-times "tabort\t255" 1 } } */
__builtin_tabort (reg + 255);
__builtin_tabort (*mem);
__builtin_tabort (global);
/* Here global + 255 gets reloaded into a reg. Better would be to
just reload global or *mem and get the +255 for free as address
arithmetic. */
__builtin_tabort (*mem + 255);
__builtin_tabort (global + 255);
__builtin_tend();
__builtin_tx_assist (23);
__builtin_tx_assist (reg);
__builtin_tx_assist (*mem);
__builtin_tx_assist (global);
}
/* Make sure the tdb NULL argument ends up as immediate value in the
instruction. */
/* { dg-final { scan-assembler-times "tbegin\t0," 10 } } */
/* Functional tests of the htm __builtin_... macros. */
/* { dg-do run } */
/* { dg-require-effective-target htm } */
/* { dg-options "-O3 -march=zEC12 -mzarch" } */
/* ---------------------------- included header files ---------------------- */
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <htmintrin.h>
/* ---------------------------- local definitions -------------------------- */
#define DEFAULT_MAX_REPETITIONS 5
#define DEFAULT_REQUIRED_QUORUM ((DEFAULT_MAX_REPETITIONS) - 1)
#define NUM_WARMUP_RUNS 10
/* ---------------------------- local macros ------------------------------- */
#define TEST_DF_REP(name) \
{ #name, name, DEFAULT_MAX_REPETITIONS, DEFAULT_REQUIRED_QUORUM }
#define TEST_NO_REP(name) { #name, name, 1, 1 }
/* ---------------------------- local types -------------------------------- */
typedef int (*test_func_t)(void);
typedef struct
{
const char *name;
test_func_t test_func;
int max_repetitions;
int required_quorum;
} test_table_entry_t;
/* ---------------------------- local variables ---------------------------- */
__attribute__ ((aligned(256))) static struct __htm_tdb local_tdb256;
static struct __htm_tdb local_tdb;
static int do_dump_tdb = 0;
/* ---------------------------- exported variables (globals) --------------- */
__attribute__ ((aligned(256))) struct
{
float float_1;
float float_2;
float float_3;
} global = { 1.0, 2.5, 0.0 };
__attribute__ ((aligned(256))) struct
{
volatile uint64_t c1;
volatile uint64_t c2;
volatile uint64_t c3;
} counters = { 0, 0, 0 };
/* ---------------------------- local helper functions --------------------- */
static void dump_tdb (struct __htm_tdb *tdb)
{
unsigned char *p;
int i;
int j;
if (do_dump_tdb == 0)
{
return;
}
p = (unsigned char *)tdb;
for (i = 0; i < 16; i++)
{
fprintf (stderr, "0x%02x ", i * 16);
for (j = 0; j < 16; j++)
{
fprintf (stderr, "%02x", (int)p[i * 16 + j]);
if (j < 15)
{
fprintf (stderr, " ");
}
if (j == 7)
{
fprintf (stderr, " ");
}
}
fprintf (stderr, "\n");
}
return;
}
/* ---------------------------- local test functions ----------------------- */
/* Check values of the constants defined in htmintrin.h. */
static int test_constants (void)
{
if (_HTM_TBEGIN_STARTED != 0)
{
return 100 * _HTM_TBEGIN_STARTED + 1;
}
if (_HTM_TBEGIN_INDETERMINATE != 1)
{
return 100 * _HTM_TBEGIN_INDETERMINATE + 2;
}
if (_HTM_TBEGIN_TRANSIENT != 2)
{
return 100 * _HTM_TBEGIN_TRANSIENT + 3;
}
if (_HTM_TBEGIN_PERSISTENT != 3)
{
return 100 * _HTM_TBEGIN_PERSISTENT + 4;
}
return 0;
}
static int test_tbegin_ntstg_tend (void)
{
int rc;
counters.c1 = 0;
counters.c2 = 0;
if ((rc = __builtin_tbegin ((void *)0)) == 0)
{
__builtin_non_tx_store ((uint64_t *)&counters.c1, 1);
counters.c2 = 2;
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 5;
}
if (counters.c1 != 1)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 2)
{
return 100 * counters.c2 + 3;
}
}
else
{
return 100 * rc + 4;
}
return 0;
}
static int test_tbegin_ntstg_tabort (void)
{
float f;
counters.c1 = 0;
counters.c2 = 0;
f = 0;
if (__builtin_tbegin ((void *)0) == 0)
{
__builtin_non_tx_store ((uint64_t *)&counters.c1, 1);
counters.c2 = 2;
f = 1;
__builtin_tabort (256);
return 1;
}
if (counters.c1 != 1)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 0)
{
return 100 * counters.c2 + 3;
}
if (f != 0)
{
return 100 * f + 4;
}
return 0;
}
static int test_tbegin_nofloat (void)
{
int rc;
counters.c1 = 0;
counters.c2 = 0;
if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
{
__builtin_non_tx_store ((uint64_t *)&counters.c1, 1);
counters.c2 = 2;
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 5;
}
if (counters.c1 != 1)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 2)
{
return 100 * counters.c2 + 3;
}
}
else
{
return 100 * rc + 4;
}
return 0;
}
static int test_tbegin_retry (void)
{
int rc;
counters.c1 = 0;
counters.c2 = 0;
counters.c3 = 0;
if ((rc = __builtin_tbegin_retry ((void *)0, 5)) == 0)
{
int do_abort;
do_abort = (counters.c1 == 0) ? 1 : 0;
__builtin_non_tx_store (
(uint64_t *)&counters.c1, counters.c1 + 1);
if (do_abort == 1)
{
__builtin_tabort (256);
}
counters.c2 = counters.c2 + 10;
__builtin_non_tx_store ((uint64_t *)&counters.c3, 3);
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 5;
}
if (counters.c1 != 2)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 10)
{
return 100 * counters.c2 + 3;
}
if (counters.c3 != 3)
{
return 100 * counters.c3 + 6;
}
}
else
{
return 100 * rc + 4;
}
return 0;
}
static int test_tbegin_retry_nofloat (void)
{
int rc;
counters.c1 = 0;
counters.c2 = 0;
counters.c3 = 0;
if ((rc = __builtin_tbegin_retry_nofloat ((void *)0, 5)) == 0)
{
int do_abort;
do_abort = (counters.c1 == 0) ? 1 : 0;
__builtin_non_tx_store (
(uint64_t *)&counters.c1, counters.c1 + 1);
if (do_abort == 1)
{
__builtin_tabort (256);
}
counters.c2 = counters.c2 + 10;
__builtin_non_tx_store ((uint64_t *)&counters.c3, 3);
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 5;
}
if (counters.c1 != 2)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 10)
{
return 100 * counters.c2 + 3;
}
if (counters.c3 != 3)
{
return 100 * counters.c3 + 6;
}
}
else
{
return 100 * rc + 4;
}
return 0;
}
static int test_tbegin_aborts (void)
{
float f;
int rc;
f = 77;
if ((rc = __builtin_tbegin ((void *)0)) == 0)
{
f = 88;
__builtin_tabort (256);
return 2;
}
else if (rc != 2)
{
return 3;
}
if (f != 77)
{
return 4;
}
f = 66;
if ((rc = __builtin_tbegin ((void *)0)) == 0)
{
f = 99;
__builtin_tabort (257);
return 5;
}
else if (rc != 3)
{
return 100 * rc + 6;
}
if (f != 66)
{
return 100 * f + 7;
}
if ((rc = __builtin_tbegin ((void *)0)) == 0)
{
global.float_3 = global.float_1 + global.float_2;
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 8;
}
}
else
{
return 100 * rc + 9;
}
if (global.float_3 != global.float_1 + global.float_2)
{
return 100 * rc + 10;
}
return 0;
}
static __attribute__((noinline)) void indirect_abort(int abort_code)
{
__builtin_tabort (abort_code);
return;
}
static int test_tbegin_indirect_aborts (void)
{
float f;
int rc;
f = 77;
if ((rc = __builtin_tbegin ((void *)0)) == 0)
{
f = 88;
indirect_abort(256);
return 2;
}
else if (rc != 2)
{
return 100 * rc + 3;
}
if (f != 77)
{
return 100 * rc + 4;
}
f = 66;
if ((rc = __builtin_tbegin ((void *)0)) == 0)
{
f = 99;
indirect_abort(257);
return 5;
}
else if (rc != 3)
{
return 100 * rc + 6;
}
if (f != 66)
{
return 100 * f + 7;
}
return 0;
}
static int test_tbegin_nofloat_aborts (void)
{
int rc;
if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
{
__builtin_tabort (256);
return 2;
}
if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
{
__builtin_tabort (257);
return 1005;
}
else if (rc != 3)
{
return 1000 * rc + 6;
}
return 0;
}
static int test_tbegin_nofloat_indirect_aborts (void)
{
int rc;
if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
{
indirect_abort (256);
return 2;
}
if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
{
indirect_abort (257);
return 1005;
}
else if (rc != 3)
{
return 1000 * rc + 6;
}
return 0;
}
static
int _test_tbegin_retry_aborts (int retries, uint64_t abort_code)
{
int rc;
counters.c1 = 0;
if ((rc = __builtin_tbegin_retry ((void *)0, retries)) == 0)
{
__builtin_non_tx_store ((uint64_t *)&counters.c1, counters.c1 + 1);
__builtin_tabort (abort_code);
return 2;
}
else
{
if ((abort_code & 1) == 0)
{
if (rc != 2)
{
return 100 * rc + 2003;
}
else if (counters.c1 != (uint64_t)retries + 1)
{
return 1000 * counters.c1 + 100 * retries + 4;
}
}
else
{
if (rc != 3)
{
return 100 * rc + 3005;
}
else if (counters.c1 != 1)
{
return 1000 * counters.c1 + 100 * retries + 6;
}
}
}
return 0;
}
static int test_tbegin_retry_aborts (void)
{
int rc;
int retries;
for (retries = 1; retries <= 3; retries++)
{
rc = _test_tbegin_retry_aborts (retries, 256);
if (rc != 0)
{
return 10000 + rc;
}
}
for (retries = 1; retries <= 3; retries++)
{
rc = _test_tbegin_retry_aborts (retries, 257);
if (rc != 0)
{
return 20000 + rc;
}
}
if ((rc = __builtin_tbegin_retry ((void *)0, 5)) == 0)
{
global.float_3 = global.float_1 + global.float_2;
rc = __builtin_tend ();
if (rc != 0)
{
return 30000 + 100 * rc + 6;
}
}
else
{
return 30000 + 100 * rc + 7;
}
return 0;
}
static int _test_tbegin_retry_nofloat_aborts (int retries, uint64_t abort_code)
{
int rc;
counters.c1 = 0;
if ((rc = __builtin_tbegin_retry_nofloat ((void *)0, retries)) == 0)
{
__builtin_non_tx_store ((uint64_t *)&counters.c1, counters.c1 + 1);
__builtin_tabort (abort_code);
return 2;
}
else
{
if ((abort_code & 1) == 0)
{
if (rc != 2)
{
return 100 * rc + 2003;
}
else if (counters.c1 != (uint64_t)retries + 1)
{
return 1000 * counters.c1 + 100 * retries + 4;
}
}
else
{
if (rc != 3)
{
return 100 * rc + 3005;
}
else if (counters.c1 != 1)
{
return 1000 * counters.c1 + 100 * retries + 6;
}
}
}
return 0;
}
static int test_tbegin_retry_nofloat_aborts (void)
{
int rc;
int retries;
for (retries = 1; retries <= 3; retries++)
{
rc = _test_tbegin_retry_nofloat_aborts (retries, 256);
if (rc != 0)
{
return 10 * retries + rc;
}
}
for (retries = 1; retries <= 3; retries++)
{
rc = _test_tbegin_retry_nofloat_aborts (retries, 257);
if (rc != 0)
{
return 10000 + 10 * retries + rc;
}
}
return 0;
}
static int test_tbegin_tdb (void)
{
int rc;
local_tdb.format = 0;
if ((rc = __builtin_tbegin (&local_tdb)) == 0)
{
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 1;
}
if (local_tdb.format != 0)
{
dump_tdb (&local_tdb);
return 100 * local_tdb.format + 2;
}
}
else
{
return 100 * rc + 3;
}
local_tdb.format = 0;
if ((rc = __builtin_tbegin (&local_tdb)) == 0)
{
__builtin_tabort (257);
return 4;
}
else
{
if (rc != 3)
{
return 100 * rc + 5;
}
if (local_tdb.format != 1)
{
dump_tdb (&local_tdb);
return 100 * local_tdb.format + 6;
}
}
local_tdb256.format = 0;
if ((rc = __builtin_tbegin (&local_tdb256)) == 0)
{
rc = __builtin_tend ();
if (rc != 0)
{
return 1100 * rc + 1;
}
if (local_tdb256.format != 0)
{
dump_tdb (&local_tdb256);
return 1100 * local_tdb256.format + 2;
}
}
else
{
return 1100 * rc + 3;
}
local_tdb256.format = 0;
if ((rc = __builtin_tbegin (&local_tdb256)) == 0)
{
__builtin_tabort (257);
return 2004;
}
else
{
if (rc != 3)
{
return 2100 * rc + 5;
}
if (local_tdb256.format != 1)
{
dump_tdb (&local_tdb256);
return 2100 * local_tdb256.format + 6;
}
}
return 0;
}
static int test_tbegin_nofloat_tdb (void)
{
int rc;
local_tdb.format = 0;
if ((rc = __builtin_tbegin_nofloat (&local_tdb)) == 0)
{
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 1;
}
if (local_tdb.format != 0)
{
dump_tdb (&local_tdb);
return 100 * local_tdb.format + 2;
}
}
else
{
return 3;
}
local_tdb.format = 0;
if ((rc = __builtin_tbegin_nofloat (&local_tdb)) == 0)
{
__builtin_tabort (257);
return 4;
}
else
{
if (rc != 3)
{
return 100 * rc + 5;
}
if (local_tdb.format != 1)
{
dump_tdb (&local_tdb);
return 100 * local_tdb.format + 6;
}
}
local_tdb256.format = 0;
if ((rc = __builtin_tbegin_nofloat (&local_tdb256)) == 0)
{
rc = __builtin_tend ();
if (rc != 0)
{
return 1100 * rc + 1;
}
if (local_tdb256.format != 0)
{
dump_tdb (&local_tdb256);
return 1100 * local_tdb256.format + 2;
}
}
else
{
return 1003;
}
local_tdb256.format = 0;
if ((rc = __builtin_tbegin_nofloat (&local_tdb256)) == 0)
{
__builtin_tabort (257);
return 2004;
}
else
{
if (rc != 3)
{
return 2100 * rc + 5;
}
if (local_tdb256.format != 1)
{
dump_tdb (&local_tdb256);
return 2100 * local_tdb256.format + 6;
}
}
return 0;
}
static int test_tbegin_retry_tdb (void)
{
int rc;
local_tdb256.format = 0;
if ((rc = __builtin_tbegin_retry (&local_tdb256, 2)) == 0)
{
rc = __builtin_tend ();
if (rc != 0)
{
return 1100 * rc + 1;
}
if (local_tdb256.format != 0)
{
dump_tdb (&local_tdb256);
return 1100 * local_tdb256.format + 2;
}
}
else
{
return 1003;
}
local_tdb256.format = 0;
if ((rc = __builtin_tbegin_retry (&local_tdb256, 2)) == 0)
{
__builtin_tabort (257);
return 2004;
}
else
{
if (rc != 3)
{
return 2100 * rc + 5;
}
if (local_tdb256.format != 1)
{
dump_tdb (&local_tdb256);
return 2100 * local_tdb256.format + 6;
}
}
return 0;
}
static int test_tbegin_retry_nofloat_tdb (void)
{
int rc;
local_tdb.format = 0;
if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb, 2)) == 0)
{
rc = __builtin_tend ();
if (rc != 0)
{
return 100 * rc + 1;
}
if (local_tdb.format != 0)
{
dump_tdb (&local_tdb);
return 100 * local_tdb.format + 2;
}
}
else
{
return 100 * rc + 3;
}
local_tdb.format = 0;
if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb, 2)) == 0)
{
__builtin_tabort (257);
return 4;
}
else
{
if (rc != 3)
{
return 100 * rc + 5;
}
if (local_tdb.format != 1)
{
dump_tdb (&local_tdb);
return 100 * local_tdb.format + 6;
}
}
local_tdb256.format = 0;
if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb256, 2)) == 0)
{
rc = __builtin_tend ();
if (rc != 0)
{
return 1100 * rc + 1;
}
if (local_tdb256.format != 0)
{
dump_tdb (&local_tdb256);
return 1100 * local_tdb256.format + 2;
}
}
else
{
return 1100 * rc + 3;
}
local_tdb256.format = 0;
if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb256, 2)) == 0)
{
__builtin_tabort (257);
return 2004;
}
else
{
if (rc != 3)
{
return 2100 * rc + 5;
}
if (local_tdb256.format != 1)
{
dump_tdb (&local_tdb256);
return 2100 * local_tdb256.format + 6;
}
}
return 0;
}
static int test_etnd (void)
{
int rc;
counters.c1 = 0;
counters.c2 = 0;
counters.c3 = 0;
if ((rc = __builtin_tbegin ((void *)0)) == 0)
{
counters.c1 = __builtin_tx_nesting_depth ();
if (__builtin_tbegin ((void *)0) == 0)
{
counters.c2 = __builtin_tx_nesting_depth ();
if (__builtin_tbegin ((void *)0) == 0)
{
counters.c3 = __builtin_tx_nesting_depth ();
__builtin_tend ();
}
__builtin_tend ();
}
__builtin_tend ();
}
else
{
return 100 * rc + 1;
}
if (counters.c1 != 1)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 2)
{
return 100 * counters.c2 + 3;
}
if (counters.c3 != 3)
{
return 100 * counters.c3 + 4;
}
return 0;
}
static int test_tbeginc (void)
{
int rc;
counters.c1 = 0;
__builtin_tbeginc ();
counters.c1 = 1;
rc = __builtin_tend ();
if (rc != 0)
{
return 10000 * rc + 1;
}
if (counters.c1 != 1)
{
return 100000 * counters.c1 + 3;
}
return 0;
}
/* ---------------------------- local testing framework functions ---------- */
static int run_one_test (const test_table_entry_t *test_entry)
{
int do_print_passes;
int succeeded;
int rc;
int i;
/* Warmup run to get all necessary data and instruction pages into the page
* tables. */
{
int run;
do_dump_tdb = 0;
for (run = 0; run < NUM_WARMUP_RUNS; run++)
{
test_entry->test_func ();
}
do_dump_tdb = 1;
}
do_print_passes = (
test_entry->required_quorum != 1 ||
test_entry->max_repetitions != 1);
printf ("RRR RUN %s\n", test_entry->name);
if (do_print_passes == 1)
{
printf (
" (requires %d successful out of %d runs)\n",
test_entry->required_quorum,
test_entry->max_repetitions);
}
succeeded = 0;
rc = 0;
for (rc = 0, i = 0; i < test_entry->max_repetitions; i++)
{
if (do_print_passes == 1)
{
if (i == 0)
{
printf (" ");
}
else
{
printf (",");
}
}
rc = test_entry->test_func ();
if (rc == 0)
{
if (do_print_passes == 1)
{
printf (" success");
}
succeeded++;
if (succeeded >= test_entry->required_quorum)
{
break;
}
}
else
{
printf (" failed (rc = %d)", rc);
}
}
if (do_print_passes == 1 || rc != 0)
{
printf ("\n");
}
if (succeeded >= test_entry->required_quorum)
{
printf ("+++ OK %s\n", test_entry->name);
return 0;
}
else
{
printf ("--- FAIL %s\n", test_entry->name);
return (rc != 0) ? rc : -1;
}
}
static int run_all_tests (const test_table_entry_t *test_table)
{
const test_table_entry_t *test;
int rc;
for (
rc = 0, test = &test_table[0];
test->test_func != NULL && rc == 0; test++)
{
rc = run_one_test (test);
}
return rc;
}
/* ---------------------------- interface functions ------------------------ */
int main (void)
{
const test_table_entry_t test_table[] = {
TEST_NO_REP (test_constants),
TEST_DF_REP (test_tbegin_ntstg_tend),
TEST_DF_REP (test_tbegin_ntstg_tabort),
TEST_DF_REP (test_tbegin_nofloat),
TEST_NO_REP (test_tbegin_retry),
TEST_NO_REP (test_tbegin_retry_nofloat),
TEST_DF_REP (test_tbegin_aborts),
TEST_DF_REP (test_tbegin_indirect_aborts),
TEST_DF_REP (test_tbegin_nofloat_aborts),
TEST_DF_REP (test_tbegin_nofloat_indirect_aborts),
TEST_NO_REP (test_tbegin_retry_aborts),
TEST_NO_REP (test_tbegin_retry_nofloat_aborts),
TEST_DF_REP (test_tbegin_tdb),
TEST_DF_REP (test_tbegin_nofloat_tdb),
TEST_NO_REP (test_tbegin_retry_tdb),
TEST_NO_REP (test_tbegin_retry_nofloat_tdb),
TEST_DF_REP (test_etnd),
TEST_DF_REP (test_tbeginc),
{ (void *)0, 0, 0 }
};
{
int rc;
rc = run_all_tests (test_table);
return rc;
}
}
/* Functional tests of the htm __TM_... macros. */
/* { dg-do run } */
/* { dg-require-effective-target htm } */
/* { dg-options "-O3 -march=zEC12 -mzarch" } */
/* ---------------------------- included header files ---------------------- */
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <htmxlintrin.h>
/* ---------------------------- local definitions -------------------------- */
#define DEFAULT_MAX_REPETITIONS 5
#define DEFAULT_REQUIRED_QUORUM ((DEFAULT_MAX_REPETITIONS) - 1)
#define DEFAULT_ABORT_ADDRESS (0x12345678u)
/* ---------------------------- local macros ------------------------------- */
#define TEST_DF_REP(name) \
{ #name, name, DEFAULT_MAX_REPETITIONS, DEFAULT_REQUIRED_QUORUM }
#define TEST_NO_REP(name) { #name, name, 1, 1 }
/* ---------------------------- local types -------------------------------- */
typedef int (*test_func_t)(void);
typedef struct
{
const char *name;
test_func_t test_func;
int max_repetitions;
int required_quorum;
} test_table_entry_t;
typedef enum
{
ABORT_T_SYSTEM = 0,
ABORT_T_USER = 1,
} abort_user_t;
typedef enum
{
ABORT_T_NONE = 0,
ABORT_T_ILLEGAL,
ABORT_T_FOOTPRINT_EXCEEDED,
ABORT_T_NESTED_TOO_DEEP,
ABORT_T_CONFLICT,
ABORT_T_INVALID_ABORT_CODE
} abort_t;
/* ---------------------------- local variables ---------------------------- */
__attribute__ ((aligned(256))) static struct __htm_tdb local_tdb256;
static struct __htm_tdb local_tdb;
static abort_t const abort_classes[] =
{
ABORT_T_INVALID_ABORT_CODE,
ABORT_T_NONE,
ABORT_T_NONE,
ABORT_T_NONE,
ABORT_T_ILLEGAL,
ABORT_T_NONE,
ABORT_T_NONE,
ABORT_T_FOOTPRINT_EXCEEDED,
ABORT_T_FOOTPRINT_EXCEEDED,
ABORT_T_CONFLICT,
ABORT_T_CONFLICT,
ABORT_T_ILLEGAL,
ABORT_T_NONE,
ABORT_T_NESTED_TOO_DEEP,
ABORT_T_NONE,
ABORT_T_NONE,
ABORT_T_NONE
};
static size_t num_abort_classes = sizeof(abort_classes) / sizeof(abort_t);
/* ---------------------------- exported variables (globals) --------------- */
int global_int = 0;
uint64_t global_u64 = 0;
float global_float_1 = 1.0;
float global_float_2 = 2.5;
float global_float_3 = 0.0;
__attribute__ ((aligned(256))) struct
{
volatile uint64_t c1;
volatile uint64_t c2;
volatile uint64_t c3;
} counters = { 0, 0, 0 };
/* ---------------------------- local helper functions --------------------- */
static void dump_tdb(struct __htm_tdb *tdb)
{
unsigned char *p;
int i;
int j;
p = (unsigned char *)tdb;
for (i = 0; i < 16; i++)
{
fprintf(stderr, "0x%02x ", i * 16);
for (j = 0; j < 16; j++)
{
fprintf(stderr, "%02x", (int)p[i * 16 + j]);
if (j < 15)
{
fprintf(stderr, " ");
}
if (j == 7)
{
fprintf(stderr, " ");
}
}
fprintf(stderr, "\n");
}
return;
}
static void make_fake_tdb(struct __htm_tdb *tdb)
{
memset(tdb, 0, sizeof(*tdb));
tdb->format = 1;
tdb->nesting_depth = 1;
tdb->atia = DEFAULT_ABORT_ADDRESS;
tdb->abort_code = 11;
return;
}
static int check_abort_code_in_tdb(struct __htm_tdb *tdb, uint64_t abort_code)
{
long expect_rc;
long rc;
if (abort_code != 0)
{
long addr;
addr = __TM_failure_address(&local_tdb);
if (addr != DEFAULT_ABORT_ADDRESS)
{
return 11;
}
}
{
long long tdb_abort_code;
tdb_abort_code = __TM_failure_code(tdb);
if ((uint64_t)tdb_abort_code != abort_code)
{
fprintf(
stderr, "tm_ac %" PRIu64 ", ac %" PRIu64
", tdb_ac %" PRIu64 "\n",
(uint64_t)tdb_abort_code, abort_code,
(uint64_t)tdb->abort_code);
return 10;
}
}
expect_rc = (abort_code >= 256) ? 1 : 0;
rc = __TM_is_user_abort(tdb);
if (rc != expect_rc)
{
fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
return 1;
}
{
unsigned char code;
code = 0xffu;
rc = __TM_is_named_user_abort(tdb, &code);
if (rc != expect_rc)
{
fprintf(
stderr, "rc %ld, expect_rc %ld\n", rc,
expect_rc);
return 2;
}
if (expect_rc == 1 && code != abort_code - 256)
{
return 3;
}
}
if (abort_code > (uint64_t)num_abort_classes)
{
abort_code = (uint64_t)num_abort_classes;
}
expect_rc = (abort_classes[abort_code] == ABORT_T_ILLEGAL) ? 1 : 0;
rc = __TM_is_illegal(tdb);
if (rc != expect_rc)
{
dump_tdb(tdb);
fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
return 4;
}
expect_rc =
(abort_classes[abort_code] == ABORT_T_FOOTPRINT_EXCEEDED) ?
1 : 0;
rc = __TM_is_footprint_exceeded(tdb);
if (rc != expect_rc)
{
dump_tdb(tdb);
fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
return 5;
}
expect_rc =
(abort_classes[abort_code] == ABORT_T_NESTED_TOO_DEEP) ? 1 : 0;
rc = __TM_is_nested_too_deep(tdb);
if (rc != expect_rc)
{
dump_tdb(tdb);
fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
return 6;
}
expect_rc = (abort_classes[abort_code] == ABORT_T_CONFLICT) ? 1 : 0;
rc = __TM_is_conflict(tdb);
if (rc != expect_rc)
{
dump_tdb(tdb);
fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
return 7;
}
return 0;
}
/* ---------------------------- local test functions ----------------------- */
/* Not a test; make sure that the involved global cachelines are reserved for
* writing. */
static int init_cache(void)
{
make_fake_tdb(&local_tdb);
make_fake_tdb(&local_tdb256);
global_int = 0;
global_u64 = 0;
global_float_1 = 1.0;
global_float_2 = 2.5;
global_float_3 = 0.0;
counters.c1 = 0;
counters.c2 = 0;
counters.c3 = 0;
return 0;
}
static int test_abort_classification(void)
{
int i;
make_fake_tdb(&local_tdb);
for (i = 0; i <= 256; i++)
{
int rc;
local_tdb.abort_code = (uint64_t)i;
rc = check_abort_code_in_tdb(&local_tdb, (uint64_t)i);
if (rc != 0)
{
return 100 * i + rc;
}
}
return 0;
}
static int test_cc_classification(void)
{
long rc;
rc = __TM_is_failure_persistent(0);
if (rc != 0)
{
return 1;
}
rc = __TM_is_failure_persistent(1);
if (rc != 0)
{
return 2;
}
rc = __TM_is_failure_persistent(2);
if (rc != 0)
{
return 3;
}
rc = __TM_is_failure_persistent(3);
if (rc != 1)
{
return 4;
}
return 0;
}
static int test_tbegin_ntstg_tend(void)
{
long rc;
counters.c1 = 0;
counters.c2 = 0;
if ((rc = __TM_simple_begin()) == 0)
{
__TM_non_transactional_store((uint64_t *)&counters.c1, 1);
counters.c2 = 2;
rc = __TM_end();
if (rc != 0)
{
return 100 * rc + 5;
}
if (counters.c1 != 1)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 2)
{
return 100 * counters.c2 + 3;
}
}
else
{
return 100 * rc + 4;
}
return 0;
}
static int test_tbegin_ntstg_tabort(void)
{
register float f;
counters.c1 = 0;
counters.c2 = 0;
f = 0;
if (__TM_simple_begin() == 0)
{
__TM_non_transactional_store((uint64_t *)&counters.c1, 1);
counters.c2 = 2;
f = 1;
__TM_named_abort(0);
return 1;
}
if (counters.c1 != 1)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 0)
{
return 100 * counters.c2 + 3;
}
if (f != 0)
{
return 100 * f + 4;
}
return 0;
}
static int test_tbegin_aborts(void)
{
float f;
long rc;
f = 77;
if ((rc = __TM_simple_begin()) == 0)
{
f = 88;
__TM_abort();
return 2;
}
else if (rc != 2)
{
return 3;
}
if (f != 77)
{
return 4;
}
f = 66;
if ((rc = __TM_simple_begin()) == 0)
{
f = 99;
__TM_named_abort(3);
return 5;
}
else if (rc != 3)
{
return 100 * rc + 6;
}
if (f != 66)
{
return 100 * f + 7;
}
if ((rc = __TM_simple_begin()) == 0)
{
global_float_3 = global_float_1 + global_float_2;
rc = __TM_end();
if (rc != 0)
{
return 100 * rc + 8;
}
}
else
{
return 100 * rc + 9;
}
if (global_float_3 != global_float_1 + global_float_2)
{
return 100 * rc + 10;
}
return 0;
}
static int test_tbegin_tdb(void)
{
long rc;
local_tdb.format = 0;
if ((rc = __TM_begin(&local_tdb)) == 0)
{
rc = __TM_end();
if (rc != 0)
{
return 100 * rc + 1;
}
if (local_tdb.format != 0)
{
dump_tdb(&local_tdb);
return 100 * local_tdb.format + 2;
}
}
else
{
return 100 * rc + 3;
}
local_tdb.format = 0;
if ((rc = __TM_begin(&local_tdb)) == 0)
{
__TM_named_abort(1);
return 4;
}
else
{
if (rc != 3)
{
return 100 * rc + 5;
}
if (local_tdb.format != 1)
{
dump_tdb(&local_tdb);
return 100 * local_tdb.format + 6;
}
}
local_tdb256.format = 0;
if ((rc = __TM_begin(&local_tdb256)) == 0)
{
rc = __TM_end();
if (rc != 0)
{
return 1100 * rc + 1;
}
if (local_tdb256.format != 0)
{
dump_tdb(&local_tdb256);
return 1100 * local_tdb256.format + 2;
}
}
else
{
return 1100 * rc + 3;
}
#if 1 /*!!!does not work*/
local_tdb256.format = 0;
if ((rc = __TM_begin(&local_tdb256)) == 0)
{
__TM_named_abort(1);
return 2004;
}
else
{
if (rc != 3)
{
return 2100 * rc + 5;
}
if (local_tdb256.format != 1)
{
dump_tdb(&local_tdb256);
return 2100 * local_tdb256.format + 6;
}
}
#endif
return 0;
}
static int test_etnd(void)
{
long rc;
{
long nd;
make_fake_tdb(&local_tdb);
local_tdb.nesting_depth = 0;
nd = __TM_nesting_depth(&local_tdb);
if (nd != 0)
{
return 1;
}
local_tdb.nesting_depth = 7;
nd = __TM_nesting_depth(&local_tdb);
if (nd != 7)
{
return 7;
}
local_tdb.format = 0;
nd = __TM_nesting_depth(&local_tdb);
if (nd != 0)
{
return 2;
}
}
counters.c1 = 0;
counters.c1 = 0;
counters.c2 = 0;
counters.c3 = 0;
if ((rc = __TM_simple_begin()) == 0)
{
counters.c1 = __TM_nesting_depth(0);
if (__TM_simple_begin() == 0)
{
counters.c2 = __TM_nesting_depth(0);
if (__TM_simple_begin() == 0)
{
counters.c3 = __TM_nesting_depth(0);
__TM_end();
}
__TM_end();
}
__TM_end();
}
else
{
return 100 * rc + 1;
}
if (counters.c1 != 1)
{
return 100 * counters.c1 + 2;
}
if (counters.c2 != 2)
{
return 100 * counters.c2 + 3;
}
if (counters.c3 != 3)
{
return 100 * counters.c3 + 4;
}
return 0;
}
/* ---------------------------- local testing framework functions ---------- */
static int run_one_test(const test_table_entry_t *test_entry)
{
int do_print_passes;
int succeeded;
int rc;
int i;
do_print_passes = (
test_entry->required_quorum != 1 ||
test_entry->max_repetitions != 1);
printf("RRR RUN %s\n", test_entry->name);
if (do_print_passes == 1)
{
printf(
" (requires %d successful out of %d runs)\n",
test_entry->required_quorum,
test_entry->max_repetitions);
}
succeeded = 0;
rc = 0;
for (rc = 0, i = 0; i < test_entry->max_repetitions; i++)
{
if (do_print_passes == 1)
{
if (i == 0)
{
printf(" ");
}
else
{
printf(",");
}
}
rc = test_entry->test_func();
if (rc == 0)
{
if (do_print_passes == 1)
{
printf(" success");
}
succeeded++;
if (succeeded >= test_entry->required_quorum)
{
break;
}
}
else
{
printf(" failed (rc = %d)", rc);
}
}
if (do_print_passes == 1 || rc != 0)
{
printf("\n");
}
if (succeeded >= test_entry->required_quorum)
{
printf("+++ OK %s\n", test_entry->name);
return 0;
}
else
{
printf("--- FAIL %s\n", test_entry->name);
return (rc != 0) ? rc : -1;
}
}
static int run_all_tests(const test_table_entry_t *test_table)
{
const test_table_entry_t *test;
int rc;
for (
rc = 0, test = &test_table[0];
test->test_func != NULL && rc == 0; test++)
{
rc = run_one_test(test);
}
return rc;
}
/* ---------------------------- interface functions ------------------------ */
int main(void)
{
const test_table_entry_t test_table[] = {
TEST_NO_REP(init_cache),
TEST_NO_REP(test_abort_classification),
TEST_NO_REP(test_cc_classification),
TEST_DF_REP(test_tbegin_ntstg_tend),
TEST_DF_REP(test_tbegin_ntstg_tabort),
TEST_DF_REP(test_tbegin_aborts),
TEST_DF_REP(test_tbegin_tdb),
TEST_DF_REP(test_etnd),
{ (void *)0, 0, 0 }
};
{
int rc;
rc = run_all_tests(test_table);
return rc;
}
}
/* This checks the availability of the low-level builtins introduced
for transactional execution. */
/* { dg-do compile } */
/* { dg-options "-O3 -march=zEC12 -mzarch" } */
#include <stdint.h>
#include <htmintrin.h>
int global = 0;
uint64_t g;
struct __htm_tdb global_tdb;
int
foo (struct __htm_tdb* tdb, int reg, int *mem, uint64_t *mem64)
{
int cc;
int n;
__builtin_tbegin ((void *)0);
__builtin_tbegin ((void *)-99999);
__builtin_tbegin ((void *)99999);
while (__builtin_tbegin ((void *)0) != 0)
{
}
cc = __builtin_tbegin ((void *)0x12345678);
cc = __builtin_tbegin (tdb);
cc = __builtin_tbegin (&global_tdb);
cc = __builtin_tbegin ((void *)(long long)(reg + 0x12345678));
cc = __builtin_tbegin ((void *)(long long)(reg));
__builtin_tbegin_nofloat ((void *)0);
__builtin_tbegin_nofloat ((void *)-99999);
__builtin_tbegin_nofloat ((void *)99999);
cc = __builtin_tbegin_nofloat ((void *)0x12345678);
cc = __builtin_tbegin_nofloat (tdb);
cc = __builtin_tbegin_nofloat (&global_tdb);
cc = __builtin_tbegin_nofloat ((void *)(long long)(reg + 0x12345678));
cc = __builtin_tbegin_nofloat ((void *)(long long)(reg));
__builtin_tbegin_retry ((void *)0, 0);
cc = __builtin_tbegin_retry ((void *)0, 1);
cc = __builtin_tbegin_retry ((void *)0, -1);
cc = __builtin_tbegin_retry ((void *)0, 42);
cc = __builtin_tbegin_retry ((void *)0, reg);
cc = __builtin_tbegin_retry ((void *)0, *mem);
cc = __builtin_tbegin_retry ((void *)0, global);
cc = __builtin_tbegin_retry (tdb, 42);
cc = __builtin_tbegin_retry (&global_tdb, 42);
cc = __builtin_tbegin_retry ((void *)0x12345678, global);
cc = __builtin_tbegin_retry (
(void *)(long long) (reg + 0x12345678), global + 1);
cc = __builtin_tbegin_retry (
(void *)(long long)(reg), global - 1);
__builtin_tbegin_retry_nofloat ((void *)0, 0);
cc = __builtin_tbegin_retry_nofloat ((void *)0, 1);
cc = __builtin_tbegin_retry_nofloat ((void *)0, -1);
cc = __builtin_tbegin_retry_nofloat ((void *)0, 42);
cc = __builtin_tbegin_retry_nofloat ((void *)0, reg);
cc = __builtin_tbegin_retry_nofloat ((void *)0, *mem);
cc = __builtin_tbegin_retry_nofloat ((void *)0, global);
cc = __builtin_tbegin_retry_nofloat (tdb, 42);
cc = __builtin_tbegin_retry_nofloat (&global_tdb, 42);
cc = __builtin_tbegin_retry_nofloat ((void *)0x12345678, global);
cc = __builtin_tbegin_retry_nofloat (
(void *)(long long) (reg + 0x12345678), global + 1);
cc = __builtin_tbegin_retry_nofloat (
(void *)(long long)(reg), global - 1);
__builtin_tbeginc ();
__builtin_tx_nesting_depth ();
n = __builtin_tx_nesting_depth ();
__builtin_non_tx_store (mem64, 0);
{
const uint64_t val_var = 0x1122334455667788;
__builtin_non_tx_store (mem64, val_var);
}
__builtin_non_tx_store (mem64, (uint64_t)reg);
__builtin_non_tx_store (mem64, g);
__builtin_non_tx_store ((uint64_t *)0, 0);
__builtin_non_tx_store ((uint64_t *)0x12345678, 0);
__builtin_non_tx_store (&g, 23);
__builtin_non_tx_store (&g, reg);
__builtin_non_tx_store (&g, *mem);
__builtin_non_tx_store (&g, global);
__builtin_tend();
__builtin_tx_assist (0);
__builtin_tx_assist (1);
__builtin_tx_assist (reg);
__builtin_tx_assist (*mem);
__builtin_tx_assist (global);
}
/* The taborts must go into separate function since they are
"noreturn". */
void
tabort1 ()
{
__builtin_tabort (256);
}
void
tabort2 (int reg)
{
__builtin_tabort (reg);
}
void
tabort3 (int reg)
{
/* { dg-final { scan-assembler-times "tabort\t255" 1 } } */
__builtin_tabort (reg + 255);
}
void
tabort4 (int *mem)
{
__builtin_tabort (*mem);
}
void
tabort5 ()
{
__builtin_tabort (global);
}
void
tabort6 (int *mem)
{
/* Here global + 255 gets reloaded into a reg. Better would be to
just reload global or *mem and get the +255 for free as address
arithmetic. */
__builtin_tabort (*mem + 255);
}
void
tabort7 ()
{
__builtin_tabort (global + 255);
}
void
tabort8 ()
{
__builtin_tabort (-1);
}
/* Make sure the tdb NULL argument ends up as immediate value in the
instruction. */
/* { dg-final { scan-assembler-times "tbegin\t0," 17 } } */
/* { dg-final { scan-assembler-times "tbegin\t" 41 } } */
/* Check number of occurences of certain instructions. */
/* { dg-final { scan-assembler-times "tbeginc\t" 1 } } */
/* { dg-final { scan-assembler-times "tabort\t" 8 } } */
/* { dg-final { scan-assembler "ppa\t" } } */
/* { dg-do compile } */
/* { dg-options "-O3 -march=zEC12 -mzarch" } */
void must_not_compile1 (void)
{
__builtin_tabort (0); /* { dg-error "Invalid transaction abort code:" } */
}
void must_not_compile2 (void)
{
__builtin_tabort (255); /* { dg-error "Invalid transaction abort code:" } */
}
......@@ -24,6 +24,19 @@ if ![istarget s390*-*-*] then {
# Load support procs.
load_lib gcc-dg.exp
# Return 1 if htm (etnd - extract nesting depth) instructions can be
# compiled.
proc check_effective_target_htm { } {
if { ![check_runtime s390_check_htm [subst {
int main (void)
{
unsigned int nd = 77;
asm (".insn rre,0xb2ec0000,%0,0" : "=d" (nd));
return nd;
}
}]] } { return 0 } else { return 1 }
}
# If a testcase doesn't have special options, use these.
global DEFAULT_CFLAGS
if ![info exists DEFAULT_CFLAGS] then {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment