Add __builtin_ppc_get_timebase to read the time base register on PowerPC. This is required for applications that measure time at high frequencies with high precision that can't afford a syscall.
[gcc] 2012-08-29 Tulio Magno Quites Machado Filho <tul...@linux.vnet.ibm.com> * config/rs6000/rs6000-builtin.def: Add __builtin_ppc_get_timebase. * config/rs6000/rs6000.c (rs6000_expand_noop_builtin): New function to expand an expression that calls a builtin without arguments. (rs6000_expand_builtin): Add __builtin_ppc_get_timebase. (rs6000_init_builtins): Likewise. * config/rs6000/rs6000.md: Likewise. [gcc/testsuite] 2012-08-29 Tulio Magno Quites Machado Filho <tul...@linux.vnet.ibm.com> * gcc.target/powerpc/ppc-get-timebase.c: New file. --- gcc/config/rs6000/rs6000-builtin.def | 3 ++ gcc/config/rs6000/rs6000.c | 31 +++++++++++++++++ gcc/config/rs6000/rs6000.md | 36 ++++++++++++++++++++ .../gcc.target/powerpc/ppc-get-timebase.c | 22 ++++++++++++ 4 files changed, 92 insertions(+), 0 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/ppc-get-timebase.c diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def index c8f8f86..75ad184 100644 --- a/gcc/config/rs6000/rs6000-builtin.def +++ b/gcc/config/rs6000/rs6000-builtin.def @@ -1429,6 +1429,9 @@ BU_SPECIAL_X (RS6000_BUILTIN_RSQRT, "__builtin_rsqrt", RS6000_BTM_FRSQRTE, BU_SPECIAL_X (RS6000_BUILTIN_RSQRTF, "__builtin_rsqrtf", RS6000_BTM_FRSQRTES, RS6000_BTC_FP) +BU_SPECIAL_X (RS6000_BUILTIN_GET_TB, "__builtin_ppc_get_timebase", + RS6000_BTM_POWERPC, RS6000_BTC_MISC) + /* Darwin CfString builtin. */ BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_ALWAYS, RS6000_BTC_MISC) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 6c58307..24e274d 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -9747,6 +9747,30 @@ rs6000_overloaded_builtin_p (enum rs6000_builtins fncode) return (rs6000_builtin_info[(int)fncode].attr & RS6000_BTC_OVERLOADED) != 0; } +/* Expand an expression EXP that calls a builtin without arguments. */ +static rtx +rs6000_expand_noop_builtin (enum insn_code icode, rtx target) +{ + rtx pat; + enum machine_mode tmode = insn_data[icode].operand[0].mode; + + if (icode == CODE_FOR_nothing) + /* Builtin not supported on this processor. */ + return 0; + + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + + pat = GEN_FCN (icode) (target); + if (! pat) + return 0; + emit_insn (pat); + + return target; +} + static rtx rs6000_expand_unop_builtin (enum insn_code icode, tree exp, rtx target) @@ -11336,6 +11360,9 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, ? CODE_FOR_bpermd_di : CODE_FOR_bpermd_si), exp, target); + case RS6000_BUILTIN_GET_TB: + return rs6000_expand_noop_builtin (CODE_FOR_get_timebase, target); + case ALTIVEC_BUILTIN_MASK_FOR_LOAD: case ALTIVEC_BUILTIN_MASK_FOR_STORE: { @@ -11620,6 +11647,10 @@ rs6000_init_builtins (void) POWER7_BUILTIN_BPERMD, "__builtin_bpermd"); def_builtin ("__builtin_bpermd", ftype, POWER7_BUILTIN_BPERMD); + ftype = build_function_type_list (unsigned_intDI_type_node, + NULL_TREE); + def_builtin ("__builtin_ppc_get_timebase", ftype, RS6000_BUILTIN_GET_TB); + #if TARGET_XCOFF /* AIX libm provides clog as __clog. */ if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE) diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index d5ffd81..09bdd80 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -136,6 +136,7 @@ UNSPECV_PROBE_STACK_RANGE ; probe range of stack addresses UNSPECV_EH_RR ; eh_reg_restore UNSPECV_ISYNC ; isync instruction + UNSPECV_GETTB ; get timebase built-in ]) @@ -14101,6 +14102,41 @@ "" "") +(define_expand "get_timebase" + [(use (match_operand:DI 0 "gpc_reg_operand" ""))] + "" + " +{ + if (TARGET_POWERPC64) + emit_insn (gen_get_timebase_ppc64 (operands[0])); + else if (TARGET_POWERPC) + emit_insn (gen_get_timebase_ppc32 (operands[0])); + else + FAIL; + DONE; +}") + +(define_insn "get_timebase_ppc32" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (unspec_volatile:DI [(const_int 0)] UNSPECV_GETTB)) + (clobber (match_scratch:SI 1 "=r"))] + "TARGET_POWERPC && !TARGET_POWERPC64" +{ + return "mftbu %0\;" + "mftb %L0\;" + "mftbu %1\;" + "cmpw %0,%1\;" + "bne- $-16"; +}) + +(define_insn "get_timebase_ppc64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (unspec_volatile:DI [(const_int 0)] UNSPECV_GETTB))] + "TARGET_POWERPC64" +{ + return "mfspr %0, 268"; +}) + (include "sync.md") diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-get-timebase.c b/gcc/testsuite/gcc.target/powerpc/ppc-get-timebase.c new file mode 100644 index 0000000..2f40974 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/ppc-get-timebase.c @@ -0,0 +1,22 @@ +/* { dg-do run { target { powerpc*-*-* } } } */ + +/* Test if __builtin_ppc_get_timebase() is compatible with the current + processor and if it's changing between reads. A read failure might indicate + a Power ISA or binutils change. */ + +#include <inttypes.h> + +int +main(void) +{ + uint64_t t1, t2, t3; + + t1 = __builtin_ppc_get_timebase (); + t2 = __builtin_ppc_get_timebase (); + t3 = __builtin_ppc_get_timebase (); + + if (t1 != t2 && t1 != t3 && t2 != t3) + return 0; + + return 1; +} -- 1.7.7.6