From d64a701ab437ae1aa2b304ce5e6106a1e3ab91c1 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Tue, 9 Jul 2019 19:26:12 +0000 Subject: [PATCH] [PoisonCheker] Support for out of bounds operands on shifts + insert/extractelement These are sources of poison which don't come from flags, but are clearly documented in the LangRef. Left off support for scalable vectors for the moment, but should be easy to add if anyone is interested. llvm-svn: 365543 --- .../Instrumentation/PoisonChecking.cpp | 42 +++++- .../PoisonChecking/basic-flag-validation.ll | 121 ++++++++++++++++++ 2 files changed, 162 insertions(+), 1 deletion(-) diff --git a/lib/Transforms/Instrumentation/PoisonChecking.cpp b/lib/Transforms/Instrumentation/PoisonChecking.cpp index 8e4c046c9f8..0c4e64bbc54 100644 --- a/lib/Transforms/Instrumentation/PoisonChecking.cpp +++ b/lib/Transforms/Instrumentation/PoisonChecking.cpp @@ -169,14 +169,54 @@ static void generatePoisonChecksForBinOp(Instruction &I, } break; } + case Instruction::AShr: + case Instruction::LShr: + case Instruction::Shl: { + Value *ShiftCheck = + B.CreateICmp(ICmpInst::ICMP_UGE, RHS, + ConstantInt::get(RHS->getType(), + LHS->getType()->getScalarSizeInBits())); + Checks.push_back(ShiftCheck); + break; + } }; } static Value* generatePoisonChecks(Instruction &I) { IRBuilder<> B(&I); SmallVector Checks; - if (isa(I)) + if (isa(I) && !I.getType()->isVectorTy()) generatePoisonChecksForBinOp(I, Checks); + + // Handle non-binops seperately + switch (I.getOpcode()) { + default: + break; + case Instruction::ExtractElement: { + Value *Vec = I.getOperand(0); + if (Vec->getType()->getVectorIsScalable()) + break; + Value *Idx = I.getOperand(1); + unsigned NumElts = Vec->getType()->getVectorNumElements(); + Value *Check = + B.CreateICmp(ICmpInst::ICMP_UGE, Idx, + ConstantInt::get(Idx->getType(), NumElts)); + Checks.push_back(Check); + break; + } + case Instruction::InsertElement: { + Value *Vec = I.getOperand(0); + if (Vec->getType()->getVectorIsScalable()) + break; + Value *Idx = I.getOperand(2); + unsigned NumElts = Vec->getType()->getVectorNumElements(); + Value *Check = + B.CreateICmp(ICmpInst::ICMP_UGE, Idx, + ConstantInt::get(Idx->getType(), NumElts)); + Checks.push_back(Check); + break; + } + }; return buildOrChain(B, Checks); } diff --git a/test/Instrumentation/PoisonChecking/basic-flag-validation.ll b/test/Instrumentation/PoisonChecking/basic-flag-validation.ll index 9fb491653fa..d32af40f3b0 100644 --- a/test/Instrumentation/PoisonChecking/basic-flag-validation.ll +++ b/test/Instrumentation/PoisonChecking/basic-flag-validation.ll @@ -199,3 +199,124 @@ define i32 @udiv_exact(i32 %a, i32 %b) { %res = udiv exact i32 %a, %b ret i32 %res } + +define i32 @ashr_noflags(i32 %a, i32 %b) { +; CHECK-LABEL: @ashr_noflags( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = ashr i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = ashr i32 %a, %b + ret i32 %res +} + +define i32 @ashr_exact(i32 %a, i32 %b) { +; CHECK-LABEL: @ashr_exact( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = ashr exact i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = ashr exact i32 %a, %b + ret i32 %res +} + +define i32 @lshr_noflags(i32 %a, i32 %b) { +; CHECK-LABEL: @lshr_noflags( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = lshr i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = lshr i32 %a, %b + ret i32 %res +} + +define i32 @lshr_exact(i32 %a, i32 %b) { +; CHECK-LABEL: @lshr_exact( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = lshr exact i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = lshr exact i32 %a, %b + ret i32 %res +} + +define i32 @shl_noflags(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_noflags( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = shl i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = shl i32 %a, %b + ret i32 %res +} + +define i32 @shl_nsw(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_nsw( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = shl nsw i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = shl nsw i32 %a, %b + ret i32 %res +} + +define i32 @shl_nuw(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_nuw( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = shl nuw i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = shl nuw i32 %a, %b + ret i32 %res +} + +define i32 @shl_nsw_nuw(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_nsw_nuw( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[B:%.*]], 32 +; CHECK-NEXT: [[RES:%.*]] = shl nuw nsw i32 [[A:%.*]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = shl nsw nuw i32 %a, %b + ret i32 %res +} + +define i32 @extractelement(<4 x i32> %v, i32 %idx) { +; CHECK-LABEL: @extractelement( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[IDX:%.*]], 4 +; CHECK-NEXT: [[RES:%.*]] = extractelement <4 x i32> [[V:%.*]], i32 [[IDX]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret i32 [[RES]] +; + %res = extractelement <4 x i32> %v, i32 %idx + ret i32 %res +} + +define <4 x i32> @insertelement(<4 x i32> %v, i32 %idx, i32 %val) { +; CHECK-LABEL: @insertelement( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[IDX:%.*]], 4 +; CHECK-NEXT: [[RES:%.*]] = insertelement <4 x i32> [[V:%.*]], i32 [[VAL:%.*]], i32 [[IDX]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true +; CHECK-NEXT: call void @__poison_checker_assert(i1 [[TMP2]]) +; CHECK-NEXT: ret <4 x i32> [[RES]] +; + %res = insertelement <4 x i32> %v, i32 %val, i32 %idx + ret <4 x i32> %res +} +