[llvm] r182603 - ARM: implement @llvm.readcyclecounter intrinsic

Tim Northover t.p.northover at gmail.com
Thu May 23 12:11:21 PDT 2013


Author: tnorthover
Date: Thu May 23 14:11:20 2013
New Revision: 182603

URL: http://llvm.org/viewvc/llvm-project?rev=182603&view=rev
Log:
ARM: implement @llvm.readcyclecounter intrinsic

This implements the @llvm.readcyclecounter intrinsic as the specific
MRC instruction specified in the ARM manuals for CPUs with the Power
Management extensions.

Older CPUs had slightly different methods which may also have to be
implemented eventually, but this should cover all v7 cases.

rdar://problem/13939186

Added:
    llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=182603&r1=182602&r2=182603&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Thu May 23 14:11:20 2013
@@ -6663,6 +6663,9 @@ memory. Implementations are allowed to e
 specific value or a system wide value. On backends without support, this
 is lowered to a constant 0.
 
+Note that runtime support may be conditional on the privilege-level code is
+running at and the host platform.
+
 Standard C Library Intrinsics
 -----------------------------
 

Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=182603&r1=182602&r2=182603&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Thu May 23 14:11:20 2013
@@ -681,6 +681,8 @@ ARMTargetLowering::ARMTargetLowering(Tar
   setOperationAction(ISD::CTTZ_ZERO_UNDEF  , MVT::i32  , Expand);
   setOperationAction(ISD::CTLZ_ZERO_UNDEF  , MVT::i32  , Expand);
 
+  setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom);
+
   // Only ARMv6 has BSWAP.
   if (!Subtarget->hasV6Ops())
     setOperationAction(ISD::BSWAP, MVT::i32, Expand);
@@ -5702,7 +5704,6 @@ static SDValue LowerAtomicLoadStore(SDVa
   return SDValue();
 }
 
-
 static void
 ReplaceATOMIC_OP_64(SDNode *Node, SmallVectorImpl<SDValue>& Results,
                     SelectionDAG &DAG, unsigned NewOp) {
@@ -5736,6 +5737,44 @@ ReplaceATOMIC_OP_64(SDNode *Node, SmallV
   Results.push_back(Result.getValue(2));
 }
 
+static void ReplaceREADCYCLECOUNTER(SDNode *N,
+                                    SmallVectorImpl<SDValue> &Results,
+                                    SelectionDAG &DAG,
+                                    const ARMSubtarget *Subtarget) {
+  DebugLoc DL = N->getDebugLoc();
+  SDValue Cycles32, OutChain;
+
+  if (Subtarget->hasPerfMon()) {
+    // Under Power Management extensions, the cycle-count is:
+    //    mrc p15, #0, <Rt>, c9, c13, #0
+    SDValue Ops[] = { N->getOperand(0), // Chain
+                      DAG.getConstant(Intrinsic::arm_mrc, MVT::i32),
+                      DAG.getConstant(15, MVT::i32),
+                      DAG.getConstant(0, MVT::i32),
+                      DAG.getConstant(9, MVT::i32),
+                      DAG.getConstant(13, MVT::i32),
+                      DAG.getConstant(0, MVT::i32)
+    };
+
+    Cycles32 = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL,
+                           DAG.getVTList(MVT::i32, MVT::Other), &Ops[0],
+                           array_lengthof(Ops));
+    OutChain = Cycles32.getValue(1);
+  } else {
+    // Intrinsic is defined to return 0 on unsupported platforms. Technically
+    // there are older ARM CPUs that have implementation-specific ways of
+    // obtaining this information (FIXME!).
+    Cycles32 = DAG.getConstant(0, MVT::i32);
+    OutChain = DAG.getEntryNode();
+  }
+
+
+  SDValue Cycles64 = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
+                                 Cycles32, DAG.getConstant(0, MVT::i32));
+  Results.push_back(Cycles64);
+  Results.push_back(OutChain);
+}
+
 SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   switch (Op.getOpcode()) {
   default: llvm_unreachable("Don't know how to custom lower this!");
@@ -5813,6 +5852,9 @@ void ARMTargetLowering::ReplaceNodeResul
   case ISD::SRA:
     Res = Expand64BitShift(N, DAG, Subtarget);
     break;
+  case ISD::READCYCLECOUNTER:
+    ReplaceREADCYCLECOUNTER(N, Results, DAG, Subtarget);
+    return;
   case ISD::ATOMIC_LOAD_ADD:
     ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMADD64_DAG);
     return;

Added: llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll?rev=182603&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll (added)
+++ llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll Thu May 23 14:11:20 2013
@@ -0,0 +1,24 @@
+; RUN: llc -mtriple=armv7-none-linux-gnueabi < %s | FileCheck %s
+; RUN: llc -mtriple=thumbv7-none-linux-gnueabi < %s | FileCheck %s
+; RUN: llc -mtriple=armv7-none-linux-gnueabi -mattr=-perfmon < %s | FileCheck %s --check-prefix=CHECK-NO-PERFMON
+; RUN: llc -mtriple=armv6-none-linux-gnueabi < %s | FileCheck %s --check-prefix=CHECK-NO-PERFMON
+
+; The performance monitor we're looking for is an ARMv7 extension. It should be
+; possible to disable it, but realistically present on at least every v7-A
+; processor (but not on v6, at least by default).
+
+declare i64 @llvm.readcyclecounter()
+
+define i64 @get_count() {
+  %val = call i64 @llvm.readcyclecounter()
+  ret i64 %val
+
+  ; As usual, exact registers only sort of matter but the cycle-count had better
+  ; end up in r0 in the end.
+
+; CHECK: mrc p15, #0, r0, c9, c13, #0
+; CHECK: {{movs?}} r1, #0
+
+; CHECK-NO-PERFMON: {{movs?}} r0, #0
+; CHECK-NO-PERFMON: {{movs?}} r1, #0
+}





More information about the llvm-commits mailing list