1f47a313eSPhilip Reames //===- PoisonChecking.cpp - -----------------------------------------------===//
2f47a313eSPhilip Reames //
3f47a313eSPhilip Reames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f47a313eSPhilip Reames // See https://llvm.org/LICENSE.txt for license information.
5f47a313eSPhilip Reames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f47a313eSPhilip Reames //
7f47a313eSPhilip Reames //===----------------------------------------------------------------------===//
8f47a313eSPhilip Reames //
9f47a313eSPhilip Reames // Implements a transform pass which instruments IR such that poison semantics
10f47a313eSPhilip Reames // are made explicit. That is, it provides a (possibly partial) executable
11f47a313eSPhilip Reames // semantics for every instruction w.r.t. poison as specified in the LLVM
12f47a313eSPhilip Reames // LangRef. There are obvious parallels to the sanitizer tools, but this pass
13f47a313eSPhilip Reames // is focused purely on the semantics of LLVM IR, not any particular source
14f47a313eSPhilip Reames // language. If you're looking for something to see if your C/C++ contains
15f47a313eSPhilip Reames // UB, this is not it.
16f47a313eSPhilip Reames //
17f47a313eSPhilip Reames // The rewritten semantics of each instruction will include the following
18f47a313eSPhilip Reames // components:
19f47a313eSPhilip Reames //
20f47a313eSPhilip Reames // 1) The original instruction, unmodified.
21f47a313eSPhilip Reames // 2) A propagation rule which translates dynamic information about the poison
22f47a313eSPhilip Reames // state of each input to whether the dynamic output of the instruction
23f47a313eSPhilip Reames // produces poison.
2480c46c53SPhilip Reames // 3) A creation rule which validates any poison producing flags on the
25f47a313eSPhilip Reames // instruction itself (e.g. checks for overflow on nsw).
26f47a313eSPhilip Reames // 4) A check rule which traps (to a handler function) if this instruction must
27f47a313eSPhilip Reames // execute undefined behavior given the poison state of it's inputs.
28f47a313eSPhilip Reames //
2980c46c53SPhilip Reames // This is a must analysis based transform; that is, the resulting code may
3080c46c53SPhilip Reames // produce a false negative result (not report UB when actually exists
3180c46c53SPhilip Reames // according to the LangRef spec), but should never produce a false positive
3280c46c53SPhilip Reames // (report UB where it doesn't exist).
33f47a313eSPhilip Reames //
34f47a313eSPhilip Reames // Use cases for this pass include:
35f47a313eSPhilip Reames // - Understanding (and testing!) the implications of the definition of poison
36f47a313eSPhilip Reames // from the LangRef.
37f47a313eSPhilip Reames // - Validating the output of a IR fuzzer to ensure that all programs produced
38f47a313eSPhilip Reames // are well defined on the specific input used.
39f47a313eSPhilip Reames // - Finding/confirming poison specific miscompiles by checking the poison
40f47a313eSPhilip Reames // status of an input/IR pair is the same before and after an optimization
41f47a313eSPhilip Reames // transform.
42f47a313eSPhilip Reames // - Checking that a bugpoint reduction does not introduce UB which didn't
43f47a313eSPhilip Reames // exist in the original program being reduced.
44f47a313eSPhilip Reames //
45f47a313eSPhilip Reames // The major sources of inaccuracy are currently:
46f47a313eSPhilip Reames // - Most validation rules not yet implemented for instructions with poison
47f47a313eSPhilip Reames // relavant flags. At the moment, only nsw/nuw on add/sub are supported.
48f47a313eSPhilip Reames // - UB which is control dependent on a branch on poison is not yet
49f47a313eSPhilip Reames // reported. Currently, only data flow dependence is modeled.
50f47a313eSPhilip Reames // - Poison which is propagated through memory is not modeled. As such,
51f47a313eSPhilip Reames // storing poison to memory and then reloading it will cause a false negative
52f47a313eSPhilip Reames // as we consider the reloaded value to not be poisoned.
53f47a313eSPhilip Reames // - Poison propagation across function boundaries is not modeled. At the
54f47a313eSPhilip Reames // moment, all arguments and return values are assumed not to be poison.
55f47a313eSPhilip Reames // - Undef is not modeled. In particular, the optimizer's freedom to pick
56f47a313eSPhilip Reames // concrete values for undef bits so as to maximize potential for producing
57f47a313eSPhilip Reames // poison is not modeled.
58f47a313eSPhilip Reames //
59f47a313eSPhilip Reames //===----------------------------------------------------------------------===//
60f47a313eSPhilip Reames
61f47a313eSPhilip Reames #include "llvm/Transforms/Instrumentation/PoisonChecking.h"
62f47a313eSPhilip Reames #include "llvm/ADT/DenseMap.h"
63f47a313eSPhilip Reames #include "llvm/Analysis/ValueTracking.h"
644c1a1d3cSReid Kleckner #include "llvm/IR/IRBuilder.h"
654c1a1d3cSReid Kleckner #include "llvm/Support/CommandLine.h"
66f47a313eSPhilip Reames
67f47a313eSPhilip Reames using namespace llvm;
68f47a313eSPhilip Reames
69f47a313eSPhilip Reames #define DEBUG_TYPE "poison-checking"
70f47a313eSPhilip Reames
71f47a313eSPhilip Reames static cl::opt<bool>
72f47a313eSPhilip Reames LocalCheck("poison-checking-function-local",
73f47a313eSPhilip Reames cl::init(false),
74f47a313eSPhilip Reames cl::desc("Check that returns are non-poison (for testing)"));
75f47a313eSPhilip Reames
76f47a313eSPhilip Reames
isConstantFalse(Value * V)77f47a313eSPhilip Reames static bool isConstantFalse(Value* V) {
78f47a313eSPhilip Reames assert(V->getType()->isIntegerTy(1));
79f47a313eSPhilip Reames if (auto *CI = dyn_cast<ConstantInt>(V))
80f47a313eSPhilip Reames return CI->isZero();
81f47a313eSPhilip Reames return false;
82f47a313eSPhilip Reames }
83f47a313eSPhilip Reames
buildOrChain(IRBuilder<> & B,ArrayRef<Value * > Ops)84f47a313eSPhilip Reames static Value *buildOrChain(IRBuilder<> &B, ArrayRef<Value*> Ops) {
85f47a313eSPhilip Reames if (Ops.size() == 0)
86f47a313eSPhilip Reames return B.getFalse();
87f47a313eSPhilip Reames unsigned i = 0;
88f47a313eSPhilip Reames for (; i < Ops.size() && isConstantFalse(Ops[i]); i++) {}
89f47a313eSPhilip Reames if (i == Ops.size())
90f47a313eSPhilip Reames return B.getFalse();
91f47a313eSPhilip Reames Value *Accum = Ops[i++];
92f47a313eSPhilip Reames for (; i < Ops.size(); i++)
93f47a313eSPhilip Reames if (!isConstantFalse(Ops[i]))
94f47a313eSPhilip Reames Accum = B.CreateOr(Accum, Ops[i]);
95f47a313eSPhilip Reames return Accum;
96f47a313eSPhilip Reames }
97f47a313eSPhilip Reames
generateCreationChecksForBinOp(Instruction & I,SmallVectorImpl<Value * > & Checks)98463513e9SPhilip Reames static void generateCreationChecksForBinOp(Instruction &I,
99463513e9SPhilip Reames SmallVectorImpl<Value*> &Checks) {
100f47a313eSPhilip Reames assert(isa<BinaryOperator>(I));
101f47a313eSPhilip Reames
102f47a313eSPhilip Reames IRBuilder<> B(&I);
103f47a313eSPhilip Reames Value *LHS = I.getOperand(0);
104f47a313eSPhilip Reames Value *RHS = I.getOperand(1);
105f47a313eSPhilip Reames switch (I.getOpcode()) {
106f47a313eSPhilip Reames default:
107f47a313eSPhilip Reames return;
108f47a313eSPhilip Reames case Instruction::Add: {
109f47a313eSPhilip Reames if (I.hasNoSignedWrap()) {
110f47a313eSPhilip Reames auto *OverflowOp =
111f47a313eSPhilip Reames B.CreateBinaryIntrinsic(Intrinsic::sadd_with_overflow, LHS, RHS);
112f47a313eSPhilip Reames Checks.push_back(B.CreateExtractValue(OverflowOp, 1));
113f47a313eSPhilip Reames }
114f47a313eSPhilip Reames if (I.hasNoUnsignedWrap()) {
115f47a313eSPhilip Reames auto *OverflowOp =
116f47a313eSPhilip Reames B.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow, LHS, RHS);
117f47a313eSPhilip Reames Checks.push_back(B.CreateExtractValue(OverflowOp, 1));
118f47a313eSPhilip Reames }
119f47a313eSPhilip Reames break;
120f47a313eSPhilip Reames }
121f47a313eSPhilip Reames case Instruction::Sub: {
122f47a313eSPhilip Reames if (I.hasNoSignedWrap()) {
123f47a313eSPhilip Reames auto *OverflowOp =
124f47a313eSPhilip Reames B.CreateBinaryIntrinsic(Intrinsic::ssub_with_overflow, LHS, RHS);
125f47a313eSPhilip Reames Checks.push_back(B.CreateExtractValue(OverflowOp, 1));
126f47a313eSPhilip Reames }
127f47a313eSPhilip Reames if (I.hasNoUnsignedWrap()) {
128f47a313eSPhilip Reames auto *OverflowOp =
129f47a313eSPhilip Reames B.CreateBinaryIntrinsic(Intrinsic::usub_with_overflow, LHS, RHS);
130f47a313eSPhilip Reames Checks.push_back(B.CreateExtractValue(OverflowOp, 1));
131f47a313eSPhilip Reames }
132f47a313eSPhilip Reames break;
133f47a313eSPhilip Reames }
134f47a313eSPhilip Reames case Instruction::Mul: {
135f47a313eSPhilip Reames if (I.hasNoSignedWrap()) {
136f47a313eSPhilip Reames auto *OverflowOp =
137f47a313eSPhilip Reames B.CreateBinaryIntrinsic(Intrinsic::smul_with_overflow, LHS, RHS);
138f47a313eSPhilip Reames Checks.push_back(B.CreateExtractValue(OverflowOp, 1));
139f47a313eSPhilip Reames }
140f47a313eSPhilip Reames if (I.hasNoUnsignedWrap()) {
141f47a313eSPhilip Reames auto *OverflowOp =
142f47a313eSPhilip Reames B.CreateBinaryIntrinsic(Intrinsic::umul_with_overflow, LHS, RHS);
143f47a313eSPhilip Reames Checks.push_back(B.CreateExtractValue(OverflowOp, 1));
144f47a313eSPhilip Reames }
145f47a313eSPhilip Reames break;
146f47a313eSPhilip Reames }
1473b38b925SPhilip Reames case Instruction::UDiv: {
1483b38b925SPhilip Reames if (I.isExact()) {
1493b38b925SPhilip Reames auto *Check =
1503b38b925SPhilip Reames B.CreateICmp(ICmpInst::ICMP_NE, B.CreateURem(LHS, RHS),
1513b38b925SPhilip Reames ConstantInt::get(LHS->getType(), 0));
1523b38b925SPhilip Reames Checks.push_back(Check);
1533b38b925SPhilip Reames }
1543b38b925SPhilip Reames break;
1553b38b925SPhilip Reames }
1563b38b925SPhilip Reames case Instruction::SDiv: {
1573b38b925SPhilip Reames if (I.isExact()) {
1583b38b925SPhilip Reames auto *Check =
1593b38b925SPhilip Reames B.CreateICmp(ICmpInst::ICMP_NE, B.CreateSRem(LHS, RHS),
1603b38b925SPhilip Reames ConstantInt::get(LHS->getType(), 0));
1613b38b925SPhilip Reames Checks.push_back(Check);
1623b38b925SPhilip Reames }
1633b38b925SPhilip Reames break;
1643b38b925SPhilip Reames }
1653dbd7e98SPhilip Reames case Instruction::AShr:
1663dbd7e98SPhilip Reames case Instruction::LShr:
1673dbd7e98SPhilip Reames case Instruction::Shl: {
1683dbd7e98SPhilip Reames Value *ShiftCheck =
1693dbd7e98SPhilip Reames B.CreateICmp(ICmpInst::ICMP_UGE, RHS,
1703dbd7e98SPhilip Reames ConstantInt::get(RHS->getType(),
1713dbd7e98SPhilip Reames LHS->getType()->getScalarSizeInBits()));
1723dbd7e98SPhilip Reames Checks.push_back(ShiftCheck);
1733dbd7e98SPhilip Reames break;
1743dbd7e98SPhilip Reames }
175f47a313eSPhilip Reames };
176f47a313eSPhilip Reames }
177f47a313eSPhilip Reames
178463513e9SPhilip Reames /// Given an instruction which can produce poison on non-poison inputs
179463513e9SPhilip Reames /// (i.e. canCreatePoison returns true), generate runtime checks to produce
180463513e9SPhilip Reames /// boolean indicators of when poison would result.
generateCreationChecks(Instruction & I,SmallVectorImpl<Value * > & Checks)181463513e9SPhilip Reames static void generateCreationChecks(Instruction &I,
182463513e9SPhilip Reames SmallVectorImpl<Value*> &Checks) {
183f47a313eSPhilip Reames IRBuilder<> B(&I);
1843dbd7e98SPhilip Reames if (isa<BinaryOperator>(I) && !I.getType()->isVectorTy())
185463513e9SPhilip Reames generateCreationChecksForBinOp(I, Checks);
1863dbd7e98SPhilip Reames
187bc93c2d7SMarek Kurdej // Handle non-binops separately
1883dbd7e98SPhilip Reames switch (I.getOpcode()) {
1893dbd7e98SPhilip Reames default:
19075ca7127SPhilip Reames // Note there are a couple of missing cases here, once implemented, this
19175ca7127SPhilip Reames // should become an llvm_unreachable.
1923dbd7e98SPhilip Reames break;
1933dbd7e98SPhilip Reames case Instruction::ExtractElement: {
1943dbd7e98SPhilip Reames Value *Vec = I.getOperand(0);
1957ca56c90SChristopher Tetreault auto *VecVTy = dyn_cast<FixedVectorType>(Vec->getType());
1967ca56c90SChristopher Tetreault if (!VecVTy)
1973dbd7e98SPhilip Reames break;
1983dbd7e98SPhilip Reames Value *Idx = I.getOperand(1);
1993bebf028SChristopher Tetreault unsigned NumElts = VecVTy->getNumElements();
2003dbd7e98SPhilip Reames Value *Check =
2013dbd7e98SPhilip Reames B.CreateICmp(ICmpInst::ICMP_UGE, Idx,
2023dbd7e98SPhilip Reames ConstantInt::get(Idx->getType(), NumElts));
2033dbd7e98SPhilip Reames Checks.push_back(Check);
2043dbd7e98SPhilip Reames break;
2053dbd7e98SPhilip Reames }
2063dbd7e98SPhilip Reames case Instruction::InsertElement: {
2073dbd7e98SPhilip Reames Value *Vec = I.getOperand(0);
2087ca56c90SChristopher Tetreault auto *VecVTy = dyn_cast<FixedVectorType>(Vec->getType());
2097ca56c90SChristopher Tetreault if (!VecVTy)
2103dbd7e98SPhilip Reames break;
2113dbd7e98SPhilip Reames Value *Idx = I.getOperand(2);
2123bebf028SChristopher Tetreault unsigned NumElts = VecVTy->getNumElements();
2133dbd7e98SPhilip Reames Value *Check =
2143dbd7e98SPhilip Reames B.CreateICmp(ICmpInst::ICMP_UGE, Idx,
2153dbd7e98SPhilip Reames ConstantInt::get(Idx->getType(), NumElts));
2163dbd7e98SPhilip Reames Checks.push_back(Check);
2173dbd7e98SPhilip Reames break;
2183dbd7e98SPhilip Reames }
2193dbd7e98SPhilip Reames };
220f47a313eSPhilip Reames }
221f47a313eSPhilip Reames
getPoisonFor(DenseMap<Value *,Value * > & ValToPoison,Value * V)222f47a313eSPhilip Reames static Value *getPoisonFor(DenseMap<Value *, Value *> &ValToPoison, Value *V) {
223f47a313eSPhilip Reames auto Itr = ValToPoison.find(V);
224f47a313eSPhilip Reames if (Itr != ValToPoison.end())
225f47a313eSPhilip Reames return Itr->second;
226f47a313eSPhilip Reames if (isa<Constant>(V)) {
227f47a313eSPhilip Reames return ConstantInt::getFalse(V->getContext());
228f47a313eSPhilip Reames }
229f47a313eSPhilip Reames // Return false for unknwon values - this implements a non-strict mode where
230f47a313eSPhilip Reames // unhandled IR constructs are simply considered to never produce poison. At
231f47a313eSPhilip Reames // some point in the future, we probably want a "strict mode" for testing if
232f47a313eSPhilip Reames // nothing else.
233f47a313eSPhilip Reames return ConstantInt::getFalse(V->getContext());
234f47a313eSPhilip Reames }
235f47a313eSPhilip Reames
CreateAssert(IRBuilder<> & B,Value * Cond)236f47a313eSPhilip Reames static void CreateAssert(IRBuilder<> &B, Value *Cond) {
237f47a313eSPhilip Reames assert(Cond->getType()->isIntegerTy(1));
238f47a313eSPhilip Reames if (auto *CI = dyn_cast<ConstantInt>(Cond))
239f47a313eSPhilip Reames if (CI->isAllOnesValue())
240f47a313eSPhilip Reames return;
241f47a313eSPhilip Reames
242f47a313eSPhilip Reames Module *M = B.GetInsertBlock()->getModule();
243f47a313eSPhilip Reames M->getOrInsertFunction("__poison_checker_assert",
244f47a313eSPhilip Reames Type::getVoidTy(M->getContext()),
245f47a313eSPhilip Reames Type::getInt1Ty(M->getContext()));
246f47a313eSPhilip Reames Function *TrapFunc = M->getFunction("__poison_checker_assert");
247f47a313eSPhilip Reames B.CreateCall(TrapFunc, Cond);
248f47a313eSPhilip Reames }
249f47a313eSPhilip Reames
CreateAssertNot(IRBuilder<> & B,Value * Cond)250f47a313eSPhilip Reames static void CreateAssertNot(IRBuilder<> &B, Value *Cond) {
251f47a313eSPhilip Reames assert(Cond->getType()->isIntegerTy(1));
252f47a313eSPhilip Reames CreateAssert(B, B.CreateNot(Cond));
253f47a313eSPhilip Reames }
254f47a313eSPhilip Reames
rewrite(Function & F)255f47a313eSPhilip Reames static bool rewrite(Function &F) {
256f47a313eSPhilip Reames auto * const Int1Ty = Type::getInt1Ty(F.getContext());
257f47a313eSPhilip Reames
258f47a313eSPhilip Reames DenseMap<Value *, Value *> ValToPoison;
259f47a313eSPhilip Reames
260f47a313eSPhilip Reames for (BasicBlock &BB : F)
261f47a313eSPhilip Reames for (auto I = BB.begin(); isa<PHINode>(&*I); I++) {
262f47a313eSPhilip Reames auto *OldPHI = cast<PHINode>(&*I);
263e5f602d8SJuneyoung Lee auto *NewPHI = PHINode::Create(Int1Ty, OldPHI->getNumIncomingValues());
264f47a313eSPhilip Reames for (unsigned i = 0; i < OldPHI->getNumIncomingValues(); i++)
265f47a313eSPhilip Reames NewPHI->addIncoming(UndefValue::get(Int1Ty),
266f47a313eSPhilip Reames OldPHI->getIncomingBlock(i));
267f47a313eSPhilip Reames NewPHI->insertBefore(OldPHI);
268f47a313eSPhilip Reames ValToPoison[OldPHI] = NewPHI;
269f47a313eSPhilip Reames }
270f47a313eSPhilip Reames
271f47a313eSPhilip Reames for (BasicBlock &BB : F)
272f47a313eSPhilip Reames for (Instruction &I : BB) {
273f47a313eSPhilip Reames if (isa<PHINode>(I)) continue;
274f47a313eSPhilip Reames
275f47a313eSPhilip Reames IRBuilder<> B(cast<Instruction>(&I));
276a6548d04SPhilip Reames
277a6548d04SPhilip Reames // Note: There are many more sources of documented UB, but this pass only
278a6548d04SPhilip Reames // attempts to find UB triggered by propagation of poison.
279f753f5b0SJuneyoung Lee SmallPtrSet<const Value *, 4> NonPoisonOps;
280f753f5b0SJuneyoung Lee getGuaranteedNonPoisonOps(&I, NonPoisonOps);
281f753f5b0SJuneyoung Lee for (const Value *Op : NonPoisonOps)
282f753f5b0SJuneyoung Lee CreateAssertNot(B, getPoisonFor(ValToPoison, const_cast<Value *>(Op)));
283f47a313eSPhilip Reames
284f47a313eSPhilip Reames if (LocalCheck)
285f47a313eSPhilip Reames if (auto *RI = dyn_cast<ReturnInst>(&I))
286f47a313eSPhilip Reames if (RI->getNumOperands() != 0) {
287f47a313eSPhilip Reames Value *Op = RI->getOperand(0);
288f47a313eSPhilip Reames CreateAssertNot(B, getPoisonFor(ValToPoison, Op));
289f47a313eSPhilip Reames }
290f47a313eSPhilip Reames
291f47a313eSPhilip Reames SmallVector<Value*, 4> Checks;
292*25ce1e04SJuneyoung Lee if (propagatesPoison(cast<Operator>(&I)))
293f47a313eSPhilip Reames for (Value *V : I.operands())
294f47a313eSPhilip Reames Checks.push_back(getPoisonFor(ValToPoison, V));
295f47a313eSPhilip Reames
2960a6aee51SJuneyoung Lee if (canCreatePoison(cast<Operator>(&I)))
297463513e9SPhilip Reames generateCreationChecks(I, Checks);
298f47a313eSPhilip Reames ValToPoison[&I] = buildOrChain(B, Checks);
299f47a313eSPhilip Reames }
300f47a313eSPhilip Reames
301f47a313eSPhilip Reames for (BasicBlock &BB : F)
302f47a313eSPhilip Reames for (auto I = BB.begin(); isa<PHINode>(&*I); I++) {
303f47a313eSPhilip Reames auto *OldPHI = cast<PHINode>(&*I);
304f47a313eSPhilip Reames if (!ValToPoison.count(OldPHI))
305f47a313eSPhilip Reames continue; // skip the newly inserted phis
306f47a313eSPhilip Reames auto *NewPHI = cast<PHINode>(ValToPoison[OldPHI]);
307f47a313eSPhilip Reames for (unsigned i = 0; i < OldPHI->getNumIncomingValues(); i++) {
308f47a313eSPhilip Reames auto *OldVal = OldPHI->getIncomingValue(i);
309f47a313eSPhilip Reames NewPHI->setIncomingValue(i, getPoisonFor(ValToPoison, OldVal));
310f47a313eSPhilip Reames }
311f47a313eSPhilip Reames }
312f47a313eSPhilip Reames return true;
313f47a313eSPhilip Reames }
314f47a313eSPhilip Reames
315f47a313eSPhilip Reames
run(Module & M,ModuleAnalysisManager & AM)316f47a313eSPhilip Reames PreservedAnalyses PoisonCheckingPass::run(Module &M,
317f47a313eSPhilip Reames ModuleAnalysisManager &AM) {
318f47a313eSPhilip Reames bool Changed = false;
319f47a313eSPhilip Reames for (auto &F : M)
320f47a313eSPhilip Reames Changed |= rewrite(F);
321f47a313eSPhilip Reames
322f47a313eSPhilip Reames return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
323f47a313eSPhilip Reames }
324f47a313eSPhilip Reames
run(Function & F,FunctionAnalysisManager & AM)325f47a313eSPhilip Reames PreservedAnalyses PoisonCheckingPass::run(Function &F,
326f47a313eSPhilip Reames FunctionAnalysisManager &AM) {
327f47a313eSPhilip Reames return rewrite(F) ? PreservedAnalyses::none() : PreservedAnalyses::all();
328f47a313eSPhilip Reames }
329f47a313eSPhilip Reames
330f47a313eSPhilip Reames /* Major TODO Items:
331f47a313eSPhilip Reames - Control dependent poison UB
332f47a313eSPhilip Reames - Strict mode - (i.e. must analyze every operand)
333f47a313eSPhilip Reames - Poison through memory
334f47a313eSPhilip Reames - Function ABIs
335a6548d04SPhilip Reames - Full coverage of intrinsics, etc.. (ouch)
336f47a313eSPhilip Reames
337a6548d04SPhilip Reames Instructions w/Unclear Semantics:
338a6548d04SPhilip Reames - shufflevector - It would seem reasonable for an out of bounds mask element
339a6548d04SPhilip Reames to produce poison, but the LangRef does not state.
340a6548d04SPhilip Reames - all binary ops w/vector operands - The likely interpretation would be that
341a6548d04SPhilip Reames any element overflowing should produce poison for the entire result, but
342a6548d04SPhilip Reames the LangRef does not state.
343a6548d04SPhilip Reames - Floating point binary ops w/fmf flags other than (nnan, noinfs). It seems
344a6548d04SPhilip Reames strange that only certian flags should be documented as producing poison.
345a6548d04SPhilip Reames
346a6548d04SPhilip Reames Cases of clear poison semantics not yet implemented:
347a6548d04SPhilip Reames - Exact flags on ashr/lshr produce poison
348a6548d04SPhilip Reames - NSW/NUW flags on shl produce poison
349a6548d04SPhilip Reames - Inbounds flag on getelementptr produce poison
350a6548d04SPhilip Reames - fptosi/fptoui (out of bounds input) produce poison
351a6548d04SPhilip Reames - Scalable vector types for insertelement/extractelement
352a6548d04SPhilip Reames - Floating point binary ops w/fmf nnan/noinfs flags produce poison
353f47a313eSPhilip Reames */
354