LLVM-STUDY
SubclassOptionalData
die4taoam
2023. 12. 11. 04:20
LLVM 에는 최적화를 위한 부가 데이터가 있다.
value.h
protected:
/// Hold subclass data that can be dropped.
///
/// This member is similar to SubclassData, however it is for holding
/// information which may be used to aid optimization, but which may be
/// cleared to zero without affecting conservative interpretation.
unsigned char SubclassOptionalData : 7;
SubClassOptionalData
or disjoint
disjoint는 or 최적화를 위한 부가정보를 담고 있다.
/// An or instruction, which can be marked as "disjoint", indicating that the
/// inputs don't have a 1 in the same bit position. Meaning this instruction
/// can also be treated as an add.
class PossiblyDisjointInst : public BinaryOperator {
주석의 설명과 같이 disjoint는 or의 두 인자가 서로 다른 비트로 구성되어 있는 경우에 세팅되게 된다.
최근에 disjoint 를 적용한 패치
https://github.com/llvm/llvm-project/pull/74467
[SCEV] Use or disjoint flag by nikic · Pull Request #74467 · llvm/llvm-project
Use the disjoint flag to convert or to add instead of calling the haveNoCommonBitsSet() ValueTracking query. This ensures that we can reliably undo add -> or canonicalization, even in cases where t...
github.com
패치 본문에 나오는 것처럼
case Instruction::Or: {
// Convert or disjoint into add nuw nsw.
if (cast<PossiblyDisjointInst>(Op)->isDisjoint())
return BinaryOp(Instruction::Add, Op->getOperand(0), Op->getOperand(1),
/*IsNSW=*/true, /*IsNUW=*/true);
return BinaryOp(Op);
}
or이 disjoint인 경우 Add 연산을 리턴하는 코드이다.
이전코드는 직접 비트를 검사했었다.
case Instruction::Or: {
// LLVM loves to convert `add` of operands with no common bits
// into an `or`. But SCEV really doesn't deal with `or` that well,
// so try extra hard to recognize this `or` as an `add`.
if (haveNoCommonBitsSet(Op->getOperand(0), Op->getOperand(1),
SimplifyQuery(DL, &DT, &AC, CxtI)))
return BinaryOp(Instruction::Add, Op->getOperand(0), Op->getOperand(1),
/*IsNSW=*/true, /*IsNUW=*/true);
return BinaryOp(Op);
}
disjoint 는 다음과 같이 세팅되거나
InstCombineSimplifyDemanded.cpp:267
// Infer disjoint flag if no common bits are set.
if (!cast<PossiblyDisjointInst>(I)->isDisjoint()) {
WithCache<const Value *> LHSCache(I->getOperand(0), LHSKnown),
RHSCache(I->getOperand(1), RHSKnown);
if (haveNoCommonBitsSet(LHSCache, RHSCache, SQ.getWithInstruction(I))) {
cast<PossiblyDisjointInst>(I)->setIsDisjoint(true);
return I;
}
}
다음처럼 최적화 과정에서 생성된다.
InstCombineSimplifyDemanded.cpp:311
// If all of the demanded bits are known to be zero on one side or the
// other, turn this into an *inclusive* or.
// e.g. (A & C1)^(B & C2) -> (A & C1)|(B & C2) iff C1&C2 == 0
if (DemandedMask.isSubsetOf(RHSKnown.Zero | LHSKnown.Zero)) {
Instruction *Or =
BinaryOperator::CreateOr(I->getOperand(0), I->getOperand(1));
if (DemandedMask.isAllOnes())
cast<PossiblyDisjointInst>(Or)->setIsDisjoint(true);
Or->takeName(I);
return InsertNewInstWith(Or, I->getIterator());
}