summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/DiagnosticInfo.h77
-rw-r--r--llvm/lib/CodeGen/StackProtector.cpp26
-rw-r--r--llvm/lib/IR/DiagnosticInfo.cpp17
-rw-r--r--llvm/test/CodeGen/X86/stack-protector-remarks.ll91
4 files changed, 176 insertions, 35 deletions
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index 956a1ff4342..458c3cf29b0 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -426,10 +426,11 @@ public:
};
/// \p PassName is the name of the pass emitting this diagnostic. \p
- /// RemarkName is a textual identifier for the remark. \p Fn is the function
- /// where the diagnostic is being emitted. \p Loc is the location information
- /// to use in the diagnostic. If line table information is available, the
- /// diagnostic will include the source code location.
+ /// RemarkName is a textual identifier for the remark (single-word,
+ /// camel-case). \p Fn is the function where the diagnostic is being emitted.
+ /// \p Loc is the location information to use in the diagnostic. If line table
+ /// information is available, the diagnostic will include the source code
+ /// location.
DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind,
enum DiagnosticSeverity Severity,
const char *PassName, StringRef RemarkName,
@@ -488,8 +489,9 @@ protected:
/// be emitted.
const char *PassName;
- /// Textual identifier for the remark. Can be used by external tools reading
- /// the YAML output file for optimization remarks to identify the remark.
+ /// Textual identifier for the remark (single-word, camel-case). Can be used
+ /// by external tools reading the YAML output file for optimization remarks to
+ /// identify the remark.
StringRef RemarkName;
/// If profile information is available, this is the number of times the
@@ -515,12 +517,13 @@ protected:
class DiagnosticInfoIROptimization : public DiagnosticInfoOptimizationBase {
public:
/// \p PassName is the name of the pass emitting this diagnostic. \p
- /// RemarkName is a textual identifier for the remark. \p Fn is the function
- /// where the diagnostic is being emitted. \p Loc is the location information
- /// to use in the diagnostic. If line table information is available, the
- /// diagnostic will include the source code location. \p CodeRegion is IR
- /// value (currently basic block) that the optimization operates on. This is
- /// currently used to provide run-time hotness information with PGO.
+ /// RemarkName is a textual identifier for the remark (single-word,
+ /// camel-case). \p Fn is the function where the diagnostic is being emitted.
+ /// \p Loc is the location information to use in the diagnostic. If line table
+ /// information is available, the diagnostic will include the source code
+ /// location. \p CodeRegion is IR value (currently basic block) that the
+ /// optimization operates on. This is currently used to provide run-time
+ /// hotness information with PGO.
DiagnosticInfoIROptimization(enum DiagnosticKind Kind,
enum DiagnosticSeverity Severity,
const char *PassName, StringRef RemarkName,
@@ -581,16 +584,22 @@ class OptimizationRemark : public DiagnosticInfoIROptimization {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass=, then the diagnostic will
- /// be emitted. \p RemarkName is a textual identifier for the remark. \p
- /// Loc is the debug location and \p CodeRegion is the region that the
- /// optimization operates on (currently on block is supported).
+ /// be emitted. \p RemarkName is a textual identifier for the remark (single-
+ /// word, camel-case). \p Loc is the debug location and \p CodeRegion is the
+ /// region that the optimization operates on (currently only block is
+ /// supported).
OptimizationRemark(const char *PassName, StringRef RemarkName,
const DiagnosticLocation &Loc, const Value *CodeRegion);
- /// Same as above but the debug location and code region is derived from \p
+ /// Same as above, but the debug location and code region are derived from \p
/// Instr.
OptimizationRemark(const char *PassName, StringRef RemarkName,
- Instruction *Inst);
+ const Instruction *Inst);
+
+ /// Same as above, but the debug location and code region are derived from \p
+ /// Func.
+ OptimizationRemark(const char *PassName, StringRef RemarkName,
+ const Function *Func);
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_OptimizationRemark;
@@ -627,9 +636,10 @@ class OptimizationRemarkMissed : public DiagnosticInfoIROptimization {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-missed=, then the
- /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
- /// remark. \p Loc is the debug location and \p CodeRegion is the region
- /// that the optimization operates on (currently on block is supported).
+ /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
+ /// remark (single-word, camel-case). \p Loc is the debug location and \p
+ /// CodeRegion is the region that the optimization operates on (currently only
+ /// block is supported).
OptimizationRemarkMissed(const char *PassName, StringRef RemarkName,
const DiagnosticLocation &Loc,
const Value *CodeRegion);
@@ -675,9 +685,10 @@ class OptimizationRemarkAnalysis : public DiagnosticInfoIROptimization {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-analysis=, then the
- /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
- /// remark. \p Loc is the debug location and \p CodeRegion is the region
- /// that the optimization operates on (currently on block is supported).
+ /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
+ /// remark (single-word, camel-case). \p Loc is the debug location and \p
+ /// CodeRegion is the region that the optimization operates on (currently only
+ /// block is supported).
OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
const DiagnosticLocation &Loc,
const Value *CodeRegion);
@@ -752,11 +763,11 @@ class OptimizationRemarkAnalysisFPCommute : public OptimizationRemarkAnalysis {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-analysis=, then the
- /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
- /// remark. \p Loc is the debug location and \p CodeRegion is the region
- /// that the optimization operates on (currently on block is supported). The
- /// front-end will append its own message related to options that address
- /// floating-point non-commutativity.
+ /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
+ /// remark (single-word, camel-case). \p Loc is the debug location and \p
+ /// CodeRegion is the region that the optimization operates on (currently only
+ /// block is supported). The front-end will append its own message related to
+ /// options that address floating-point non-commutativity.
OptimizationRemarkAnalysisFPCommute(const char *PassName,
StringRef RemarkName,
const DiagnosticLocation &Loc,
@@ -796,11 +807,11 @@ class OptimizationRemarkAnalysisAliasing : public OptimizationRemarkAnalysis {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-analysis=, then the
- /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
- /// remark. \p Loc is the debug location and \p CodeRegion is the region
- /// that the optimization operates on (currently on block is supported). The
- /// front-end will append its own message related to options that address
- /// pointer aliasing legality.
+ /// diagnostic will be emitted. \p RemarkName is a textual identifier for the
+ /// remark (single-word, camel-case). \p Loc is the debug location and \p
+ /// CodeRegion is the region that the optimization operates on (currently only
+ /// block is supported). The front-end will append its own message related to
+ /// options that address pointer aliasing legality.
OptimizationRemarkAnalysisAliasing(const char *PassName, StringRef RemarkName,
const DiagnosticLocation &Loc,
const Value *CodeRegion)
diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index 2fe9c7ed5c6..1753eda56d8 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/EHPersonalities.h"
+#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/Attributes.h"
@@ -58,7 +59,7 @@ static cl::opt<bool> EnableSelectionDAGSP("enable-selectiondag-sp",
char StackProtector::ID = 0;
INITIALIZE_TM_PASS(StackProtector, "stack-protector", "Insert stack protectors",
- false, true)
+ false, true)
FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
return new StackProtector(TM);
@@ -229,7 +230,17 @@ bool StackProtector::RequiresStackProtector() {
if (F->hasFnAttribute(Attribute::SafeStack))
return false;
+ // We are constructing the OptimizationRemarkEmitter on the fly rather than
+ // using the analysis pass to avoid building DominatorTree and LoopInfo which
+ // are not available this late in the IR pipeline.
+ OptimizationRemarkEmitter ORE(F);
+ auto ReasonStub =
+ Twine("Stack protection applied to function " + F->getName() + " due to ")
+ .str();
+
if (F->hasFnAttribute(Attribute::StackProtectReq)) {
+ ORE.emit(OptimizationRemark(DEBUG_TYPE, "StackProtectorRequested", F)
+ << ReasonStub << "a function attribute or command-line switch");
NeedsProtector = true;
Strong = true; // Use the same heuristic as strong to determine SSPLayout
} else if (F->hasFnAttribute(Attribute::StackProtectStrong))
@@ -243,20 +254,27 @@ bool StackProtector::RequiresStackProtector() {
for (const Instruction &I : BB) {
if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
if (AI->isArrayAllocation()) {
+ OptimizationRemark Remark(DEBUG_TYPE, "StackProtectorAllocaOrArray",
+ &I);
+ Remark << ReasonStub
+ << "a call to alloca or use of a variable length array";
if (const auto *CI = dyn_cast<ConstantInt>(AI->getArraySize())) {
if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize) {
// A call to alloca with size >= SSPBufferSize requires
// stack protectors.
Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ ORE.emit(Remark);
NeedsProtector = true;
} else if (Strong) {
// Require protectors for all alloca calls in strong mode.
Layout.insert(std::make_pair(AI, SSPLK_SmallArray));
+ ORE.emit(Remark);
NeedsProtector = true;
}
} else {
// A call to alloca with a variable size requires protectors.
Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ ORE.emit(Remark);
NeedsProtector = true;
}
continue;
@@ -266,6 +284,9 @@ bool StackProtector::RequiresStackProtector() {
if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) {
Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray
: SSPLK_SmallArray));
+ ORE.emit(OptimizationRemark(DEBUG_TYPE, "StackProtectorBuffer", &I)
+ << ReasonStub
+ << "a stack allocated buffer or struct containing a buffer");
NeedsProtector = true;
continue;
}
@@ -273,6 +294,9 @@ bool StackProtector::RequiresStackProtector() {
if (Strong && HasAddressTaken(AI)) {
++NumAddrTaken;
Layout.insert(std::make_pair(AI, SSPLK_AddrOf));
+ ORE.emit(
+ OptimizationRemark(DEBUG_TYPE, "StackProtectorAddressTaken", &I)
+ << ReasonStub << "the address of a local variable being taken");
NeedsProtector = true;
}
}
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index 8afb547971c..395b6158e0c 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -228,11 +228,26 @@ OptimizationRemark::OptimizationRemark(const char *PassName,
*cast<BasicBlock>(CodeRegion)->getParent(), Loc, CodeRegion) {}
OptimizationRemark::OptimizationRemark(const char *PassName,
- StringRef RemarkName, Instruction *Inst)
+ StringRef RemarkName,
+ const Instruction *Inst)
: DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName,
RemarkName, *Inst->getParent()->getParent(),
Inst->getDebugLoc(), Inst->getParent()) {}
+// Helper to allow for an assert before attempting to return an invalid
+// reference.
+static const BasicBlock &getFirstFunctionBlock(const Function *Func) {
+ assert(!Func->empty() && "Function does not have a body");
+ return Func->front();
+}
+
+OptimizationRemark::OptimizationRemark(const char *PassName,
+ StringRef RemarkName,
+ const Function *Func)
+ : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName,
+ RemarkName, *Func, Func->getSubprogram(),
+ &getFirstFunctionBlock(Func)) {}
+
bool OptimizationRemark::isEnabled(StringRef PassName) {
return PassRemarksOptLoc.Pattern &&
PassRemarksOptLoc.Pattern->match(PassName);
diff --git a/llvm/test/CodeGen/X86/stack-protector-remarks.ll b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
new file mode 100644
index 00000000000..a86976ddb32
--- /dev/null
+++ b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
@@ -0,0 +1,91 @@
+; RUN: llc %s -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
+; CHECK-NOT: nossp
+; CHECK: function attribute_ssp
+; CHECK-SAME: a function attribute or command-line switch
+; CHECK-NOT: alloca_fixed_small_nossp
+; CHECK: function alloca_fixed_small_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function alloca_fixed_large_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function alloca_variable_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function buffer_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function struct_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function address_ssp
+; CHECK-SAME: the address of a local variable being taken
+; CHECK: function multiple_ssp
+; CHECK-SAME: a function attribute or command-line switch
+; CHECK: function multiple_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function multiple_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function multiple_ssp
+; CHECK-SAME: the address of a local variable being taken
+; CHECK: function multiple_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+
+; Check that no remark is emitted when the switch is not specified.
+; RUN: llc %s -o /dev/null 2>&1 | FileCheck %s -check-prefix=NOREMARK -allow-empty
+; NOREMARK-NOT: ssp
+
+define void @nossp() ssp {
+ ret void
+}
+
+define void @attribute_ssp() sspreq {
+ ret void
+}
+
+define void @alloca_fixed_small_nossp() ssp {
+ %1 = alloca i8, i64 2, align 16
+ ret void
+}
+
+define void @alloca_fixed_small_ssp() sspstrong {
+ %1 = alloca i8, i64 2, align 16
+ ret void
+}
+
+define void @alloca_fixed_large_ssp() ssp {
+ %1 = alloca i8, i64 64, align 16
+ ret void
+}
+
+define void @alloca_variable_ssp(i64 %x) ssp {
+ %1 = alloca i8, i64 %x, align 16
+ ret void
+}
+
+define void @buffer_ssp() sspstrong {
+ %x = alloca [64 x i32], align 16
+ ret void
+}
+
+%struct.X = type { [64 x i32] }
+define void @struct_ssp() sspstrong {
+ %x = alloca %struct.X, align 4
+ ret void
+}
+
+define void @address_ssp() sspstrong {
+entry:
+ %x = alloca i32, align 4
+ %y = alloca i32*, align 8
+ store i32 32, i32* %x, align 4
+ store i32* %x, i32** %y, align 8
+ ret void
+}
+
+define void @multiple_ssp() sspreq {
+entry:
+ %x = alloca %struct.X, align 4
+ %y = alloca [64 x i32], align 16
+ %a = alloca i32, align 4
+ %b = alloca i32*, align 8
+ %0 = alloca i8, i64 2, align 16
+ store i32 32, i32* %a, align 4
+ store i32* %a, i32** %b, align 8
+ ret void
+}