Index: llvm/trunk/lib/Target/AArch64/AArch64.td =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64.td +++ llvm/trunk/lib/Target/AArch64/AArch64.td @@ -32,6 +32,9 @@ def FeatureCRC : SubtargetFeature<"crc", "HasCRC", "true", "Enable ARMv8 CRC-32 checksum instructions">; +def FeaturePerfMon : SubtargetFeature<"perfmon", "HasPerfMon", "true", + "Enable ARMv8 PMUv3 Performance Monitors extension">; + /// Cyclone has register move instructions which are "free". def FeatureZCRegMove : SubtargetFeature<"zcm", "HasZeroCycleRegMove", "true", "Has zero-cycle register moves">; @@ -84,14 +87,16 @@ [FeatureFPARMv8, FeatureNEON, FeatureCrypto, - FeatureCRC]>; + FeatureCRC, + FeaturePerfMon]>; def ProcA57 : SubtargetFeature<"a57", "ARMProcFamily", "CortexA57", "Cortex-A57 ARM processors", [FeatureFPARMv8, FeatureNEON, FeatureCrypto, - FeatureCRC]>; + FeatureCRC, + FeaturePerfMon]>; def ProcCyclone : SubtargetFeature<"cyclone", "ARMProcFamily", "Cyclone", "Cyclone", @@ -99,11 +104,13 @@ FeatureNEON, FeatureCrypto, FeatureCRC, + FeaturePerfMon, FeatureZCRegMove, FeatureZCZeroing]>; def : ProcessorModel<"generic", NoSchedModel, [FeatureFPARMv8, FeatureNEON, - FeatureCRC]>; + FeatureCRC, + FeaturePerfMon]>; def : ProcessorModel<"cortex-a53", CortexA53Model, [ProcA53]>; def : ProcessorModel<"cortex-a57", CortexA57Model, [ProcA57]>; Index: llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -399,6 +399,11 @@ setOperationAction(ISD::PREFETCH, MVT::Other, Custom); + // Lower READCYCLECOUNTER using an mrs from PMCCNTR_EL0. + // This requires the Performance Monitors extension. + if (Subtarget->hasPerfMon()) + setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Legal); + if (Subtarget->isTargetMachO()) { // For iOS, we don't want to the normal expansion of a libcall to // sincos. We want to issue a libcall to __sincos_stret to avoid memory Index: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td +++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td @@ -24,6 +24,7 @@ AssemblerPredicate<"FeatureCrypto", "crypto">; def HasCRC : Predicate<"Subtarget->hasCRC()">, AssemblerPredicate<"FeatureCRC", "crc">; +def HasPerfMon : Predicate<"Subtarget->hasPerfMon()">; def IsLE : Predicate<"Subtarget->isLittleEndian()">; def IsBE : Predicate<"!Subtarget->isLittleEndian()">; def IsCyclone : Predicate<"Subtarget->isCyclone()">; @@ -404,6 +405,10 @@ // TPIDR_EL0. def : Pat<(AArch64threadpointer), (MRS 0xde82)>; +// The cycle counter PMC register is PMCCNTR_EL0. +let Predicates = [HasPerfMon] in +def : Pat<(readcyclecounter), (MRS 0xdce8)>; + // Generic system instructions def SYSxt : SystemXtI<0, "sys">; def SYSLxt : SystemLXtI<1, "sysl">; Index: llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h +++ llvm/trunk/lib/Target/AArch64/AArch64Subtarget.h @@ -44,6 +44,7 @@ bool HasNEON; bool HasCrypto; bool HasCRC; + bool HasPerfMon; // HasZeroCycleRegMove - Has zero-cycle register mov instructions. bool HasZeroCycleRegMove; @@ -114,6 +115,7 @@ bool hasNEON() const { return HasNEON; } bool hasCrypto() const { return HasCrypto; } bool hasCRC() const { return HasCRC; } + bool hasPerfMon() const { return HasPerfMon; } bool isLittleEndian() const { return IsLittle; } Index: llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp @@ -47,9 +47,9 @@ const TargetMachine &TM, bool LittleEndian) : AArch64GenSubtargetInfo(TT, CPU, FS), ARMProcFamily(Others), HasV8_1aOps(false), HasFPARMv8(false), HasNEON(false), HasCrypto(false), - HasCRC(false), HasZeroCycleRegMove(false), HasZeroCycleZeroing(false), - StrictAlign(false), ReserveX18(false), IsLittle(LittleEndian), - CPUString(CPU), TargetTriple(TT), FrameLowering(), + HasCRC(false), HasPerfMon(false), HasZeroCycleRegMove(false), + HasZeroCycleZeroing(false), StrictAlign(false), ReserveX18(false), + IsLittle(LittleEndian), CPUString(CPU), TargetTriple(TT), FrameLowering(), InstrInfo(initializeSubtargetDependencies(FS)), TSInfo(), TLInfo(TM, *this) {} Index: llvm/trunk/test/CodeGen/AArch64/readcyclecounter.ll =================================================================== --- llvm/trunk/test/CodeGen/AArch64/readcyclecounter.ll +++ llvm/trunk/test/CodeGen/AArch64/readcyclecounter.ll @@ -0,0 +1,15 @@ +; RUN: llc -mtriple=aarch64-unknown-unknown -asm-verbose=false < %s |\ +; RUN: FileCheck %s --check-prefix=CHECK --check-prefix=PERFMON +; RUN: llc -mtriple=aarch64-unknown-unknown -mattr=-perfmon -asm-verbose=false < %s |\ +; RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOPERFMON + +define i64 @test_readcyclecounter() nounwind { + ; CHECK-LABEL: test_readcyclecounter: + ; PERFMON-NEXT: mrs x0, PMCCNTR_EL0 + ; NOPERFMON-NEXT: mov x0, xzr + ; CHECK-NEXT: ret + %tmp0 = call i64 @llvm.readcyclecounter() + ret i64 %tmp0 +} + +declare i64 @llvm.readcyclecounter()