OSDN Git Service

[PoisonCheker] Support for out of bounds operands on shifts + insert/extractelement
authorPhilip Reames <listmail@philipreames.com>
Tue, 9 Jul 2019 19:26:12 +0000 (19:26 +0000)
committerPhilip Reames <listmail@philipreames.com>
Tue, 9 Jul 2019 19:26:12 +0000 (19:26 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365543 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Instrumentation/PoisonChecking.cpp
test/Instrumentation/PoisonChecking/basic-flag-validation.ll

index 8e4c046..0c4e64b 100644 (file)
@@ -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<Value*, 2> Checks;
-  if (isa<BinaryOperator>(I))
+  if (isa<BinaryOperator>(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);
 }
 
index 9fb4916..d32af40 100644 (file)
@@ -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
+}
+