mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[SimplifyCFG] Create attribute for fuzzing-specific optimizations.
Summary: When building with libFuzzer, converting control flow to selects or obscuring the original operands of CMPs reduces the effectiveness of libFuzzer's heuristics. This patch provides an attribute to disable or modify certain optimizations for optimal fuzzing signal. Provides a less aggressive alternative to https://reviews.llvm.org/D44057. Reviewers: vitalybuka, davide, arsenm, hfinkel Reviewed By: vitalybuka Subscribers: junbuml, mehdi_amini, wdng, javed.absar, hiraditya, llvm-commits, kcc Differential Revision: https://reviews.llvm.org/D44232 llvm-svn: 328214
This commit is contained in:
parent
c65ff81b00
commit
3102888fd3
@ -588,6 +588,7 @@ enum AttributeKindCodes {
|
||||
ATTR_KIND_STRICT_FP = 54,
|
||||
ATTR_KIND_SANITIZE_HWADDRESS = 55,
|
||||
ATTR_KIND_NOCF_CHECK = 56,
|
||||
ATTR_KIND_OPT_FOR_FUZZING = 57,
|
||||
};
|
||||
|
||||
enum ComdatSelectionKindCodes {
|
||||
|
@ -112,6 +112,9 @@ def NoCfCheck : EnumAttr<"nocf_check">;
|
||||
/// 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">;
|
||||
|
||||
|
@ -650,6 +650,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(noreturn);
|
||||
KEYWORD(nocf_check);
|
||||
KEYWORD(nounwind);
|
||||
KEYWORD(optforfuzzing);
|
||||
KEYWORD(optnone);
|
||||
KEYWORD(optsize);
|
||||
KEYWORD(readnone);
|
||||
|
@ -1134,6 +1134,8 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
|
||||
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;
|
||||
@ -1471,6 +1473,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
|
||||
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:
|
||||
@ -1565,6 +1568,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
|
||||
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:
|
||||
|
@ -201,6 +201,7 @@ enum Kind {
|
||||
kw_noreturn,
|
||||
kw_nocf_check,
|
||||
kw_nounwind,
|
||||
kw_optforfuzzing,
|
||||
kw_optnone,
|
||||
kw_optsize,
|
||||
kw_readnone,
|
||||
|
@ -1161,6 +1161,7 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
|
||||
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;
|
||||
@ -1343,6 +1344,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
|
||||
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:
|
||||
|
@ -642,6 +642,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
|
||||
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:
|
||||
|
@ -305,6 +305,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
||||
return "norecurse";
|
||||
if (hasAttribute(Attribute::NoUnwind))
|
||||
return "nounwind";
|
||||
if (hasAttribute(Attribute::OptForFuzzing))
|
||||
return "optforfuzzing";
|
||||
if (hasAttribute(Attribute::OptimizeNone))
|
||||
return "optnone";
|
||||
if (hasAttribute(Attribute::OptimizeForSize))
|
||||
|
@ -1430,6 +1430,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
|
||||
case Attribute::Builtin:
|
||||
case Attribute::NoBuiltin:
|
||||
case Attribute::Cold:
|
||||
case Attribute::OptForFuzzing:
|
||||
case Attribute::OptimizeNone:
|
||||
case Attribute::JumpTable:
|
||||
case Attribute::Convergent:
|
||||
|
@ -45,6 +45,7 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) {
|
||||
.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)
|
||||
|
@ -684,6 +684,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
|
||||
case Attribute::NonLazyBind:
|
||||
case Attribute::NoRedZone:
|
||||
case Attribute::NoUnwind:
|
||||
case Attribute::OptForFuzzing:
|
||||
case Attribute::OptimizeNone:
|
||||
case Attribute::OptimizeForSize:
|
||||
case Attribute::SafeStack:
|
||||
|
@ -2273,6 +2273,10 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI,
|
||||
// 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 ||
|
||||
@ -5799,6 +5803,9 @@ static BasicBlock *allPredecessorsComeFromSameSource(BasicBlock *BB) {
|
||||
|
||||
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)) {
|
||||
|
49
test/Transforms/SimplifyCFG/opt-for-fuzzing.ll
Normal file
49
test/Transforms/SimplifyCFG/opt-for-fuzzing.ll
Normal file
@ -0,0 +1,49 @@
|
||||
; 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user