ATTR_KIND_STRICT_FP = 54,
ATTR_KIND_SANITIZE_HWADDRESS = 55,
ATTR_KIND_NOCF_CHECK = 56,
+ ATTR_KIND_OPT_FOR_FUZZING = 57,
};
enum ComdatSelectionKindCodes {
/// Function doesn't unwind stack.
def NoUnwind : EnumAttr<"nounwind">;
+/// Select optimizations for best fuzzing signal.
+def OptForFuzzing : EnumAttr<"optforfuzzing">;
+
/// opt_size.
def OptimizeForSize : EnumAttr<"optsize">;
KEYWORD(noreturn);
KEYWORD(nocf_check);
KEYWORD(nounwind);
+ KEYWORD(optforfuzzing);
KEYWORD(optnone);
KEYWORD(optsize);
KEYWORD(readnone);
case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break;
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
+ case lltok::kw_optforfuzzing:
+ B.addAttribute(Attribute::OptForFuzzing); break;
case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break;
case lltok::kw_optsize: B.addAttribute(Attribute::OptimizeForSize); break;
case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break;
case lltok::kw_noreturn:
case lltok::kw_nocf_check:
case lltok::kw_nounwind:
+ case lltok::kw_optforfuzzing:
case lltok::kw_optnone:
case lltok::kw_optsize:
case lltok::kw_returns_twice:
case lltok::kw_noreturn:
case lltok::kw_nocf_check:
case lltok::kw_nounwind:
+ case lltok::kw_optforfuzzing:
case lltok::kw_optnone:
case lltok::kw_optsize:
case lltok::kw_returns_twice:
kw_noreturn,
kw_nocf_check,
kw_nounwind,
+ kw_optforfuzzing,
kw_optnone,
kw_optsize,
kw_readnone,
case Attribute::StrictFP: return 1ULL << 55;
case Attribute::SanitizeHWAddress: return 1ULL << 56;
case Attribute::NoCfCheck: return 1ULL << 57;
+ case Attribute::OptForFuzzing: return 1ULL << 58;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
return Attribute::NoCfCheck;
case bitc::ATTR_KIND_NO_UNWIND:
return Attribute::NoUnwind;
+ case bitc::ATTR_KIND_OPT_FOR_FUZZING:
+ return Attribute::OptForFuzzing;
case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE:
return Attribute::OptimizeForSize;
case bitc::ATTR_KIND_OPTIMIZE_NONE:
return bitc::ATTR_KIND_NOCF_CHECK;
case Attribute::NoUnwind:
return bitc::ATTR_KIND_NO_UNWIND;
+ case Attribute::OptForFuzzing:
+ return bitc::ATTR_KIND_OPT_FOR_FUZZING;
case Attribute::OptimizeForSize:
return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE;
case Attribute::OptimizeNone:
return "norecurse";
if (hasAttribute(Attribute::NoUnwind))
return "nounwind";
+ if (hasAttribute(Attribute::OptForFuzzing))
+ return "optforfuzzing";
if (hasAttribute(Attribute::OptimizeNone))
return "optnone";
if (hasAttribute(Attribute::OptimizeForSize))
case Attribute::Builtin:
case Attribute::NoBuiltin:
case Attribute::Cold:
+ case Attribute::OptForFuzzing:
case Attribute::OptimizeNone:
case Attribute::JumpTable:
case Attribute::Convergent:
.Case("nocf_check", Attribute::NoCfCheck)
.Case("norecurse", Attribute::NoRecurse)
.Case("nounwind", Attribute::NoUnwind)
+ .Case("optforfuzzing", Attribute::OptForFuzzing)
.Case("optnone", Attribute::OptimizeNone)
.Case("optsize", Attribute::OptimizeForSize)
.Case("readnone", Attribute::ReadNone)
case Attribute::NonLazyBind:
case Attribute::NoRedZone:
case Attribute::NoUnwind:
+ case Attribute::OptForFuzzing:
case Attribute::OptimizeNone:
case Attribute::OptimizeForSize:
case Attribute::SafeStack:
// dependence information for this check, but simplifycfg can't keep it up
// to date, and this catches most of the cases we care about anyway.
BasicBlock *BB = PN->getParent();
+ const Function *Fn = BB->getParent();
+ if (Fn && Fn->hasFnAttribute(Attribute::OptForFuzzing))
+ return false;
+
BasicBlock *IfTrue, *IfFalse;
Value *IfCond = GetIfCondition(BB, IfTrue, IfFalse);
if (!IfCond ||
bool SimplifyCFGOpt::SimplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) {
BasicBlock *BB = BI->getParent();
+ const Function *Fn = BB->getParent();
+ if (Fn && Fn->hasFnAttribute(Attribute::OptForFuzzing))
+ return false;
// Conditional branch
if (isValueEqualityComparison(BI)) {
--- /dev/null
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+define i32 @foo(i32 %x) optforfuzzing {
+entry:
+ %x.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ %0 = load i32, i32* %x.addr, align 4
+ %cmp = icmp sgt i32 %0, 16
+ br i1 %cmp, label %land.rhs, label %land.end
+
+land.rhs:
+ %1 = load i32, i32* %x.addr, align 4
+ %cmp1 = icmp slt i32 %1, 32
+ br label %land.end
+
+land.end:
+ %2 = phi i1 [ false, %entry ], [ %cmp1, %land.rhs ]
+ %conv = zext i1 %2 to i32
+ ret i32 %conv
+
+; CHECK-LABEL: define i32 @foo(i32 %x)
+; CHECK: br i1 %cmp, label %land.rhs, label %land.end
+; CHECK-LABEL: land.rhs:
+; CHECK: br label %land.end
+; CHECK-LABEL: land.end:
+; CHECK: phi {{.*}} %entry {{.*}} %land.rhs
+}
+
+define i32 @bar(i32 %x) {
+entry:
+ %x.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ %0 = load i32, i32* %x.addr, align 4
+ %cmp = icmp sgt i32 %0, 16
+ br i1 %cmp, label %land.rhs, label %land.end
+
+land.rhs:
+ %1 = load i32, i32* %x.addr, align 4
+ %cmp1 = icmp slt i32 %1, 32
+ br label %land.end
+
+land.end:
+ %2 = phi i1 [ false, %entry ], [ %cmp1, %land.rhs ]
+ %conv = zext i1 %2 to i32
+ ret i32 %conv
+
+; CHECK-LABEL: define i32 @bar(i32 %x)
+; CHECK-NOT: br
+}