1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

[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
This commit is contained in:
Philip Reames 2019-07-09 19:26:12 +00:00
parent 64a23513ff
commit d64a701ab4
2 changed files with 162 additions and 1 deletions

View 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);
}

View 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
}