[clang] [llvm] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and buiiltin (PR #81331)

2024-02-09 Thread Joseph Huber via cfe-commits

https://github.com/jhuber6 updated 
https://github.com/llvm/llvm-project/pull/81331

>From 6b85d8edfe35d3952fc4e67e249175d9f8f734c6 Mon Sep 17 00:00:00 2001
From: Joseph Huber 
Date: Fri, 9 Feb 2024 16:13:42 -0600
Subject: [PATCH] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and
 buiiltin

Summary:
This patch adds a new intrinsic and builtin function mirroring the
existing `__builtin_readcyclecounter`. The difference is that this
implementation targets a separate counter that some targets have which
returns a fixed frequency clock that can be used to determine elapsed
time, this is different compared to the cycle counter which often has
variable frequency. This is currently only valid for the NVPTX and
AMDGPU targets.
---
 clang/docs/LanguageExtensions.rst | 31 +++
 clang/include/clang/Basic/Builtins.td |  6 
 clang/lib/CodeGen/CGBuiltin.cpp   |  4 +++
 llvm/include/llvm/CodeGen/ISDOpcodes.h|  6 
 llvm/include/llvm/IR/Intrinsics.td|  2 ++
 llvm/include/llvm/Support/TargetOpcodes.def   |  3 ++
 llvm/include/llvm/Target/GenericOpcodes.td|  6 
 .../Target/GlobalISel/SelectionDAGCompat.td   |  1 +
 .../include/llvm/Target/TargetSelectionDAG.td |  3 ++
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  |  2 ++
 llvm/lib/CodeGen/IntrinsicLowering.cpp|  6 
 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp |  6 ++--
 .../SelectionDAG/LegalizeIntegerTypes.cpp |  7 +++--
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h |  2 +-
 .../SelectionDAG/SelectionDAGBuilder.cpp  |  8 +
 .../SelectionDAG/SelectionDAGDumper.cpp   |  1 +
 llvm/lib/CodeGen/TargetLoweringBase.cpp   |  3 ++
 .../lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp |  2 ++
 .../Target/AMDGPU/AMDGPURegisterBankInfo.cpp  |  1 +
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp |  4 +++
 llvm/lib/Target/AMDGPU/SMInstructions.td  | 14 +
 llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp   |  3 ++
 llvm/lib/Target/NVPTX/NVPTXInstrInfo.td   |  1 -
 llvm/lib/Target/NVPTX/NVPTXIntrinsics.td  |  4 +++
 llvm/test/CodeGen/AMDGPU/readfixedtimer.ll| 24 ++
 llvm/test/CodeGen/NVPTX/intrinsics.ll | 12 +++
 26 files changed, 155 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/readfixedtimer.ll

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index e91156837290f7..a30fc15183bfd4 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -2764,6 +2764,37 @@ Query for this feature with 
``__has_builtin(__builtin_readcyclecounter)``. Note
 that even if present, its use may depend on run-time privilege or other OS
 controlled state.
 
+``__builtin_readfixedtimer``
+--
+
+``__builtin_readfixedtimer`` is used to access the fixed frequency counter 
+register (or a similar steady-rate clock) on those targets that support it.
+The function is similar to ``__builtin_readcyclecounter`` above except that 
the 
+frequency is fixed, making it suitable for measuring elapsed time.
+
+**Syntax**:
+
+.. code-block:: c++
+
+  __builtin_readfixedtimer()
+
+**Example of Use**:
+
+.. code-block:: c++
+
+  unsigned long long t0 = __builtin_readfixedtimer();
+  do_something();
+  unsigned long long t1 = __builtin_readfixedtimer();
+  unsigned long long secs_to_do_something = (t1 - t0) / tick_rate;
+
+**Description**:
+
+The ``__builtin_readfixedtimer()`` builtin returns the frequency counter value.
+When not supported by the target, the return value is always zero. This 
builtin 
+takes no arguments and produces an unsigned long long result.
+
+Query for this feature with ``__has_builtin(__builtin_readfixedtimer)``.
+
 ``__builtin_dump_struct``
 -
 
diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 31a2bdeb2d3e5e..3bc043b35e187b 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1110,6 +1110,12 @@ def ReadCycleCounter : Builtin {
   let Prototype = "unsigned long long int()";
 }
 
+def ReadFixedTimer : Builtin {
+  let Spellings = ["__builtin_readfixedtimer"];
+  let Attributes = [NoThrow];
+  let Prototype = "unsigned long long int()";
+}
+
 def Trap : Builtin {
   let Spellings = ["__builtin_trap"];
   let Attributes = [NoThrow, NoReturn];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a7a410dab1a018..8da8bbc56758d5 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3443,6 +3443,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
 Function *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
 return RValue::get(Builder.CreateCall(F));
   }
+  case Builtin::BI__builtin_readfixedtimer: {
+Function *F = CGM.getIntrinsic(Intrinsic::readfixedtimer);
+return 

[clang] [llvm] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and buiiltin (PR #81331)

2024-02-09 Thread Joseph Huber via cfe-commits

https://github.com/jhuber6 edited 
https://github.com/llvm/llvm-project/pull/81331
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and buiiltin (PR #81331)

2024-02-09 Thread Joseph Huber via cfe-commits

https://github.com/jhuber6 updated 
https://github.com/llvm/llvm-project/pull/81331

>From 4008cb94b59ea1be8aa6936c4dc6b5b7ad4e749a Mon Sep 17 00:00:00 2001
From: Joseph Huber 
Date: Fri, 9 Feb 2024 16:13:42 -0600
Subject: [PATCH] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and
 buiiltin

Summary:
This patch adds a new intrinsic and builtin function mirroring the
existing `__builtin_readcyclecounter`. The difference is that this
implementation targets a separate counter that some targets have which
returns a fixed frequency clock that can be used to determine elapsed
time, this is different compared to the cycle counter which often has
variable frequency. This is currently only valid for the NVPTX and
AMDGPU targets.
---
 clang/include/clang/Basic/Builtins.td  |  6 ++
 clang/lib/CodeGen/CGBuiltin.cpp|  4 
 llvm/include/llvm/CodeGen/ISDOpcodes.h |  6 ++
 llvm/include/llvm/IR/Intrinsics.td |  2 ++
 llvm/include/llvm/Support/TargetOpcodes.def|  3 +++
 llvm/include/llvm/Target/GenericOpcodes.td |  6 ++
 .../llvm/Target/GlobalISel/SelectionDAGCompat.td   |  1 +
 llvm/include/llvm/Target/TargetSelectionDAG.td |  3 +++
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp   |  2 ++
 llvm/lib/CodeGen/IntrinsicLowering.cpp |  6 ++
 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp  |  6 --
 .../CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp  | 11 ---
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h  |  2 +-
 .../CodeGen/SelectionDAG/SelectionDAGBuilder.cpp   |  8 
 .../CodeGen/SelectionDAG/SelectionDAGDumper.cpp|  2 ++
 llvm/lib/CodeGen/TargetLoweringBase.cpp|  3 +++
 llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp |  2 ++
 llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp  |  1 +
 llvm/lib/Target/AMDGPU/SMInstructions.td   | 14 ++
 19 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 31a2bdeb2d3e5e..3bc043b35e187b 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1110,6 +1110,12 @@ def ReadCycleCounter : Builtin {
   let Prototype = "unsigned long long int()";
 }
 
+def ReadFixedTimer : Builtin {
+  let Spellings = ["__builtin_readfixedtimer"];
+  let Attributes = [NoThrow];
+  let Prototype = "unsigned long long int()";
+}
+
 def Trap : Builtin {
   let Spellings = ["__builtin_trap"];
   let Attributes = [NoThrow, NoReturn];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a7a410dab1a018..8da8bbc56758d5 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3443,6 +3443,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
 Function *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
 return RValue::get(Builder.CreateCall(F));
   }
+  case Builtin::BI__builtin_readfixedtimer: {
+Function *F = CGM.getIntrinsic(Intrinsic::readfixedtimer);
+return RValue::get(Builder.CreateCall(F));
+  }
   case Builtin::BI__builtin___clear_cache: {
 Value *Begin = EmitScalarExpr(E->getArg(0));
 Value *End = EmitScalarExpr(E->getArg(1));
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h 
b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 349d1286c8dc4f..882e80c521e897 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1179,6 +1179,12 @@ enum NodeType {
   /// counter-like register (or other high accuracy low latency clock source).
   READCYCLECOUNTER,
 
+  /// READFIXEDTIMER - This corresponds to the readfixedcounter intrinsic.
+  /// It has the same semantics as the READCYCLECOUNTER implementation except
+  /// that the result is the content of the architecture-specific fixed
+  /// frequency counter suitable for measuring elapsed time.
+  READFIXEDTIMER,
+
   /// HANDLENODE node - Used as a handle for various purposes.
   HANDLENODE,
 
diff --git a/llvm/include/llvm/IR/Intrinsics.td 
b/llvm/include/llvm/IR/Intrinsics.td
index 3c19c7b063652c..4d7c57944f3778 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -870,6 +870,8 @@ def int_pcmarker  : DefaultAttrsIntrinsic<[], 
[llvm_i32_ty]>;
 
 def int_readcyclecounter : DefaultAttrsIntrinsic<[llvm_i64_ty]>;
 
+def int_readfixedtimer : DefaultAttrsIntrinsic<[llvm_i64_ty]>;
+
 // The assume intrinsic is marked InaccessibleMemOnly so that proper control
 // dependencies will be maintained.
 def int_assume : DefaultAttrsIntrinsic<
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def 
b/llvm/include/llvm/Support/TargetOpcodes.def
index abb237083d254e..29c6b6488ebb72 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -352,6 +352,9 @@ HANDLE_TARGET_OPCODE(G_INTRINSIC_ROUNDEVEN)
 /// INTRINSIC 

[clang] [llvm] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and buiiltin (PR #81331)

2024-02-09 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff 967374123bd6eee23db9a57fcac7324e420648c5 
f6d905fe46c18b8076bb9af4ccb6583ed60d5ca6 -- clang/lib/CodeGen/CGBuiltin.cpp 
llvm/include/llvm/CodeGen/ISDOpcodes.h 
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp 
llvm/lib/CodeGen/IntrinsicLowering.cpp 
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp 
llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 
llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h 
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp 
llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp 
llvm/lib/CodeGen/TargetLoweringBase.cpp 
llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp 
llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
``





View the diff from clang-format here.


``diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 
b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
index cd0e910752..90b1d87c17 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -2648,8 +2648,12 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, 
unsigned ResNo) {
   case ISD::LLRINT:  ExpandIntRes_XROUND_XRINT(N, Lo, Hi); break;
   case ISD::LOAD:ExpandIntRes_LOAD(cast(N), Lo, Hi); break;
   case ISD::MUL: ExpandIntRes_MUL(N, Lo, Hi); break;
-  case ISD::READCYCLECOUNTER: ExpandIntRes_READCOUNTER(N, Lo, Hi); break;
-  case ISD::READFIXEDTIMER:   ExpandIntRes_READCOUNTER(N, Lo, Hi); break;
+  case ISD::READCYCLECOUNTER:
+ExpandIntRes_READCOUNTER(N, Lo, Hi);
+break;
+  case ISD::READFIXEDTIMER:
+ExpandIntRes_READCOUNTER(N, Lo, Hi);
+break;
   case ISD::SDIV:ExpandIntRes_SDIV(N, Lo, Hi); break;
   case ISD::SIGN_EXTEND: ExpandIntRes_SIGN_EXTEND(N, Lo, Hi); break;
   case ISD::SIGN_EXTEND_INREG: ExpandIntRes_SIGN_EXTEND_INREG(N, Lo, Hi); 
break;
@@ -4028,7 +4032,7 @@ void DAGTypeLegalizer::ExpandIntRes_MUL(SDNode *N,
 }
 
 void DAGTypeLegalizer::ExpandIntRes_READCOUNTER(SDNode *N, SDValue ,
- SDValue ) {
+SDValue ) {
   SDLoc DL(N);
   EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
   SDVTList VTs = DAG.getVTList(NVT, NVT, MVT::Other);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h 
b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 9114987162..2b09703084 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -439,7 +439,7 @@ private:
   void ExpandIntRes_CTPOP (SDNode *N, SDValue , SDValue );
   void ExpandIntRes_CTTZ  (SDNode *N, SDValue , SDValue );
   void ExpandIntRes_LOAD  (LoadSDNode *N, SDValue , SDValue );
-  void ExpandIntRes_READCOUNTER   (SDNode *N, SDValue , SDValue );
+  void ExpandIntRes_READCOUNTER(SDNode *N, SDValue , SDValue );
   void ExpandIntRes_SIGN_EXTEND   (SDNode *N, SDValue , SDValue );
   void ExpandIntRes_SIGN_EXTEND_INREG (SDNode *N, SDValue , SDValue );
   void ExpandIntRes_TRUNCATE  (SDNode *N, SDValue , SDValue );
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp 
b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 0d308fa8ad..ebd49f1306 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -104,7 +104,8 @@ std::string SDNode::getOperationName(const SelectionDAG *G) 
const {
   case ISD::ATOMIC_STORE:   return "AtomicStore";
   case ISD::PCMARKER:   return "PCMarker";
   case ISD::READCYCLECOUNTER:   return "ReadCycleCounter";
-  case ISD::READFIXEDTIMER: return "ReadFixedTimer";
+  case ISD::READFIXEDTIMER:
+return "ReadFixedTimer";
   case ISD::SRCVALUE:   return "SrcValue";
   case ISD::MDNODE_SDNODE:  return "MDNode";
   case ISD::EntryToken: return "EntryToken";
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp 
b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
index c9ea359d79..63f843ea94 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
@@ -1957,8 +1957,7 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const 
GCNSubtarget _,
   getActionDefinitionsBuilder(G_READCYCLECOUNTER)
 .legalFor({S64});
 
-  getActionDefinitionsBuilder(G_READFIXEDTIMER)
-.legalFor({S64});
+  getActionDefinitionsBuilder(G_READFIXEDTIMER).legalFor({S64});
 
   getActionDefinitionsBuilder(G_FENCE)
 .alwaysLegal();

``




https://github.com/llvm/llvm-project/pull/81331
___
cfe-commits mailing list
cfe-commits@lists.llvm.org

[clang] [llvm] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and buiiltin (PR #81331)

2024-02-09 Thread Joseph Huber via cfe-commits

jhuber6 wrote:

This is a draft, I'm trying to get this to map to either `s_memtime` or 
`s_sendmsg_rtn(0x83)` depending on the target for AMDGPU. Currently, it will 
recognize the new intrinsic but just lower it to `i64 0`. I'm not overly 
familiar with the backend, so any suggestions would be greatly appreciated.

https://github.com/llvm/llvm-project/pull/81331
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and buiiltin (PR #81331)

2024-02-09 Thread Joseph Huber via cfe-commits

https://github.com/jhuber6 created 
https://github.com/llvm/llvm-project/pull/81331

Summary:
This patch adds a new intrinsic and builtin function mirroring the
existing `__builtin_readcyclecounter`. The difference is that this
implementation targets a separate counter that some targets have which
returns a fixed frequency clock that can be used to determine elapsed
time, this is different compared to the cycle counter which often has
variable frequency. This is currently only valid for the NVPTX and
AMDGPU targets.


>From f6d905fe46c18b8076bb9af4ccb6583ed60d5ca6 Mon Sep 17 00:00:00 2001
From: Joseph Huber 
Date: Fri, 9 Feb 2024 16:13:42 -0600
Subject: [PATCH] [WIP][LLVM] Add `__builtin_readfixedtimer` intrinsic and
 buiiltin

Summary:
This patch adds a new intrinsic and builtin function mirroring the
existing `__builtin_readcyclecounter`. The difference is that this
implementation targets a separate counter that some targets have which
returns a fixed frequency clock that can be used to determine elapsed
time, this is different compared to the cycle counter which often has
variable frequency. This is currently only valid for the NVPTX and
AMDGPU targets.
---
 clang/include/clang/Basic/Builtins.td  |  6 ++
 clang/lib/CodeGen/CGBuiltin.cpp|  4 
 llvm/include/llvm/CodeGen/ISDOpcodes.h |  6 ++
 llvm/include/llvm/IR/Intrinsics.td |  2 ++
 llvm/include/llvm/Support/TargetOpcodes.def|  3 +++
 llvm/include/llvm/Target/GenericOpcodes.td |  6 ++
 .../llvm/Target/GlobalISel/SelectionDAGCompat.td   |  1 +
 llvm/include/llvm/Target/TargetSelectionDAG.td |  3 +++
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp   |  2 ++
 llvm/lib/CodeGen/IntrinsicLowering.cpp |  6 ++
 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp  |  6 --
 .../CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp  |  5 +++--
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h  |  2 +-
 .../CodeGen/SelectionDAG/SelectionDAGBuilder.cpp   |  8 
 .../CodeGen/SelectionDAG/SelectionDAGDumper.cpp|  1 +
 llvm/lib/CodeGen/TargetLoweringBase.cpp|  3 +++
 llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp |  3 +++
 llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp  |  1 +
 llvm/lib/Target/AMDGPU/SMInstructions.td   | 14 ++
 19 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 31a2bdeb2d3e5e..3bc043b35e187b 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1110,6 +1110,12 @@ def ReadCycleCounter : Builtin {
   let Prototype = "unsigned long long int()";
 }
 
+def ReadFixedTimer : Builtin {
+  let Spellings = ["__builtin_readfixedtimer"];
+  let Attributes = [NoThrow];
+  let Prototype = "unsigned long long int()";
+}
+
 def Trap : Builtin {
   let Spellings = ["__builtin_trap"];
   let Attributes = [NoThrow, NoReturn];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a7a410dab1a018..8da8bbc56758d5 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3443,6 +3443,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
 Function *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
 return RValue::get(Builder.CreateCall(F));
   }
+  case Builtin::BI__builtin_readfixedtimer: {
+Function *F = CGM.getIntrinsic(Intrinsic::readfixedtimer);
+return RValue::get(Builder.CreateCall(F));
+  }
   case Builtin::BI__builtin___clear_cache: {
 Value *Begin = EmitScalarExpr(E->getArg(0));
 Value *End = EmitScalarExpr(E->getArg(1));
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h 
b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 349d1286c8dc4f..882e80c521e897 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1179,6 +1179,12 @@ enum NodeType {
   /// counter-like register (or other high accuracy low latency clock source).
   READCYCLECOUNTER,
 
+  /// READFIXEDTIMER - This corresponds to the readfixedcounter intrinsic.
+  /// It has the same semantics as the READCYCLECOUNTER implementation except
+  /// that the result is the content of the architecture-specific fixed
+  /// frequency counter suitable for measuring elapsed time.
+  READFIXEDTIMER,
+
   /// HANDLENODE node - Used as a handle for various purposes.
   HANDLENODE,
 
diff --git a/llvm/include/llvm/IR/Intrinsics.td 
b/llvm/include/llvm/IR/Intrinsics.td
index 3c19c7b063652c..4d7c57944f3778 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -870,6 +870,8 @@ def int_pcmarker  : DefaultAttrsIntrinsic<[], 
[llvm_i32_ty]>;
 
 def int_readcyclecounter : DefaultAttrsIntrinsic<[llvm_i64_ty]>;
 
+def int_readfixedtimer : DefaultAttrsIntrinsic<[llvm_i64_ty]>;
+
 // The assume intrinsic is marked InaccessibleMemOnly