From 236cdaf84c684a985fa501721bf99b93ce2614da Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Thu, 22 Mar 2018 17:07:51 +0000 Subject: [PATCH] [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 --- llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 + llvm/include/llvm/IR/Attributes.td | 3 ++ llvm/lib/AsmParser/LLLexer.cpp | 1 + llvm/lib/AsmParser/LLParser.cpp | 4 ++ llvm/lib/AsmParser/LLToken.h | 1 + llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 3 ++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 + llvm/lib/IR/Attributes.cpp | 2 + llvm/lib/IR/Verifier.cpp | 1 + llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp | 1 + llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 + llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 7 ++++ .../test/Transforms/SimplifyCFG/opt-for-fuzzing.ll | 49 ++++++++++++++++++++++ 13 files changed, 76 insertions(+) create mode 100644 llvm/test/Transforms/SimplifyCFG/opt-for-fuzzing.ll diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 1519536..f3500e1 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -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 { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 5dd4f3f..554f0df 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -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">; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index e315760..645d9aa 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -650,6 +650,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(noreturn); KEYWORD(nocf_check); KEYWORD(nounwind); + KEYWORD(optforfuzzing); KEYWORD(optnone); KEYWORD(optsize); KEYWORD(readnone); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 1c607de..d59b21d 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -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: diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index 3ef44d4..d24f74a 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -201,6 +201,7 @@ enum Kind { kw_noreturn, kw_nocf_check, kw_nounwind, + kw_optforfuzzing, kw_optnone, kw_optsize, kw_readnone, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 74b57a8..5867db4 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -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: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index d82101b..b43a26f 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -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: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index 0aea24f..1a060ba 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -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)) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index aec5c68..4cb1661 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -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: diff --git a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp index d10b4f4a..f7cdd41 100644 --- a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -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) diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index ef39f21..d87eccf 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -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: diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 685fdb7..5dc9d2c 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -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)) { diff --git a/llvm/test/Transforms/SimplifyCFG/opt-for-fuzzing.ll b/llvm/test/Transforms/SimplifyCFG/opt-for-fuzzing.ll new file mode 100644 index 0000000..429f4a3 --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/opt-for-fuzzing.ll @@ -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 +} -- 2.7.4