Files
gps/tools/local/circt/include/llvm/Transforms/Utils/PredicateInfo.h
T
2026-07-12 11:01:51 +03:00

256 lines
8.2 KiB
C++

//===- PredicateInfo.h - Build PredicateInfo ----------------------*-C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the PredicateInfo analysis, which creates an Extended
/// SSA form for operations used in branch comparisons and llvm.assume
/// comparisons.
///
/// Copies of these operations are inserted into the true/false edge (and after
/// assumes), and information attached to the copies. All uses of the original
/// operation in blocks dominated by the true/false edge (and assume), are
/// replaced with uses of the copies. This enables passes to easily and sparsely
/// propagate condition based info into the operations that may be affected.
///
/// Example:
/// %cmp = icmp eq i32 %x, 50
/// br i1 %cmp, label %true, label %false
/// true:
/// ret i32 %x
/// false:
/// ret i32 1
///
/// will become
///
/// %cmp = icmp eq i32, %x, 50
/// br i1 %cmp, label %true, label %false
/// true:
/// %x.0 = bitcast i32 %x to %x
/// ret i32 %x.0
/// false:
/// ret i32 1
///
/// Using getPredicateInfoFor on x.0 will give you the comparison it is
/// dominated by (the icmp), and that you are located in the true edge of that
/// comparison, which tells you x.0 is 50.
///
/// In order to reduce the number of copies inserted, predicateinfo is only
/// inserted where it would actually be live. This means if there are no uses of
/// an operation dominated by the branch edges, or by an assume, the associated
/// predicate info is never inserted.
///
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H
#define LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/IR/BundleAttributes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
namespace llvm {
class AssumptionCache;
class DominatorTree;
class Function;
class Value;
class IntrinsicInst;
class raw_ostream;
enum PredicateType {
PT_Branch,
PT_ConditionAssume,
PT_BundleAssume,
PT_Switch
};
/// Constraint for a predicate of the form "cmp Pred Op, OtherOp", where Op
/// is the value the constraint applies to (the bitcast result).
struct PredicateConstraint {
CmpInst::Predicate Predicate;
Value *OtherOp;
};
// Base class for all predicate information we provide.
// All of our predicate information has at least a comparison.
class PredicateBase {
public:
PredicateType Type;
// The original operand before we renamed it.
// This can be use by passes, when destroying predicateinfo, to know
// whether they can just drop the intrinsic, or have to merge metadata.
Value *OriginalOp;
// The renamed operand in the condition used for this predicate. For nested
// predicates, this is different to OriginalOp which refers to the initial
// operand.
Value *RenamedOp;
// The condition associated with this predicate.
Value *Condition;
PredicateBase(const PredicateBase &) = delete;
PredicateBase &operator=(const PredicateBase &) = delete;
PredicateBase() = delete;
static bool classof(const PredicateBase *PB) {
return PB->Type == PT_BundleAssume || PB->Type == PT_ConditionAssume ||
PB->Type == PT_Branch || PB->Type == PT_Switch;
}
/// Fetch condition in the form of PredicateConstraint, if possible.
LLVM_ABI std::optional<PredicateConstraint> getConstraint() const;
protected:
PredicateBase(PredicateType PT, Value *Op, Value *Condition)
: Type(PT), OriginalOp(Op), Condition(Condition) {}
};
// Provides predicate information for assumes. Since assumes are always true,
// we simply provide the assume instruction, so you can tell your relative
// position to it.
class PredicateAssume : public PredicateBase {
public:
IntrinsicInst *AssumeInst;
static bool classof(const PredicateBase *PB) {
return PB->Type == PT_ConditionAssume || PB->Type == PT_BundleAssume;
}
protected:
PredicateAssume(PredicateType PT, Value *Op, IntrinsicInst *AssumeInst,
Value *Condition)
: PredicateBase(PT, Op, Condition), AssumeInst(AssumeInst) {}
};
class PredicateBundleAssume : public PredicateAssume {
public:
BundleAttr AttrKind;
PredicateBundleAssume(Value *Op, IntrinsicInst *AssumeInst,
BundleAttr AttrKind)
: PredicateAssume(PT_BundleAssume, Op, AssumeInst, nullptr),
AttrKind(AttrKind) {}
static bool classof(const PredicateBase *PB) {
return PB->Type == PT_BundleAssume;
}
};
class PredicateConditionAssume : public PredicateAssume {
public:
PredicateConditionAssume(Value *Op, IntrinsicInst *AssumeInst,
Value *Condition)
: PredicateAssume(PT_ConditionAssume, Op, AssumeInst, Condition) {}
static bool classof(const PredicateBase *PB) {
return PB->Type == PT_ConditionAssume;
}
};
// Mixin class for edge predicates. The FROM block is the block where the
// predicate originates, and the TO block is the block where the predicate is
// valid.
class PredicateWithEdge : public PredicateBase {
public:
BasicBlock *From;
BasicBlock *To;
PredicateWithEdge() = delete;
static bool classof(const PredicateBase *PB) {
return PB->Type == PT_Branch || PB->Type == PT_Switch;
}
protected:
PredicateWithEdge(PredicateType PType, Value *Op, BasicBlock *From,
BasicBlock *To, Value *Cond)
: PredicateBase(PType, Op, Cond), From(From), To(To) {}
};
// Provides predicate information for branches.
class PredicateBranch : public PredicateWithEdge {
public:
// If true, SplitBB is the true successor, otherwise it's the false successor.
bool TrueEdge;
PredicateBranch(Value *Op, BasicBlock *BranchBB, BasicBlock *SplitBB,
Value *Condition, bool TakenEdge)
: PredicateWithEdge(PT_Branch, Op, BranchBB, SplitBB, Condition),
TrueEdge(TakenEdge) {}
PredicateBranch() = delete;
static bool classof(const PredicateBase *PB) {
return PB->Type == PT_Branch;
}
};
class PredicateSwitch : public PredicateWithEdge {
public:
Value *CaseValue;
// This is the switch instruction.
SwitchInst *Switch;
PredicateSwitch(Value *Op, BasicBlock *SwitchBB, BasicBlock *TargetBB,
Value *CaseValue, SwitchInst *SI)
: PredicateWithEdge(PT_Switch, Op, SwitchBB, TargetBB,
SI->getCondition()),
CaseValue(CaseValue), Switch(SI) {}
PredicateSwitch() = delete;
static bool classof(const PredicateBase *PB) {
return PB->Type == PT_Switch;
}
};
/// Encapsulates PredicateInfo, including all data associated with memory
/// accesses.
class PredicateInfo {
public:
LLVM_ABI PredicateInfo(Function &, DominatorTree &, AssumptionCache &,
BumpPtrAllocator &);
LLVM_ABI void verifyPredicateInfo() const;
LLVM_ABI void dump() const;
LLVM_ABI void print(raw_ostream &) const;
const PredicateBase *getPredicateInfoFor(const Value *V) const {
return PredicateMap.lookup(V);
}
protected:
// Used by PredicateInfo annotater, dumpers, and wrapper pass.
friend class PredicateInfoAnnotatedWriter;
friend class PredicateInfoBuilder;
private:
Function &F;
// This maps from copy operands to Predicate Info. Note that it does not own
// the Predicate Info, they belong to the ValueInfo structs in the ValueInfos
// vector.
DenseMap<const Value *, const PredicateBase *> PredicateMap;
};
/// Printer pass for \c PredicateInfo.
class PredicateInfoPrinterPass
: public RequiredPassInfoMixin<PredicateInfoPrinterPass> {
raw_ostream &OS;
public:
explicit PredicateInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
/// Verifier pass for \c PredicateInfo.
struct PredicateInfoVerifierPass
: RequiredPassInfoMixin<PredicateInfoVerifierPass> {
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
} // end namespace llvm
#endif // LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H