-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[TargetLowering] Deduplicate choosing InlineAsm constraint between ISels #67057
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 all commits
9d40003
3ac190b
5d1d8ab
2d16f27
a542e81
a0cb4cb
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 |
---|---|---|
|
@@ -5378,11 +5378,12 @@ SDValue TargetLowering::LowerAsmOutputForConstraint( | |
/// Lower the specified operand into the Ops vector. | ||
/// If it is invalid, don't add anything to Ops. | ||
void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, | ||
std::string &Constraint, | ||
StringRef Constraint, | ||
std::vector<SDValue> &Ops, | ||
SelectionDAG &DAG) const { | ||
|
||
if (Constraint.length() > 1) return; | ||
if (Constraint.size() > 1) | ||
return; | ||
|
||
char ConstraintLetter = Constraint[0]; | ||
switch (ConstraintLetter) { | ||
|
@@ -5701,20 +5702,27 @@ TargetLowering::ParseConstraints(const DataLayout &DL, | |
return ConstraintOperands; | ||
} | ||
|
||
/// Return an integer indicating how general CT is. | ||
static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { | ||
/// Return a number indicating our preference for chosing a type of constraint | ||
/// over another, for the purpose of sorting them. Immediates are almost always | ||
/// preferrable (when they can be emitted). A higher return value means a | ||
/// stronger preference for one constraint type relative to another. | ||
/// FIXME: We should prefer registers over memory but doing so may lead to | ||
/// unrecoverable register exhaustion later. | ||
/// https://github.com/llvm/llvm-project/issues/20571 | ||
static unsigned getConstraintPiority(TargetLowering::ConstraintType CT) { | ||
switch (CT) { | ||
case TargetLowering::C_Immediate: | ||
case TargetLowering::C_Other: | ||
case TargetLowering::C_Unknown: | ||
return 0; | ||
case TargetLowering::C_Register: | ||
return 1; | ||
case TargetLowering::C_RegisterClass: | ||
return 2; | ||
return 4; | ||
case TargetLowering::C_Memory: | ||
case TargetLowering::C_Address: | ||
return 3; | ||
case TargetLowering::C_RegisterClass: | ||
return 2; | ||
case TargetLowering::C_Register: | ||
return 1; | ||
case TargetLowering::C_Unknown: | ||
return 0; | ||
} | ||
llvm_unreachable("Invalid constraint type"); | ||
} | ||
|
@@ -5812,59 +5820,51 @@ TargetLowering::ConstraintWeight | |
/// 2) Otherwise, pick the most general constraint present. This prefers | ||
/// 'm' over 'r', for example. | ||
/// | ||
static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, | ||
const TargetLowering &TLI, | ||
SDValue Op, SelectionDAG *DAG) { | ||
assert(OpInfo.Codes.size() > 1 && "Doesn't have multiple constraint options"); | ||
unsigned BestIdx = 0; | ||
TargetLowering::ConstraintType BestType = TargetLowering::C_Unknown; | ||
int BestGenerality = -1; | ||
TargetLowering::ConstraintGroup TargetLowering::getConstraintPreferences( | ||
TargetLowering::AsmOperandInfo &OpInfo) const { | ||
ConstraintGroup Ret; | ||
|
||
// Loop over the options, keeping track of the most general one. | ||
for (unsigned i = 0, e = OpInfo.Codes.size(); i != e; ++i) { | ||
TargetLowering::ConstraintType CType = | ||
TLI.getConstraintType(OpInfo.Codes[i]); | ||
Ret.reserve(OpInfo.Codes.size()); | ||
for (StringRef Code : OpInfo.Codes) { | ||
TargetLowering::ConstraintType CType = getConstraintType(Code); | ||
|
||
// Indirect 'other' or 'immediate' constraints are not allowed. | ||
if (OpInfo.isIndirect && !(CType == TargetLowering::C_Memory || | ||
CType == TargetLowering::C_Register || | ||
CType == TargetLowering::C_RegisterClass)) | ||
continue; | ||
|
||
// If this is an 'other' or 'immediate' constraint, see if the operand is | ||
// valid for it. For example, on X86 we might have an 'rI' constraint. If | ||
// the operand is an integer in the range [0..31] we want to use I (saving a | ||
// load of a register), otherwise we must use 'r'. | ||
if ((CType == TargetLowering::C_Other || | ||
CType == TargetLowering::C_Immediate) && Op.getNode()) { | ||
assert(OpInfo.Codes[i].size() == 1 && | ||
"Unhandled multi-letter 'other' constraint"); | ||
std::vector<SDValue> ResultOps; | ||
TLI.LowerAsmOperandForConstraint(Op, OpInfo.Codes[i], | ||
ResultOps, *DAG); | ||
if (!ResultOps.empty()) { | ||
BestType = CType; | ||
BestIdx = i; | ||
break; | ||
} | ||
} | ||
|
||
// Things with matching constraints can only be registers, per gcc | ||
// documentation. This mainly affects "g" constraints. | ||
if (CType == TargetLowering::C_Memory && OpInfo.hasMatchingInput()) | ||
continue; | ||
|
||
// This constraint letter is more general than the previous one, use it. | ||
int Generality = getConstraintGenerality(CType); | ||
if (Generality > BestGenerality) { | ||
BestType = CType; | ||
BestIdx = i; | ||
BestGenerality = Generality; | ||
} | ||
Ret.emplace_back(Code, CType); | ||
} | ||
|
||
OpInfo.ConstraintCode = OpInfo.Codes[BestIdx]; | ||
OpInfo.ConstraintType = BestType; | ||
std::sort(Ret.begin(), Ret.end(), [](ConstraintPair a, ConstraintPair b) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this sort() seems to have introduced nondeterminism in some configs I've replaced it with stable_sort in 679c3a1 - maybe you have a better fix, but this seemed like a safe way to avoid reverting. (My reading is the old code picks the first best option & stable_sort restores this) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, thank you @sam-mccall ! |
||
return getConstraintPiority(a.second) > getConstraintPiority(b.second); | ||
}); | ||
|
||
return Ret; | ||
} | ||
|
||
/// If we have an immediate, see if we can lower it. Return true if we can, | ||
/// false otherwise. | ||
static bool lowerImmediateIfPossible(TargetLowering::ConstraintPair &P, | ||
nickdesaulniers marked this conversation as resolved.
Show resolved
Hide resolved
|
||
SDValue Op, SelectionDAG *DAG, | ||
const TargetLowering &TLI) { | ||
|
||
assert((P.second == TargetLowering::C_Other || | ||
P.second == TargetLowering::C_Immediate) && | ||
"need immediate or other"); | ||
|
||
if (!Op.getNode()) | ||
return false; | ||
|
||
std::vector<SDValue> ResultOps; | ||
TLI.LowerAsmOperandForConstraint(Op, P.first, ResultOps, *DAG); | ||
return !ResultOps.empty(); | ||
} | ||
|
||
/// Determines the constraint code and constraint type to use for the specific | ||
|
@@ -5879,7 +5879,20 @@ void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo, | |
OpInfo.ConstraintCode = OpInfo.Codes[0]; | ||
OpInfo.ConstraintType = getConstraintType(OpInfo.ConstraintCode); | ||
} else { | ||
ChooseConstraint(OpInfo, *this, Op, DAG); | ||
ConstraintGroup G = getConstraintPreferences(OpInfo); | ||
if (G.empty()) | ||
return; | ||
|
||
unsigned BestIdx = 0; | ||
for (const unsigned E = G.size(); | ||
BestIdx < E && (G[BestIdx].second == TargetLowering::C_Other || | ||
G[BestIdx].second == TargetLowering::C_Immediate); | ||
++BestIdx) | ||
if (lowerImmediateIfPossible(G[BestIdx], Op, DAG, *this)) | ||
break; | ||
|
||
OpInfo.ConstraintCode = G[BestIdx].first; | ||
OpInfo.ConstraintType = G[BestIdx].second; | ||
} | ||
|
||
// 'X' matches anything. | ||
|
Uh oh!
There was an error while loading. Please reload this page.