Hi Tulio,
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.
For things that do mftb with high frequency, maybe you should also add a
builtin that does just an mftb, i.e. returns a 32-bit result on 32-bit
implementations.
Please add documentation for the new builtin(s).
--- 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)
RS6000_BTM_POWERPC does not exist anymore. RS6000_BTM_ALWAYS?
+/* Expand an expression EXP that calls a builtin without
arguments. */
+static rtx
+rs6000_expand_noop_builtin (enum insn_code icode, rtx target)
"noop" gives the wrong idea, "zeroop" perhaps?
+(define_expand "get_timebase"
You should probably prefix this with powerpc_ or rs6000_ as well.
The existing code is not very consistent in this.
+ [(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;
+}")
TARGET_POWERPC is always true.
+(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";
+})
This only works for WORDS_BIG_ENDIAN.
You should say you clobber CR0 here I think; actually, allow any CRn
instead.
Does mftb work on all supported assemblers? The machine instruction
is phased out, but some assemblers translate it to mfspr.
+(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";
+})
POWER3 needs mftb.
--- /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;
+}
On some systems the timebase runs at a rather low frequency, say 20MHz.
This test will spuriously fail there. Waste a million CPU cycles before
reading TB the second time?
Segher