Skip to content

Commit f73f8ac

Browse files
toppercAllen Bing-Sung Lu
authored andcommitted
[IR] Add disjoint flag for Or instructions. (llvm#72583)
This flag indicates that every bit is known to be zero in at least one of the inputs. This allows the Or to be treated as an Add since there is no possibility of a carry from any bit. If the flag is present and this property does not hold, the result is poison. This makes it easier to reverse the InstCombine transform that turns Add into Or. This is inspired by a comment here llvm#71955 (comment) Discourse thread https://discourse.llvm.org/t/rfc-add-or-disjoint-flag/75036
1 parent 9805308 commit f73f8ac

File tree

17 files changed

+221
-3
lines changed

17 files changed

+221
-3
lines changed

llvm/docs/LangRef.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9901,6 +9901,7 @@ Syntax:
99019901
::
99029902

99039903
<result> = or <ty> <op1>, <op2> ; yields ty:result
9904+
<result> = or disjoint <ty> <op1>, <op2> ; yields ty:result
99049905

99059906
Overview:
99069907
"""""""""
@@ -9932,6 +9933,12 @@ The truth table used for the '``or``' instruction is:
99329933
| 1 | 1 | 1 |
99339934
+-----+-----+-----+
99349935

9936+
``disjoint`` means that for each bit, that bit is zero in at least one of the
9937+
inputs. This allows the Or to be treated as an Add since no carry can occur from
9938+
any bit. If the disjoint keyword is present, the result value of the ``or`` is a
9939+
:ref:`poison value <poisonvalues>` if both inputs have a one in the same bit
9940+
position. For vectors, only the element containing the bit is poison.
9941+
99359942
Example:
99369943
""""""""
99379944

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ enum Kind {
109109
kw_nuw,
110110
kw_nsw,
111111
kw_exact,
112+
kw_disjoint,
112113
kw_inbounds,
113114
kw_inrange,
114115
kw_addrspace,

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ enum FastMathMap {
509509
/// PossiblyExactOperator's SubclassOptionalData contents.
510510
enum PossiblyExactOperatorOptionalFlags { PEO_EXACT = 0 };
511511

512+
/// PossiblyDisjointInstOptionalFlags - Flags for serializing
513+
/// PossiblyDisjointInst's SubclassOptionalData contents.
514+
enum PossiblyDisjointInstOptionalFlags { PDI_DISJOINT = 0 };
515+
512516
/// Encoded AtomicOrdering values.
513517
enum AtomicOrderingCodes {
514518
ORDERING_NOTATOMIC = 0,

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,29 @@ struct OperandTraits<BinaryOperator> :
415415

416416
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryOperator, Value)
417417

418+
/// An or instruction, which can be marked as "disjoint", indicating that the
419+
/// inputs don't have a 1 in the same bit position. Meaning this instruction
420+
/// can also be treated as an add.
421+
class PossiblyDisjointInst : public BinaryOperator {
422+
public:
423+
enum { IsDisjoint = (1 << 0) };
424+
425+
void setIsDisjoint(bool B) {
426+
SubclassOptionalData =
427+
(SubclassOptionalData & ~IsDisjoint) | (B * IsDisjoint);
428+
}
429+
430+
bool isDisjoint() const { return SubclassOptionalData & IsDisjoint; }
431+
432+
static bool classof(const Instruction *I) {
433+
return I->getOpcode() == Instruction::Or;
434+
}
435+
436+
static bool classof(const Value *V) {
437+
return isa<Instruction>(V) && classof(cast<Instruction>(V));
438+
}
439+
};
440+
418441
//===----------------------------------------------------------------------===//
419442
// CastInst Class
420443
//===----------------------------------------------------------------------===//

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ lltok::Kind LLLexer::LexIdentifier() {
564564
KEYWORD(nuw);
565565
KEYWORD(nsw);
566566
KEYWORD(exact);
567+
KEYWORD(disjoint);
567568
KEYWORD(inbounds);
568569
KEYWORD(inrange);
569570
KEYWORD(addrspace);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6404,8 +6404,15 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
64046404
case lltok::kw_srem:
64056405
return parseArithmetic(Inst, PFS, KeywordVal,
64066406
/*IsFP*/ false);
6407+
case lltok::kw_or: {
6408+
bool Disjoint = EatIfPresent(lltok::kw_disjoint);
6409+
if (parseLogical(Inst, PFS, KeywordVal))
6410+
return true;
6411+
if (Disjoint)
6412+
cast<PossiblyDisjointInst>(Inst)->setIsDisjoint(true);
6413+
return false;
6414+
}
64076415
case lltok::kw_and:
6408-
case lltok::kw_or:
64096416
case lltok::kw_xor:
64106417
return parseLogical(Inst, PFS, KeywordVal);
64116418
case lltok::kw_icmp:

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4865,12 +4865,14 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
48654865
Opc == Instruction::AShr) {
48664866
if (Record[OpNum] & (1 << bitc::PEO_EXACT))
48674867
cast<BinaryOperator>(I)->setIsExact(true);
4868+
} else if (Opc == Instruction::Or) {
4869+
if (Record[OpNum] & (1 << bitc::PDI_DISJOINT))
4870+
cast<PossiblyDisjointInst>(I)->setIsDisjoint(true);
48684871
} else if (isa<FPMathOperator>(I)) {
48694872
FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]);
48704873
if (FMF.any())
48714874
I->setFastMathFlags(FMF);
48724875
}
4873-
48744876
}
48754877
break;
48764878
}

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,9 @@ static uint64_t getOptimizationFlags(const Value *V) {
15221522
} else if (const auto *PEO = dyn_cast<PossiblyExactOperator>(V)) {
15231523
if (PEO->isExact())
15241524
Flags |= 1 << bitc::PEO_EXACT;
1525+
} else if (const auto *PDI = dyn_cast<PossiblyDisjointInst>(V)) {
1526+
if (PDI->isDisjoint())
1527+
Flags |= 1 << bitc::PDI_DISJOINT;
15251528
} else if (const auto *FPMO = dyn_cast<FPMathOperator>(V)) {
15261529
if (FPMO->hasAllowReassoc())
15271530
Flags |= bitc::AllowReassoc;

llvm/lib/IR/AsmWriter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,10 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
13431343
dyn_cast<PossiblyExactOperator>(U)) {
13441344
if (Div->isExact())
13451345
Out << " exact";
1346+
} else if (const PossiblyDisjointInst *PDI =
1347+
dyn_cast<PossiblyDisjointInst>(U)) {
1348+
if (PDI->isDisjoint())
1349+
Out << " disjoint";
13461350
} else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
13471351
if (GEP->isInBounds())
13481352
Out << " inbounds";

llvm/lib/IR/Instruction.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ void Instruction::dropPoisonGeneratingFlags() {
201201
cast<PossiblyExactOperator>(this)->setIsExact(false);
202202
break;
203203

204+
case Instruction::Or:
205+
cast<PossiblyDisjointInst>(this)->setIsDisjoint(false);
206+
break;
207+
204208
case Instruction::GetElementPtr:
205209
cast<GetElementPtrInst>(this)->setIsInBounds(false);
206210
break;
@@ -371,6 +375,10 @@ void Instruction::copyIRFlags(const Value *V, bool IncludeWrapFlags) {
371375
if (isa<PossiblyExactOperator>(this))
372376
setIsExact(PE->isExact());
373377

378+
if (auto *SrcPD = dyn_cast<PossiblyDisjointInst>(V))
379+
if (auto *DestPD = dyn_cast<PossiblyDisjointInst>(this))
380+
DestPD->setIsDisjoint(SrcPD->isDisjoint());
381+
374382
// Copy the fast-math flags.
375383
if (auto *FP = dyn_cast<FPMathOperator>(V))
376384
if (isa<FPMathOperator>(this))
@@ -393,6 +401,10 @@ void Instruction::andIRFlags(const Value *V) {
393401
if (isa<PossiblyExactOperator>(this))
394402
setIsExact(isExact() && PE->isExact());
395403

404+
if (auto *SrcPD = dyn_cast<PossiblyDisjointInst>(V))
405+
if (auto *DestPD = dyn_cast<PossiblyDisjointInst>(this))
406+
DestPD->setIsDisjoint(DestPD->isDisjoint() && SrcPD->isDisjoint());
407+
396408
if (auto *FP = dyn_cast<FPMathOperator>(V)) {
397409
if (isa<FPMathOperator>(this)) {
398410
FastMathFlags FM = getFastMathFlags();

0 commit comments

Comments
 (0)