Skip to content

Commit c2f465f

Browse files
committed
Add AMDGPU overflow intrinsic fuzzing
1 parent 9c27019 commit c2f465f

2 files changed

Lines changed: 98 additions & 5 deletions

File tree

‎amdgpu/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ rare signed division/remainder by proven-positive divisors,
4949
`i64` subexpressions truncated to `i32`, `<2 x i32>` / `<4 x i32>` vector
5050
subexpressions and narrow `<4/8 x i8>` / `<4/8 x i16>` vector subexpressions
5151
reduced back to `i32`, explicit `i1` boolean subexpressions reduced back to
52-
`i32`, and LLVM bit, min/max, saturation, absolute-value, and funnel-shift
53-
intrinsics. It also emits a finite scalar FP subset by masking
52+
`i32`, and LLVM bit, min/max, saturation, absolute-value, funnel-shift, and
53+
integer overflow intrinsics. It also emits a finite scalar FP subset by masking
5454
inputs to small nonnegative integers, converting with `uitofp`, using exact
5555
`fadd` / `fmul` / `fcmp` / `select` shapes, and converting back with in-range
5656
`fptoui`; a signed variant uses small sign-extended integers, `sitofp`,

‎amdgpu/fuzzer/llvm_amdgpu_diff_fuzzer.cpp‎

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,12 @@ bool isAllowedIRIntrinsic(Intrinsic::ID ID) {
411411
case Intrinsic::usub_sat:
412412
case Intrinsic::sadd_sat:
413413
case Intrinsic::ssub_sat:
414+
case Intrinsic::uadd_with_overflow:
415+
case Intrinsic::usub_with_overflow:
416+
case Intrinsic::umul_with_overflow:
417+
case Intrinsic::sadd_with_overflow:
418+
case Intrinsic::ssub_with_overflow:
419+
case Intrinsic::smul_with_overflow:
414420
case Intrinsic::fshl:
415421
case Intrinsic::fshr:
416422
return true;
@@ -623,6 +629,41 @@ bool isValidVectorInstruction(const Instruction &I) {
623629
return true;
624630
}
625631

632+
bool isOverflowIntrinsic(Intrinsic::ID ID) {
633+
switch (ID) {
634+
case Intrinsic::uadd_with_overflow:
635+
case Intrinsic::usub_with_overflow:
636+
case Intrinsic::umul_with_overflow:
637+
case Intrinsic::sadd_with_overflow:
638+
case Intrinsic::ssub_with_overflow:
639+
case Intrinsic::smul_with_overflow:
640+
return true;
641+
default:
642+
return false;
643+
}
644+
}
645+
646+
bool isValidAggregateInstruction(const Instruction &I) {
647+
const auto *Extract = dyn_cast<ExtractValueInst>(&I);
648+
if (!Extract)
649+
return true;
650+
if (Extract->getNumIndices() != 1)
651+
return false;
652+
const auto *Call = dyn_cast<CallInst>(Extract->getAggregateOperand());
653+
if (!Call)
654+
return false;
655+
const Function *Callee = Call->getCalledFunction();
656+
if (!Callee || !Callee->isIntrinsic() ||
657+
!isOverflowIntrinsic(Callee->getIntrinsicID()))
658+
return false;
659+
unsigned Index = *Extract->idx_begin();
660+
if (Index == 0)
661+
return Extract->getType()->isIntegerTy(32);
662+
if (Index == 1)
663+
return Extract->getType()->isIntegerTy(1);
664+
return false;
665+
}
666+
626667
bool isValidFPConversionInstruction(const Instruction &I) {
627668
const auto *UIToFP = dyn_cast<UIToFPInst>(&I);
628669
if (!UIToFP)
@@ -638,7 +679,7 @@ bool isValidFPConversionInstruction(const Instruction &I) {
638679
}
639680

640681
bool isAllowedIRInstruction(const Instruction &I) {
641-
if (isa<InsertElementInst, ExtractElementInst>(&I))
682+
if (isa<InsertElementInst, ExtractElementInst, ExtractValueInst>(&I))
642683
return true;
643684
if (isa<BranchInst, SwitchInst, ReturnInst, LoadInst, StoreInst,
644685
GetElementPtrInst, ZExtInst, SExtInst, TruncInst, UIToFPInst,
@@ -1484,6 +1525,7 @@ bool validateIRCorpusModule(Module &M) {
14841525
for (Instruction &I : BB)
14851526
if (!isAllowedIRInstruction(I) ||
14861527
!isValidVectorInstruction(I) ||
1528+
!isValidAggregateInstruction(I) ||
14871529
!isValidFPConversionInstruction(I) ||
14881530
!isValidLoopControlInstruction(I) ||
14891531
(!AllowM019 && triggersM019HighBitOrXor(I)) ||
@@ -2382,6 +2424,42 @@ Value *emitRandomFiniteSignedFPInstruction(IRBuilder<NoFolder> &B, Value *A,
23822424
}
23832425
}
23842426

2427+
Intrinsic::ID randomOverflowIntrinsic(std::minstd_rand &Gen) {
2428+
static constexpr std::array<Intrinsic::ID, 6> IDs = {
2429+
Intrinsic::uadd_with_overflow, Intrinsic::usub_with_overflow,
2430+
Intrinsic::umul_with_overflow, Intrinsic::sadd_with_overflow,
2431+
Intrinsic::ssub_with_overflow, Intrinsic::smul_with_overflow};
2432+
return IDs[Gen() % IDs.size()];
2433+
}
2434+
2435+
Value *emitRandomOverflowInstruction(IRBuilder<NoFolder> &B, Module &M,
2436+
Value *A, Value *Bv,
2437+
std::minstd_rand &Gen,
2438+
StringRef NamePrefix) {
2439+
LLVMContext &Ctx = M.getContext();
2440+
Type *I32 = Type::getInt32Ty(Ctx);
2441+
FunctionCallee Fn =
2442+
Intrinsic::getOrInsertDeclaration(&M, randomOverflowIntrinsic(Gen), {I32});
2443+
Value *Pair = B.CreateCall(Fn, {A, Bv}, Twine(NamePrefix) + ".call");
2444+
Value *Result = B.CreateExtractValue(Pair, {0}, Twine(NamePrefix) + ".value");
2445+
Value *Overflow =
2446+
B.CreateExtractValue(Pair, {1}, Twine(NamePrefix) + ".overflow");
2447+
Value *OverflowI32 =
2448+
B.CreateZExt(Overflow, I32, Twine(NamePrefix) + ".overflow.i32");
2449+
switch (Gen() % 5) {
2450+
case 0:
2451+
return Result;
2452+
case 1:
2453+
return B.CreateXor(Result, OverflowI32, Twine(NamePrefix) + ".xor");
2454+
case 2:
2455+
return B.CreateAdd(Result, OverflowI32, Twine(NamePrefix) + ".add");
2456+
case 3:
2457+
return B.CreateSub(Result, OverflowI32, Twine(NamePrefix) + ".sub");
2458+
default:
2459+
return B.CreateSelect(Overflow, Bv, Result, Twine(NamePrefix) + ".select");
2460+
}
2461+
}
2462+
23852463
Value *emitSafeSignedDivRemInstruction(IRBuilder<NoFolder> &B, Value *A,
23862464
Value *Bv, bool IsRem,
23872465
StringRef NamePrefix) {
@@ -2448,7 +2526,7 @@ Value *emitRandomIRInstruction(IRBuilder<NoFolder> &B, Module &M,
24482526
Type *I32 = Type::getInt32Ty(Ctx);
24492527
Value *A = Current;
24502528
Value *Bv = chooseI32Value(InsertPt, Gen);
2451-
switch (Gen() % 82) {
2529+
switch (Gen() % 88) {
24522530
case 0:
24532531
return B.CreateAdd(A, Bv, "fuzz.add");
24542532
case 1:
@@ -2606,6 +2684,13 @@ Value *emitRandomIRInstruction(IRBuilder<NoFolder> &B, Module &M,
26062684
case 66:
26072685
case 67:
26082686
return emitRandomFiniteHalfFPInstruction(B, A, Bv, Gen, "fuzz.fp16");
2687+
case 68:
2688+
case 69:
2689+
case 70:
2690+
case 71:
2691+
case 72:
2692+
case 73:
2693+
return emitRandomOverflowInstruction(B, M, A, Bv, Gen, "fuzz.overflow");
26092694
default:
26102695
switch (Gen() % 5) {
26112696
case 0:
@@ -2640,7 +2725,7 @@ Value *emitRandomCFGArmInstruction(IRBuilder<NoFolder> &B, Module &M, Value *A,
26402725
Type *I8 = Type::getInt8Ty(Ctx);
26412726
Type *I16 = Type::getInt16Ty(Ctx);
26422727
Type *I32 = Type::getInt32Ty(Ctx);
2643-
switch (Gen() % 68) {
2728+
switch (Gen() % 74) {
26442729
case 0:
26452730
return B.CreateAdd(A, Bv, "fuzz.cfg.add");
26462731
case 1:
@@ -2785,6 +2870,14 @@ Value *emitRandomCFGArmInstruction(IRBuilder<NoFolder> &B, Module &M, Value *A,
27852870
case 58:
27862871
case 59:
27872872
return emitRandomFiniteHalfFPInstruction(B, A, Bv, Gen, "fuzz.cfg.fp16");
2873+
case 60:
2874+
case 61:
2875+
case 62:
2876+
case 63:
2877+
case 64:
2878+
case 65:
2879+
return emitRandomOverflowInstruction(B, M, A, Bv, Gen,
2880+
"fuzz.cfg.overflow");
27882881
default:
27892882
switch (Gen() % 5) {
27902883
case 0:

0 commit comments

Comments
 (0)