diff options
-rw-r--r-- | llvm/docs/LangRef.rst | 7 | ||||
-rw-r--r-- | llvm/include/llvm/AsmParser/LLToken.h | 1 | ||||
-rw-r--r-- | llvm/include/llvm/Bitcode/LLVMBitCodes.h | 4 | ||||
-rw-r--r-- | llvm/include/llvm/IR/InstrTypes.h | 23 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLLexer.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 9 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/IR/AsmWriter.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/IR/Instruction.cpp | 12 | ||||
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 5 | ||||
-rw-r--r-- | llvm/test/Assembler/flags.ll | 5 | ||||
-rw-r--r-- | llvm/test/Bitcode/compatibility.ll | 4 | ||||
-rw-r--r-- | llvm/test/Bitcode/flags.ll | 4 | ||||
-rw-r--r-- | llvm/test/Transforms/InstCombine/freeze.ll | 11 | ||||
-rw-r--r-- | llvm/test/Transforms/InstCombine/or.ll | 11 | ||||
-rw-r--r-- | llvm/test/Transforms/SimplifyCFG/HoistCode.ll | 30 |
17 files changed, 135 insertions, 3 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index bc1eab1..e448c5e 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -9981,6 +9981,7 @@ Syntax: :: <result> = or <ty> <op1>, <op2> ; yields ty:result + <result> = or disjoint <ty> <op1>, <op2> ; yields ty:result Overview: """"""""" @@ -10012,6 +10013,12 @@ The truth table used for the '``or``' instruction is: | 1 | 1 | 1 | +-----+-----+-----+ +``disjoint`` means that for each bit, that bit is zero in at least one of the +inputs. This allows the Or to be treated as an Add since no carry can occur from +any bit. If the disjoint keyword is present, the result value of the ``or`` is a +:ref:`poison value <poisonvalues>` if both inputs have a one in the same bit +position. For vectors, only the element containing the bit is poison. + Example: """""""" diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index 1eb3986..0683291 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -109,6 +109,7 @@ enum Kind { kw_nuw, kw_nsw, kw_exact, + kw_disjoint, kw_inbounds, kw_nneg, kw_inrange, diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 9fa70c0..99a41fa 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -512,6 +512,10 @@ enum PossiblyNonNegInstOptionalFlags { PNNI_NON_NEG = 0 }; /// PossiblyExactOperator's SubclassOptionalData contents. enum PossiblyExactOperatorOptionalFlags { PEO_EXACT = 0 }; +/// PossiblyDisjointInstOptionalFlags - Flags for serializing +/// PossiblyDisjointInst's SubclassOptionalData contents. +enum PossiblyDisjointInstOptionalFlags { PDI_DISJOINT = 0 }; + /// Encoded AtomicOrdering values. enum AtomicOrderingCodes { ORDERING_NOTATOMIC = 0, diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h index fc5e228..ddae3e4 100644 --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -415,6 +415,29 @@ struct OperandTraits<BinaryOperator> : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryOperator, Value) +/// 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 { +public: + enum { IsDisjoint = (1 << 0) }; + + void setIsDisjoint(bool B) { + SubclassOptionalData = + (SubclassOptionalData & ~IsDisjoint) | (B * IsDisjoint); + } + + bool isDisjoint() const { return SubclassOptionalData & IsDisjoint; } + + static bool classof(const Instruction *I) { + return I->getOpcode() == Instruction::Or; + } + + static bool classof(const Value *V) { + return isa<Instruction>(V) && classof(cast<Instruction>(V)); + } +}; + //===----------------------------------------------------------------------===// // CastInst Class //===----------------------------------------------------------------------===// diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index fb11104..09a205c 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -564,6 +564,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(nuw); KEYWORD(nsw); KEYWORD(exact); + KEYWORD(disjoint); KEYWORD(inbounds); KEYWORD(nneg); KEYWORD(inrange); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 2d2c1bf..d236b6c 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -6370,8 +6370,15 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB, case lltok::kw_srem: return parseArithmetic(Inst, PFS, KeywordVal, /*IsFP*/ false); + case lltok::kw_or: { + bool Disjoint = EatIfPresent(lltok::kw_disjoint); + if (parseLogical(Inst, PFS, KeywordVal)) + return true; + if (Disjoint) + cast<PossiblyDisjointInst>(Inst)->setIsDisjoint(true); + return false; + } case lltok::kw_and: - case lltok::kw_or: case lltok::kw_xor: return parseLogical(Inst, PFS, KeywordVal); case lltok::kw_icmp: diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 788906a..e4c3770 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -4866,12 +4866,14 @@ Error BitcodeReader::parseFunctionBody(Function *F) { Opc == Instruction::AShr) { if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast<BinaryOperator>(I)->setIsExact(true); + } else if (Opc == Instruction::Or) { + if (Record[OpNum] & (1 << bitc::PDI_DISJOINT)) + cast<PossiblyDisjointInst>(I)->setIsDisjoint(true); } else if (isa<FPMathOperator>(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } - } break; } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 9c21cc6..8239775 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1540,6 +1540,9 @@ static uint64_t getOptimizationFlags(const Value *V) { } else if (const auto *PEO = dyn_cast<PossiblyExactOperator>(V)) { if (PEO->isExact()) Flags |= 1 << bitc::PEO_EXACT; + } else if (const auto *PDI = dyn_cast<PossiblyDisjointInst>(V)) { + if (PDI->isDisjoint()) + Flags |= 1 << bitc::PDI_DISJOINT; } else if (const auto *FPMO = dyn_cast<FPMathOperator>(V)) { if (FPMO->hasAllowReassoc()) Flags |= bitc::AllowReassoc; diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index c37adb4..601b636 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1355,6 +1355,10 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) { dyn_cast<PossiblyExactOperator>(U)) { if (Div->isExact()) Out << " exact"; + } else if (const PossiblyDisjointInst *PDI = + dyn_cast<PossiblyDisjointInst>(U)) { + if (PDI->isDisjoint()) + Out << " disjoint"; } else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) { if (GEP->isInBounds()) Out << " inbounds"; diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 7449692..97797e9 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -357,6 +357,10 @@ void Instruction::dropPoisonGeneratingFlags() { cast<PossiblyExactOperator>(this)->setIsExact(false); break; + case Instruction::Or: + cast<PossiblyDisjointInst>(this)->setIsDisjoint(false); + break; + case Instruction::GetElementPtr: cast<GetElementPtrInst>(this)->setIsInBounds(false); break; @@ -532,6 +536,10 @@ void Instruction::copyIRFlags(const Value *V, bool IncludeWrapFlags) { if (isa<PossiblyExactOperator>(this)) setIsExact(PE->isExact()); + if (auto *SrcPD = dyn_cast<PossiblyDisjointInst>(V)) + if (auto *DestPD = dyn_cast<PossiblyDisjointInst>(this)) + DestPD->setIsDisjoint(SrcPD->isDisjoint()); + // Copy the fast-math flags. if (auto *FP = dyn_cast<FPMathOperator>(V)) if (isa<FPMathOperator>(this)) @@ -558,6 +566,10 @@ void Instruction::andIRFlags(const Value *V) { if (isa<PossiblyExactOperator>(this)) setIsExact(isExact() && PE->isExact()); + if (auto *SrcPD = dyn_cast<PossiblyDisjointInst>(V)) + if (auto *DestPD = dyn_cast<PossiblyDisjointInst>(this)) + DestPD->setIsDisjoint(DestPD->isDisjoint() && SrcPD->isDisjoint()); + if (auto *FP = dyn_cast<FPMathOperator>(V)) { if (isa<FPMathOperator>(this)) { FastMathFlags FM = getFastMathFlags(); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index 69b95c0..fa07609 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -231,8 +231,11 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, // If either the LHS or the RHS are One, the result is One. if (SimplifyDemandedBits(I, 1, DemandedMask, RHSKnown, Depth + 1) || SimplifyDemandedBits(I, 0, DemandedMask & ~RHSKnown.One, LHSKnown, - Depth + 1)) + Depth + 1)) { + // Disjoint flag may not longer hold. + I->dropPoisonGeneratingFlags(); return I; + } assert(!RHSKnown.hasConflict() && "Bits known to be one AND zero?"); assert(!LHSKnown.hasConflict() && "Bits known to be one AND zero?"); diff --git a/llvm/test/Assembler/flags.ll b/llvm/test/Assembler/flags.ll index 6ab5e1b..04bddd0 100644 --- a/llvm/test/Assembler/flags.ll +++ b/llvm/test/Assembler/flags.ll @@ -256,3 +256,8 @@ define i64 @test_zext(i32 %a) { ret i64 %res } +define i64 @test_or(i64 %a, i64 %b) { +; CHECK: %res = or disjoint i64 %a, %b + %res = or disjoint i64 %a, %b + ret i64 %res +} diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll index 8170f18..483024a 100644 --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -1359,6 +1359,10 @@ define void @instructions.bitwise_binops(i8 %op1, i8 %op2) { xor i8 %op1, %op2 ; CHECK: xor i8 %op1, %op2 + ; disjoint + or disjoint i8 %op1, %op2 + ; CHECK: or disjoint i8 %op1, %op2 + ret void } diff --git a/llvm/test/Bitcode/flags.ll b/llvm/test/Bitcode/flags.ll index a6e368b..e3fc827 100644 --- a/llvm/test/Bitcode/flags.ll +++ b/llvm/test/Bitcode/flags.ll @@ -18,6 +18,8 @@ second: ; preds = %first %z = add i32 %a, 0 ; <i32> [#uses=0] %hh = zext nneg i32 %a to i64 %ll = zext i32 %s to i64 + %jj = or disjoint i32 %a, 0 + %oo = or i32 %a, 0 unreachable first: ; preds = %entry @@ -28,5 +30,7 @@ first: ; preds = %entry %zz = add i32 %a, 0 ; <i32> [#uses=0] %kk = zext nneg i32 %a to i64 %rr = zext i32 %ss to i64 + %mm = or disjoint i32 %a, 0 + %nn = or i32 %a, 0 br label %second } diff --git a/llvm/test/Transforms/InstCombine/freeze.ll b/llvm/test/Transforms/InstCombine/freeze.ll index dd9272b..da59101 100644 --- a/llvm/test/Transforms/InstCombine/freeze.ll +++ b/llvm/test/Transforms/InstCombine/freeze.ll @@ -1127,6 +1127,17 @@ define i32 @freeze_zext_nneg(i8 %x) { ret i32 %fr } +define i32 @propagate_drop_flags_or(i32 %arg) { +; CHECK-LABEL: @propagate_drop_flags_or( +; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] +; CHECK-NEXT: [[V1:%.*]] = or i32 [[ARG_FR]], 2 +; CHECK-NEXT: ret i32 [[V1]] +; + %v1 = or disjoint i32 %arg, 2 + %v1.fr = freeze i32 %v1 + ret i32 %v1.fr +} + !0 = !{} !1 = !{i64 4} !2 = !{i32 0, i32 100} diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll index fd53783..642a028 100644 --- a/llvm/test/Transforms/InstCombine/or.ll +++ b/llvm/test/Transforms/InstCombine/or.ll @@ -1576,3 +1576,14 @@ define <4 x i1> @and_or_not_or_logical_vec(<4 x i32> %ap, <4 x i32> %bp) { %Z = or <4 x i1> %X, %Y ret <4 x i1> %Z } + +; Make sure SimplifyDemandedBits drops the disjoint flag. +define i8 @drop_disjoint(i8 %x) { +; CHECK-LABEL: @drop_disjoint( +; CHECK-NEXT: [[B:%.*]] = or i8 [[X:%.*]], 1 +; CHECK-NEXT: ret i8 [[B]] +; + %a = and i8 %x, -2 + %b = or disjoint i8 %a, 1 + ret i8 %b +} diff --git a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll index 08cf6cd..a081edd 100644 --- a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll +++ b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll @@ -124,3 +124,33 @@ F: %z2 = zext i8 %x to i32 ret i32 %z2 } + +define i32 @hoist_or_flags_preserve(i1 %C, i32 %x, i32 %y) { +; CHECK-LABEL: @hoist_or_flags_preserve( +; CHECK-NEXT: common.ret: +; CHECK-NEXT: [[Z1:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[Z1]] +; + br i1 %C, label %T, label %F +T: + %z1 = or disjoint i32 %x, %y + ret i32 %z1 +F: + %z2 = or disjoint i32 %x, %y + ret i32 %z2 +} + +define i32 @hoist_or_flags_drop(i1 %C, i32 %x, i32 %y) { +; CHECK-LABEL: @hoist_or_flags_drop( +; CHECK-NEXT: common.ret: +; CHECK-NEXT: [[Z1:%.*]] = or i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[Z1]] +; + br i1 %C, label %T, label %F +T: + %z1 = or i32 %x, %y + ret i32 %z1 +F: + %z2 = or disjoint i32 %x, %y + ret i32 %z2 +} |