<div dir="ltr"><div>PMUSERENR.EN seems to default to zero on Linux, no? At least my local Ubuntu A15 board test says so, and as expected I get SIGILL in user mode.</div><div><br></div><div style>Wouldn't it also useful to have an intrinsic to check for the value? "mrc p15, 0, %0, c9, c14, 0"'s bottom bit should do it. Or figure out which OS also supports PMUSERENR.EN=1 by default, with an override flag?</div>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, May 23, 2013 at 12:11 PM, Tim Northover <span dir="ltr"><<a href="mailto:t.p.northover@gmail.com" target="_blank">t.p.northover@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: tnorthover<br>
Date: Thu May 23 14:11:20 2013<br>
New Revision: 182603<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=182603&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=182603&view=rev</a><br>
Log:<br>
ARM: implement @llvm.readcyclecounter intrinsic<br>
<br>
This implements the @llvm.readcyclecounter intrinsic as the specific<br>
MRC instruction specified in the ARM manuals for CPUs with the Power<br>
Management extensions.<br>
<br>
Older CPUs had slightly different methods which may also have to be<br>
implemented eventually, but this should cover all v7 cases.<br>
<br>
rdar://problem/13939186<br>
<br>
Added:<br>
    llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll<br>
Modified:<br>
    llvm/trunk/docs/LangRef.rst<br>
    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp<br>
<br>
Modified: llvm/trunk/docs/LangRef.rst<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=182603&r1=182602&r2=182603&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=182603&r1=182602&r2=182603&view=diff</a><br>

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

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

==============================================================================<br>
--- llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll (added)<br>
+++ llvm/trunk/test/CodeGen/ARM/readcyclecounter.ll Thu May 23 14:11:20 2013<br>
@@ -0,0 +1,24 @@<br>
+; RUN: llc -mtriple=armv7-none-linux-gnueabi < %s | FileCheck %s<br>
+; RUN: llc -mtriple=thumbv7-none-linux-gnueabi < %s | FileCheck %s<br>
+; RUN: llc -mtriple=armv7-none-linux-gnueabi -mattr=-perfmon < %s | FileCheck %s --check-prefix=CHECK-NO-PERFMON<br>
+; RUN: llc -mtriple=armv6-none-linux-gnueabi < %s | FileCheck %s --check-prefix=CHECK-NO-PERFMON<br>
+<br>
+; The performance monitor we're looking for is an ARMv7 extension. It should be<br>
+; possible to disable it, but realistically present on at least every v7-A<br>
+; processor (but not on v6, at least by default).<br>
+<br>
+declare i64 @llvm.readcyclecounter()<br>
+<br>
+define i64 @get_count() {<br>
+  %val = call i64 @llvm.readcyclecounter()<br>
+  ret i64 %val<br>
+<br>
+  ; As usual, exact registers only sort of matter but the cycle-count had better<br>
+  ; end up in r0 in the end.<br>
+<br>
+; CHECK: mrc p15, #0, r0, c9, c13, #0<br>
+; CHECK: {{movs?}} r1, #0<br>
+<br>
+; CHECK-NO-PERFMON: {{movs?}} r0, #0<br>
+; CHECK-NO-PERFMON: {{movs?}} r1, #0<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>