-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[AArch64][FEAT_CMPBR] Codegen for Armv9.6-a compare-and-branch #116465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
55a4f0f
563ae0f
df6e831
0139ebe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -507,6 +507,9 @@ class AArch64DAGToDAGISel : public SelectionDAGISel { | |
|
|
||
| bool SelectAllActivePredicate(SDValue N); | ||
| bool SelectAnyPredicate(SDValue N); | ||
|
|
||
| template <int Bits> | ||
| bool SelectCmpBranchUImm6Operand(SDNode *P, SDValue N, SDValue &Imm); | ||
| }; | ||
|
|
||
| class AArch64DAGToDAGISelLegacy : public SelectionDAGISelLegacy { | ||
|
|
@@ -7489,3 +7492,57 @@ bool AArch64DAGToDAGISel::SelectSMETileSlice(SDValue N, unsigned MaxSize, | |
| Offset = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); | ||
| return true; | ||
| } | ||
|
|
||
| template <int Bits> | ||
| bool AArch64DAGToDAGISel::SelectCmpBranchUImm6Operand(SDNode *P, SDValue N, | ||
| SDValue &Imm) { | ||
| ConstantSDNode *C = dyn_cast<ConstantSDNode>(P->getOperand(1)); | ||
| if (!C) | ||
| return false; | ||
|
|
||
| AArch64CC::CondCode CC = static_cast<AArch64CC::CondCode>(C->getZExtValue()); | ||
| if (auto *CN = dyn_cast<ConstantSDNode>(N)) { | ||
| // Check conservatively if the immediate fits the valid range [0, 64). | ||
| // Immediate variants for GE and HS definitely need to be decremented | ||
| // when lowering the pseudos later, so an immediate of 1 would become 0. | ||
| // For the inverse conditions LT and LO we don't know for sure if they | ||
| // will need a decrement but should the decision be made to reverse the | ||
| // branch condition, we again end up with the need to decrement. | ||
| // The same argument holds for LE, LS, GT and HI and possibly | ||
| // incremented immediates. This can lead to slightly less optimal | ||
| // codegen, e.g. we never codegen the legal case | ||
| // cblt w0, #63, A | ||
| // because we could end up with the illegal case | ||
| // cbge w0, #64, B | ||
| // should the decision to reverse the branch direction be made. For the | ||
| // lower bound cases this is no problem since we can express comparisons | ||
| // against 0 with either tbz/tnbz or using wzr/xzr. | ||
| uint64_t LowerBound = 0, UpperBound = 64; | ||
| switch (CC) { | ||
| case AArch64CC::GE: | ||
| case AArch64CC::HS: | ||
| case AArch64CC::LT: | ||
| case AArch64CC::LO: | ||
| LowerBound = 1; | ||
| break; | ||
| case AArch64CC::LE: | ||
| case AArch64CC::LS: | ||
| case AArch64CC::GT: | ||
| case AArch64CC::HI: | ||
| UpperBound = 63; | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
|
|
||
| if (CN->getAPIntValue().uge(LowerBound) && | ||
| CN->getAPIntValue().ult(UpperBound)) { | ||
| SDLoc DL(N); | ||
| Imm = CurDAG->getTargetConstant(CN->getZExtValue(), DL, | ||
| Bits == 32 ? MVT::i32 : MVT::i64); | ||
|
||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2983,6 +2983,7 @@ const char *AArch64TargetLowering::getTargetNodeName(unsigned Opcode) const { | |
| MAKE_CASE(AArch64ISD::CTTZ_ELTS) | ||
| MAKE_CASE(AArch64ISD::CALL_ARM64EC_TO_X64) | ||
| MAKE_CASE(AArch64ISD::URSHR_I_PRED) | ||
| MAKE_CASE(AArch64ISD::CB) | ||
| } | ||
|
||
| #undef MAKE_CASE | ||
| return nullptr; | ||
|
|
@@ -10593,6 +10594,17 @@ SDValue AArch64TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { | |
| DAG.getConstant(SignBitPos, dl, MVT::i64), Dest); | ||
| } | ||
|
|
||
| // Try to emit Armv9.6 CB instructions. We prefer tb{n}z/cb{n}z due to their | ||
| // larger branch displacement but do prefer CB over cmp + br. | ||
| if (Subtarget->hasCMPBR() && | ||
| AArch64CC::isValidCBCond(changeIntCCToAArch64CC(CC)) && | ||
| ProduceNonFlagSettingCondBr) { | ||
| SDValue Cond = | ||
| DAG.getTargetConstant(changeIntCCToAArch64CC(CC), dl, MVT::i32); | ||
| return DAG.getNode(AArch64ISD::CB, dl, MVT::Other, Chain, Cond, LHS, RHS, | ||
| Dest); | ||
| } | ||
|
|
||
| SDValue CCVal; | ||
| SDValue Cmp = getAArch64Cmp(LHS, RHS, CC, CCVal, DAG, dl); | ||
| return DAG.getNode(AArch64ISD::BRCOND, dl, MVT::Other, Chain, Dest, CCVal, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -400,6 +400,20 @@ def uimm6_32b : Operand<i32>, ImmLeaf<i32, [{ return Imm >= 0 && Imm < 64; }]> { | |
| let ParserMatchClass = UImm6Operand; | ||
| } | ||
|
|
||
| def CmpBranchUImm6Operand_32b | ||
| : Operand<i32>, | ||
|
||
| ComplexPattern<i32, 1, "SelectCmpBranchUImm6Operand<32>"> { | ||
| let ParserMatchClass = UImm6Operand; | ||
| let WantsParent = true; | ||
| } | ||
|
|
||
| def CmpBranchUImm6Operand_64b | ||
| : Operand<i64>, | ||
| ComplexPattern<i64, 1, "SelectCmpBranchUImm6Operand<64>"> { | ||
| let ParserMatchClass = UImm6Operand; | ||
| let WantsParent = true; | ||
| } | ||
|
|
||
| def UImm6Plus1Operand : AsmOperandClass { | ||
| let Name = "UImm6P1"; | ||
| let DiagnosticType = "InvalidImm1_64"; | ||
|
|
@@ -13232,6 +13246,21 @@ multiclass CmpBranchRegisterAlias<string mnemonic, string insn> { | |
| def : InstAlias<mnemonic # "\t$Rt, $Rm, $target", | ||
| (!cast<Instruction>(insn # "Xrr") GPR64:$Rm, GPR64:$Rt, am_brcmpcond:$target), 0>; | ||
| } | ||
|
|
||
| class CmpBranchRegisterPseudo<RegisterClass regtype> | ||
| : Pseudo<(outs), (ins ccode:$Cond, regtype:$Rt, regtype:$Rm, am_brcmpcond:$Target), []>, | ||
| Sched<[WriteBr]> { | ||
| let isBranch = 1; | ||
| let isTerminator = 1; | ||
| } | ||
|
|
||
| class CmpBranchImmediatePseudo<RegisterClass regtype, ImmLeaf imtype> | ||
| : Pseudo<(outs), (ins ccode:$Cond, regtype:$Rt, imtype:$Imm, am_brcmpcond:$Target), []>, | ||
| Sched<[WriteBr]> { | ||
| let isBranch = 1; | ||
| let isTerminator = 1; | ||
| } | ||
|
|
||
| //---------------------------------------------------------------------------- | ||
| // Allow the size specifier tokens to be upper case, not just lower. | ||
| def : TokenAlias<".4B", ".4b">; // Add dot product | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can assume this is always the case, so rely upon P->getConstantOperandVal(1) (it has an assert inside it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done