Author: Gui Andrade
Date: 2021-03-04T12:15:12-08:00
New Revision: 10264a1b21aebf75a8102116c9648c3386e8021e
URL:
https://github.com/llvm/llvm-project/commit/10264a1b21aebf75a8102116c9648c3386e8021e
DIFF:
https://github.com/llvm/llvm-project/commit/10264a1b21aebf75a8102116c9648c3386e8021e.diff
LOG: Introduce noundef attribute at call sites for stricter poison analysis
This change adds a new IR noundef attribute, which denotes when a function call
argument or return val may never contain uninitialized bits.
In MemorySanitizer, this attribute enables optimizations which decrease
instrumented code size by up to 17% (measured with an instrumented build of
clang) . I'll introduce the change allowing msan to take advantage of this
information in a separate patch.
Differential Revision: https://reviews.llvm.org/D81678
Added:
clang/test/CodeGen/attr-noundef.cpp
clang/test/CodeGen/indirect-noundef.cpp
Modified:
clang/include/clang/Basic/CodeGenOptions.def
clang/include/clang/Driver/Options.td
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/CodeGenModule.h
Removed:
diff --git a/clang/include/clang/Basic/CodeGenOptions.def
b/clang/include/clang/Basic/CodeGenOptions.def
index 50503dbe4f84..a1db1b101620 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -64,6 +64,7 @@ CODEGENOPT(DisableLifetimeMarkers, 1, 0) ///< Don't emit any
lifetime markers
CODEGENOPT(DisableO0ImplyOptNone , 1, 0) ///< Don't annonate function with
optnone at O0
CODEGENOPT(ExperimentalStrictFloatingPoint, 1, 0) ///< Enables the new,
experimental
///< strict floating point.
+CODEGENOPT(EnableNoundefAttrs, 1, 0) ///< Enable emitting `noundef` attributes
on IR call arguments and return values
CODEGENOPT(LegacyPassManager, 1, 0) ///< Use the legacy pass manager.
CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new
///< pass manager.
diff --git a/clang/include/clang/Driver/Options.td
b/clang/include/clang/Driver/Options.td
index 583d08151e1a..d4d48deb649f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4994,6 +4994,9 @@ def code_completion_with_fixits : Flag<["-"],
"code-completion-with-fixits">,
def disable_free : Flag<["-"], "disable-free">,
HelpText<"Disable freeing of memory on exit">,
MarshallingInfoFlag>;
+def enable_noundef_analysis : Flag<["-"], "enable-noundef-analysis">,
Group,
+ HelpText<"Enable analyzing function argument and return types for mandatory
definedness">,
+ MarshallingInfoFlag>;
def discard_value_names : Flag<["-"], "discard-value-names">,
HelpText<"Discard value names in LLVM IR">,
MarshallingInfoFlag>;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 4ea707621b33..f5411daaa677 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1732,6 +1732,18 @@ static void
AddAttributesFromFunctionProtoType(ASTContext &Ctx,
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
+bool CodeGenModule::MayDropFunctionReturn(const ASTContext &Context,
+ QualType ReturnType) {
+ // We can't just discard the return value for a record type with a
+ // complex destructor or a non-trivially copyable type.
+ if (const RecordType *RT =
+ ReturnType.getCanonicalType()->getAs()) {
+if (const auto *ClassDecl = dyn_cast(RT->getDecl()))
+ return ClassDecl->hasTrivialDestructor();
+ }
+ return ReturnType.isTriviallyCopyableType(Context);
+}
+
void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
bool HasOptnone,
bool AttrOnCallSite,
@@ -1905,6 +1917,55 @@ static void addNoBuiltinAttributes(llvm::AttrBuilder
&FuncAttrs,
llvm::for_each(NBA->builtinNames(), AddNoBuiltinAttr);
}
+static bool DetermineNoUndef(QualType QTy, CodeGenTypes &Types,
+ const llvm::DataLayout &DL, const ABIArgInfo &AI,
+ bool CheckCoerce = true) {
+ llvm::Type *Ty = Types.ConvertTypeForMem(QTy);
+ if (AI.getKind() == ABIArgInfo::Indirect)
+return true;
+ if (AI.getKind() == ABIArgInfo::Extend)
+return true;
+ if (!DL.typeSizeEqualsStoreSize(Ty))
+// TODO: This will result in a modest amount of values not marked noundef
+// when they could be. We care about values that *invisibly* contain undef
+// bits from the perspective of LLVM IR.
+return false;
+ if (CheckCoerce && AI.canHaveCoerceToType()) {
+llvm::Type *CoerceTy = AI.getCoerceToType();
+if (llvm::TypeSize::isKnownGT(DL.getTypeSizeInBits(CoerceTy),
+