[CodeGen] Support (and default to) expanding READCYCLECOUNTER to 0.

For targets that didn't support this, this will let us respect the
langref instead of failing to select.

Note that we don't need to change the 32-bit x86/PPC lowerings (to
account for the result type/# difference) because they're both
custom and bypass type legalization.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246258 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ahmed Bougacha 2015-08-28 01:49:59 +00:00
parent 0bf9bbac45
commit 5edf06bb57
6 changed files with 54 additions and 33 deletions

View File

@ -638,9 +638,11 @@ namespace ISD {
PCMARKER, PCMARKER,
/// READCYCLECOUNTER - This corresponds to the readcyclecounter intrinsic. /// READCYCLECOUNTER - This corresponds to the readcyclecounter intrinsic.
/// The only operand is a chain and a value and a chain are produced. The /// It produces a chain and one i64 value. The only operand is a chain.
/// value is the contents of the architecture specific cycle counter like /// If i64 is not legal, the result will be expanded into smaller values.
/// register (or other high accuracy low latency clock source) /// Still, it returns an i64, so targets should set legality for i64.
/// The result is the content of the architecture-specific cycle
/// counter-like register (or other high accuracy low latency clock source).
READCYCLECOUNTER, READCYCLECOUNTER,
/// HANDLENODE node - Used as a handle for various purposes. /// HANDLENODE node - Used as a handle for various purposes.

View File

@ -1269,6 +1269,11 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
if (Action == TargetLowering::Legal) if (Action == TargetLowering::Legal)
Action = TargetLowering::Custom; Action = TargetLowering::Custom;
break; break;
case ISD::READCYCLECOUNTER:
// READCYCLECOUNTER returns an i64, even if type legalization might have
// expanded that to several smaller types.
Action = TLI.getOperationAction(Node->getOpcode(), MVT::i64);
break;
case ISD::READ_REGISTER: case ISD::READ_REGISTER:
case ISD::WRITE_REGISTER: case ISD::WRITE_REGISTER:
// Named register is legal in the DAG, but blocked by register name // Named register is legal in the DAG, but blocked by register name
@ -2901,6 +2906,13 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node) {
// preserve the chain and be done. // preserve the chain and be done.
Results.push_back(Node->getOperand(0)); Results.push_back(Node->getOperand(0));
break; break;
case ISD::READCYCLECOUNTER:
// If the target didn't expand this, just return 'zero' and preserve the
// chain.
Results.append(Node->getNumValues() - 1,
DAG.getConstant(0, dl, Node->getValueType(0)));
Results.push_back(Node->getOperand(0));
break;
case ISD::EH_SJLJ_SETJMP: case ISD::EH_SJLJ_SETJMP:
// If the target didn't expand this, just return 'zero' and preserve the // If the target didn't expand this, just return 'zero' and preserve the
// chain. // chain.

View File

@ -1274,6 +1274,7 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) {
case ISD::FP_TO_UINT: ExpandIntRes_FP_TO_UINT(N, Lo, Hi); break; case ISD::FP_TO_UINT: ExpandIntRes_FP_TO_UINT(N, Lo, Hi); break;
case ISD::LOAD: ExpandIntRes_LOAD(cast<LoadSDNode>(N), Lo, Hi); break; case ISD::LOAD: ExpandIntRes_LOAD(cast<LoadSDNode>(N), Lo, Hi); break;
case ISD::MUL: ExpandIntRes_MUL(N, Lo, Hi); break; case ISD::MUL: ExpandIntRes_MUL(N, Lo, Hi); break;
case ISD::READCYCLECOUNTER: ExpandIntRes_READCYCLECOUNTER(N, Lo, Hi); break;
case ISD::SDIV: ExpandIntRes_SDIV(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: ExpandIntRes_SIGN_EXTEND(N, Lo, Hi); break;
case ISD::SIGN_EXTEND_INREG: ExpandIntRes_SIGN_EXTEND_INREG(N, Lo, Hi); break; case ISD::SIGN_EXTEND_INREG: ExpandIntRes_SIGN_EXTEND_INREG(N, Lo, Hi); break;
@ -2105,6 +2106,17 @@ void DAGTypeLegalizer::ExpandIntRes_MUL(SDNode *N,
Lo, Hi); Lo, Hi);
} }
void DAGTypeLegalizer::ExpandIntRes_READCYCLECOUNTER(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDLoc DL(N);
EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDVTList VTs = DAG.getVTList(NVT, NVT, MVT::Other);
SDValue R = DAG.getNode(N->getOpcode(), DL, VTs, N->getOperand(0));
Lo = R.getValue(0);
Hi = R.getValue(1);
ReplaceValueWith(SDValue(N, 1), R.getValue(2));
}
void DAGTypeLegalizer::ExpandIntRes_SADDSUBO(SDNode *Node, void DAGTypeLegalizer::ExpandIntRes_SADDSUBO(SDNode *Node,
SDValue &Lo, SDValue &Hi) { SDValue &Lo, SDValue &Hi) {
SDValue LHS = Node->getOperand(0); SDValue LHS = Node->getOperand(0);

View File

@ -322,6 +322,7 @@ private:
void ExpandIntRes_CTPOP (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_CTPOP (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_CTTZ (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_CTTZ (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_LOAD (LoadSDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_LOAD (LoadSDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_READCYCLECOUNTER (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_SIGN_EXTEND (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_SIGN_EXTEND (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_SIGN_EXTEND_INREG (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_SIGN_EXTEND_INREG (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_TRUNCATE (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_TRUNCATE (SDNode *N, SDValue &Lo, SDValue &Hi);

View File

@ -845,6 +845,9 @@ void TargetLoweringBase::initActions() {
// Most targets ignore the @llvm.prefetch intrinsic. // Most targets ignore the @llvm.prefetch intrinsic.
setOperationAction(ISD::PREFETCH, MVT::Other, Expand); setOperationAction(ISD::PREFETCH, MVT::Other, Expand);
// Most targets also ignore the @llvm.readcyclecounter intrinsic.
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Expand);
// ConstantFP nodes default to expand. Targets can either change this to // ConstantFP nodes default to expand. Targets can either change this to
// Legal, in which case all fp constants are legal, or use isFPImmLegal() // Legal, in which case all fp constants are legal, or use isFPImmLegal()
// to optimize expansions for certain constants. // to optimize expansions for certain constants.

View File

@ -725,7 +725,12 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::CTTZ_ZERO_UNDEF , MVT::i32 , Expand); setOperationAction(ISD::CTTZ_ZERO_UNDEF , MVT::i32 , Expand);
setOperationAction(ISD::CTLZ_ZERO_UNDEF , MVT::i32 , Expand); setOperationAction(ISD::CTLZ_ZERO_UNDEF , MVT::i32 , Expand);
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom); // @llvm.readcyclecounter requires the Performance Monitors extension.
// Default to the 0 expansion on unsupported platforms.
// FIXME: Technically there are older ARM CPUs that have
// implementation-specific ways of obtaining this information.
if (Subtarget->hasPerfMon())
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom);
// Only ARMv6 has BSWAP. // Only ARMv6 has BSWAP.
if (!Subtarget->hasV6Ops()) if (!Subtarget->hasV6Ops())
@ -6645,36 +6650,22 @@ static void ReplaceREADCYCLECOUNTER(SDNode *N,
SelectionDAG &DAG, SelectionDAG &DAG,
const ARMSubtarget *Subtarget) { const ARMSubtarget *Subtarget) {
SDLoc DL(N); SDLoc DL(N);
SDValue Cycles32, OutChain; // 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, DL, MVT::i32),
DAG.getConstant(15, DL, MVT::i32),
DAG.getConstant(0, DL, MVT::i32),
DAG.getConstant(9, DL, MVT::i32),
DAG.getConstant(13, DL, MVT::i32),
DAG.getConstant(0, DL, MVT::i32)
};
if (Subtarget->hasPerfMon()) { SDValue Cycles32 = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL,
// Under Power Management extensions, the cycle-count is: DAG.getVTList(MVT::i32, MVT::Other), Ops);
// mrc p15, #0, <Rt>, c9, c13, #0 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Cycles32,
SDValue Ops[] = { N->getOperand(0), // Chain DAG.getConstant(0, DL, MVT::i32)));
DAG.getConstant(Intrinsic::arm_mrc, DL, MVT::i32), Results.push_back(Cycles32.getValue(1));
DAG.getConstant(15, DL, MVT::i32),
DAG.getConstant(0, DL, MVT::i32),
DAG.getConstant(9, DL, MVT::i32),
DAG.getConstant(13, DL, MVT::i32),
DAG.getConstant(0, DL, MVT::i32)
};
Cycles32 = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL,
DAG.getVTList(MVT::i32, MVT::Other), 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, DL, MVT::i32);
OutChain = DAG.getEntryNode();
}
SDValue Cycles64 = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
Cycles32, DAG.getConstant(0, DL, MVT::i32));
Results.push_back(Cycles64);
Results.push_back(OutChain);
} }
SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {