70#define DEBUG_TYPE "poison-checking"
75 cl::desc(
"Check that returns are non-poison (for testing)"));
79 assert(V->getType()->isIntegerTy(1));
80 if (
auto *CI = dyn_cast<ConstantInt>(V))
92 Value *Accum = Ops[i++];
95 Accum =
B.CreateOr(Accum,
Op);
101 assert(isa<BinaryOperator>(
I));
106 switch (
I.getOpcode()) {
109 case Instruction::Add: {
110 if (
I.hasNoSignedWrap()) {
112 B.CreateBinaryIntrinsic(Intrinsic::sadd_with_overflow,
LHS,
RHS);
113 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
115 if (
I.hasNoUnsignedWrap()) {
117 B.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow,
LHS,
RHS);
118 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
122 case Instruction::Sub: {
123 if (
I.hasNoSignedWrap()) {
125 B.CreateBinaryIntrinsic(Intrinsic::ssub_with_overflow,
LHS,
RHS);
126 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
128 if (
I.hasNoUnsignedWrap()) {
130 B.CreateBinaryIntrinsic(Intrinsic::usub_with_overflow,
LHS,
RHS);
131 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
135 case Instruction::Mul: {
136 if (
I.hasNoSignedWrap()) {
138 B.CreateBinaryIntrinsic(Intrinsic::smul_with_overflow,
LHS,
RHS);
139 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
141 if (
I.hasNoUnsignedWrap()) {
143 B.CreateBinaryIntrinsic(Intrinsic::umul_with_overflow,
LHS,
RHS);
144 Checks.
push_back(
B.CreateExtractValue(OverflowOp, 1));
148 case Instruction::UDiv: {
151 B.CreateICmp(ICmpInst::ICMP_NE,
B.CreateURem(
LHS,
RHS),
157 case Instruction::SDiv: {
160 B.CreateICmp(ICmpInst::ICMP_NE,
B.CreateSRem(
LHS,
RHS),
166 case Instruction::AShr:
167 case Instruction::LShr:
168 case Instruction::Shl: {
170 B.CreateICmp(ICmpInst::ICMP_UGE,
RHS,
185 if (isa<BinaryOperator>(
I) && !
I.getType()->isVectorTy())
189 switch (
I.getOpcode()) {
194 case Instruction::ExtractElement: {
195 Value *Vec =
I.getOperand(0);
196 auto *VecVTy = dyn_cast<FixedVectorType>(Vec->
getType());
200 unsigned NumElts = VecVTy->getNumElements();
202 B.CreateICmp(ICmpInst::ICMP_UGE,
Idx,
203 ConstantInt::get(
Idx->getType(), NumElts));
207 case Instruction::InsertElement: {
208 Value *Vec =
I.getOperand(0);
209 auto *VecVTy = dyn_cast<FixedVectorType>(Vec->
getType());
213 unsigned NumElts = VecVTy->getNumElements();
215 B.CreateICmp(ICmpInst::ICMP_UGE,
Idx,
216 ConstantInt::get(
Idx->getType(), NumElts));
224 auto Itr = ValToPoison.
find(V);
225 if (Itr != ValToPoison.
end())
227 if (isa<Constant>(V)) {
239 if (
auto *CI = dyn_cast<ConstantInt>(
Cond))
240 if (CI->isAllOnesValue())
243 Module *M =
B.GetInsertBlock()->getModule();
244 M->getOrInsertFunction(
"__poison_checker_assert",
247 Function *TrapFunc = M->getFunction(
"__poison_checker_assert");
248 B.CreateCall(TrapFunc,
Cond);
262 for (
auto I = BB.begin(); isa<PHINode>(&*
I);
I++) {
263 auto *OldPHI = cast<PHINode>(&*
I);
264 auto *NewPHI =
PHINode::Create(Int1Ty, OldPHI->getNumIncomingValues());
265 for (
unsigned i = 0; i < OldPHI->getNumIncomingValues(); i++)
267 OldPHI->getIncomingBlock(i));
268 NewPHI->insertBefore(OldPHI);
269 ValToPoison[OldPHI] = NewPHI;
274 if (isa<PHINode>(
I))
continue;
283 for (
const Value *
Op : NonPoisonOps)
284 if (SeenNonPoisonOps.
insert(
Op).second)
289 if (
auto *RI = dyn_cast<ReturnInst>(&
I))
290 if (RI->getNumOperands() != 0) {
296 for (
const Use &U :
I.operands()) {
307 for (
auto I = BB.begin(); isa<PHINode>(&*
I);
I++) {
308 auto *OldPHI = cast<PHINode>(&*
I);
309 if (!ValToPoison.
count(OldPHI))
311 auto *NewPHI = cast<PHINode>(ValToPoison[OldPHI]);
312 for (
unsigned i = 0; i < OldPHI->getNumIncomingValues(); i++) {
313 auto *OldVal = OldPHI->getIncomingValue(i);
314 NewPHI->setIncomingValue(i,
getPoisonFor(ValToPoison, OldVal));
323 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.
Module.h This file contains the declarations for the Module 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 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="", InsertPosition 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)