diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index f1cc9fd958447..9e8ac6f2cfdff 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -359,6 +359,10 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM, setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + if (Subtarget.hasMips32r2() || + getTargetMachine().getTargetTriple().isOSLinux()) + setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom); + // Lower fmin/fmax/fclass operations for MIPS R6. if (Subtarget.hasMips32r6()) { setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal); @@ -1311,6 +1315,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const case ISD::STORE: return lowerSTORE(Op, DAG); case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG); case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG); + case ISD::READCYCLECOUNTER: + return lowerREADCYCLECOUNTER(Op, DAG); } return SDValue(); } @@ -2092,6 +2098,44 @@ MachineBasicBlock *MipsTargetLowering::emitAtomicCmpSwapPartword( return exitMBB; } +SDValue MipsTargetLowering::lowerREADCYCLECOUNTER(SDValue Op, + SelectionDAG &DAG) const { + SmallVector Results; + SDLoc DL(Op); + MachineFunction &MF = DAG.getMachineFunction(); + unsigned RdhwrOpc, DestReg; + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + if (PtrVT == MVT::i64) { + RdhwrOpc = Mips::RDHWR64; + DestReg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64)); + SDNode *Rdhwr = DAG.getMachineNode(RdhwrOpc, DL, MVT::i64, MVT::Glue, + DAG.getRegister(Mips::HWR2, MVT::i32), + DAG.getTargetConstant(0, DL, MVT::i32)); + SDValue Chain = DAG.getCopyToReg(DAG.getEntryNode(), DL, DestReg, + SDValue(Rdhwr, 0), SDValue(Rdhwr, 1)); + SDValue ResNode = + DAG.getCopyFromReg(Chain, DL, DestReg, MVT::i64, Chain.getValue(1)); + Results.push_back(ResNode); + Results.push_back(ResNode.getValue(1)); + } else { + RdhwrOpc = Mips::RDHWR; + DestReg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32)); + SDNode *Rdhwr = DAG.getMachineNode(RdhwrOpc, DL, MVT::i32, MVT::Glue, + DAG.getRegister(Mips::HWR2, MVT::i32), + DAG.getTargetConstant(0, DL, MVT::i32)); + SDValue Chain = DAG.getCopyToReg(DAG.getEntryNode(), DL, DestReg, + SDValue(Rdhwr, 0), SDValue(Rdhwr, 1)); + SDValue ResNode = + DAG.getCopyFromReg(Chain, DL, DestReg, MVT::i32, Chain.getValue(1)); + Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, ResNode, + DAG.getConstant(0, DL, MVT::i32))); + Results.push_back(ResNode.getValue(1)); + } + + return DAG.getMergeValues(Results, DL); +} + SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const { // The first operand is the chain, the second is the condition, the third is // the block to branch to if the condition is true. diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h index 2b18b29918092..e96f6500d0f13 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.h +++ b/llvm/lib/Target/Mips/MipsISelLowering.h @@ -560,6 +560,7 @@ class TargetRegisterClass; bool IsSRA) const; SDValue lowerEH_DWARF_CFA(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerREADCYCLECOUNTER(SDValue Op, SelectionDAG &DAG) const; /// isEligibleForTailCallOptimization - Check whether the call is eligible /// for tail call optimization. diff --git a/llvm/test/CodeGen/Mips/readcyclecounter.ll b/llvm/test/CodeGen/Mips/readcyclecounter.ll new file mode 100644 index 0000000000000..c7a27d34806f8 --- /dev/null +++ b/llvm/test/CodeGen/Mips/readcyclecounter.ll @@ -0,0 +1,43 @@ +;RUN: llc -mtriple=mipsel-linux-gnu -mcpu=mips32r2 < %s | FileCheck %s --check-prefix=MIPSEL +;RUN: llc -mtriple=mips64el-linux-gnuabi64 -mcpu=mips64r2 < %s | FileCheck %s --check-prefix=MIPS64EL +;RUN: llc -mtriple=mipsel-linux-gnu -mcpu=mips2 < %s | FileCheck %s --check-prefix=MIPSEL +;RUN: llc -mtriple=mips64el-linux-gnuabi64 -mcpu=mips3 < %s | FileCheck %s --check-prefix=MIPS64EL +;RUN: llc -mtriple=mipsel -mcpu=mips32r2 < %s | FileCheck %s --check-prefix=MIPSEL +;RUN: llc -mtriple=mips64el -mcpu=mips64r2 < %s | FileCheck %s --check-prefix=MIPS64EL +;RUN: llc -mtriple=mipsel -mcpu=mips2 < %s | FileCheck %s --check-prefix=MIPSEL_NOT_SUPPORTED +;RUN: llc -mtriple=mips64el -mcpu=mips3 < %s | FileCheck %s --check-prefix=MIPS64EL_NOT_SUPPORTED + +define i64 @test_readcyclecounter() nounwind { +; MIPSEL-LABEL: test_readcyclecounter: +; MIPSEL: # %bb.0: # %entry +; MIPSEL-NEXT: .set push +; MIPSEL-NEXT: .set mips32r2 +; MIPSEL-NEXT: rdhwr $2, $hwr_cc +; MIPSEL-NEXT: .set pop +; MIPSEL-NEXT: jr $ra +; MIPSEL-NEXT: addiu $3, $zero, 0 +; +; MIPSEL_NOT_SUPPORTED-LABEL: test_readcyclecounter: +; MIPSEL_NOT_SUPPORTED: # %bb.0: # %entry +; MIPSEL_NOT_SUPPORTED-NEXT: addiu $2, $zero, 0 +; MIPSEL_NOT_SUPPORTED-NEXT: jr $ra +; MIPSEL_NOT_SUPPORTED-NEXT: addiu $3, $zero, 0 +; +; MIPS64EL-LABEL: test_readcyclecounter: +; MIPS64EL: # %bb.0: # %entry +; MIPS64EL-NEXT: .set push +; MIPS64EL-NEXT: .set mips32r2 +; MIPS64EL-NEXT: rdhwr $2, $hwr_cc +; MIPS64EL-NEXT: .set pop +; MIPS64EL-NEXT: jr $ra +; MIPS64EL-NEXT: nop +; +; MIPS64EL_NOT_SUPPORTED-LABEL: test_readcyclecounter: +; MIPS64EL_NOT_SUPPORTED: # %bb.0: # %entry +; MIPS64EL_NOT_SUPPORTED-NEXT: jr $ra +; MIPS64EL_NOT_SUPPORTED-NEXT: daddiu $2, $zero, 0 +entry: + %tmp0 = call i64 @llvm.readcyclecounter() + ret i64 %tmp0 +} +