69#define DEBUG_TYPE "poison-checking"
74 cl::desc(
"Check that returns are non-poison (for testing)"));
78 assert(V->getType()->isIntegerTy(1));
79 if (
auto *CI = dyn_cast<ConstantInt>(V))
91 Value *Accum = Ops[i++];
94 Accum =
B.CreateOr(Accum,
Op);
100 assert(isa<BinaryOperator>(
I));
105 switch (
I.getOpcode()) {
108 case Instruction::Add: {
109 if (
I.hasNoSignedWrap()) {
111 B.CreateBinaryIntrinsic(Intrinsic::sadd_with_overflow,
LHS,
RHS);
112 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
114 if (
I.hasNoUnsignedWrap()) {
116 B.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow,
LHS,
RHS);
117 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
121 case Instruction::Sub: {
122 if (
I.hasNoSignedWrap()) {
124 B.CreateBinaryIntrinsic(Intrinsic::ssub_with_overflow,
LHS,
RHS);
125 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
127 if (
I.hasNoUnsignedWrap()) {
129 B.CreateBinaryIntrinsic(Intrinsic::usub_with_overflow,
LHS,
RHS);
130 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
134 case Instruction::Mul: {
135 if (
I.hasNoSignedWrap()) {
137 B.CreateBinaryIntrinsic(Intrinsic::smul_with_overflow,
LHS,
RHS);
138 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
140 if (
I.hasNoUnsignedWrap()) {
142 B.CreateBinaryIntrinsic(Intrinsic::umul_with_overflow,
LHS,
RHS);
143 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
147 case Instruction::UDiv: {
150 B.CreateICmp(ICmpInst::ICMP_NE,
B.CreateURem(
LHS,
RHS),
156 case Instruction::SDiv: {
159 B.CreateICmp(ICmpInst::ICMP_NE,
B.CreateSRem(
LHS,
RHS),
165 case Instruction::AShr:
166 case Instruction::LShr:
167 case Instruction::Shl: {
169 B.CreateICmp(ICmpInst::ICMP_UGE,
RHS,
184 if (isa<BinaryOperator>(
I) && !
I.getType()->isVectorTy())
188 switch (
I.getOpcode()) {
193 case Instruction::ExtractElement: {
194 Value *Vec =
I.getOperand(0);
195 auto *VecVTy = dyn_cast<FixedVectorType>(Vec->
getType());
199 unsigned NumElts = VecVTy->getNumElements();
201 B.CreateICmp(ICmpInst::ICMP_UGE,
Idx,
206 case Instruction::InsertElement: {
207 Value *Vec =
I.getOperand(0);
208 auto *VecVTy = dyn_cast<FixedVectorType>(Vec->
getType());
212 unsigned NumElts = VecVTy->getNumElements();
214 B.CreateICmp(ICmpInst::ICMP_UGE,
Idx,
223 auto Itr = ValToPoison.
find(V);
224 if (Itr != ValToPoison.
end())
226 if (isa<Constant>(V)) {
238 if (
auto *CI = dyn_cast<ConstantInt>(
Cond))
239 if (CI->isAllOnesValue())
242 Module *M =
B.GetInsertBlock()->getModule();
243 M->getOrInsertFunction(
"__poison_checker_assert",
246 Function *TrapFunc = M->getFunction(
"__poison_checker_assert");
247 B.CreateCall(TrapFunc,
Cond);
261 for (
auto I = BB.begin(); isa<PHINode>(&*
I);
I++) {
262 auto *OldPHI = cast<PHINode>(&*
I);
263 auto *NewPHI =
PHINode::Create(Int1Ty, OldPHI->getNumIncomingValues());
264 for (
unsigned i = 0; i < OldPHI->getNumIncomingValues(); i++)
266 OldPHI->getIncomingBlock(i));
267 NewPHI->insertBefore(OldPHI);
268 ValToPoison[OldPHI] = NewPHI;
273 if (isa<PHINode>(
I))
continue;
282 for (
const Value *
Op : NonPoisonOps)
283 if (SeenNonPoisonOps.
insert(
Op).second)
288 if (
auto *RI = dyn_cast<ReturnInst>(&
I))
289 if (RI->getNumOperands() != 0) {
295 for (
const Use &U :
I.operands()) {
306 for (
auto I = BB.begin(); isa<PHINode>(&*
I);
I++) {
307 auto *OldPHI = cast<PHINode>(&*
I);
308 if (!ValToPoison.
count(OldPHI))
310 auto *NewPHI = cast<PHINode>(ValToPoison[OldPHI]);
311 for (
unsigned i = 0; i < OldPHI->getNumIncomingValues(); i++) {
312 auto *OldVal = OldPHI->getIncomingValue(i);
313 NewPHI->setIncomingValue(i,
getPoisonFor(ValToPoison, OldVal));
322 bool Changed =
false;
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseMap class.
static void generateCreationChecksForBinOp(Instruction &I, SmallVectorImpl< Value * > &Checks)
static void CreateAssertNot(IRBuilder<> &B, Value *Cond)
static bool rewrite(Function &F)
static Value * getPoisonFor(DenseMap< Value *, Value * > &ValToPoison, Value *V)
static cl::opt< bool > LocalCheck("poison-checking-function-local", cl::init(false), cl::desc("Check that returns are non-poison (for testing)"))
static bool isConstantFalse(Value *V)
static Value * buildOrChain(IRBuilder<> &B, ArrayRef< Value * > Ops)
static void generateCreationChecks(Instruction &I, SmallVectorImpl< Value * > &Checks)
Given an instruction which can produce poison on non-poison inputs (i.e.
static void CreateAssert(IRBuilder<> &B, Value *Cond)
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A container for analyses that lazily runs them and caches their results.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
LLVM Basic Block Representation.
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
static ConstantInt * getFalse(LLVMContext &Context)
This class represents an Operation in the Expression.
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
A Module instance is used to store all the information related to an LLVM module.
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static IntegerType * getInt1Ty(LLVMContext &C)
unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
static Type * getVoidTy(LLVMContext &C)
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool canCreatePoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
void getGuaranteedNonPoisonOps(const Instruction *I, SmallVectorImpl< const Value * > &Ops)
Insert operands of I into Ops such that I will trigger undefined behavior if I is executed and that o...
bool propagatesPoison(const Use &PoisonOp)
Return true if PoisonOp's user yields poison or raises UB if its operand PoisonOp is poison.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)