24#include "llvm/ADT/SmallString.h"
25#include "llvm/Support/MathExtras.h"
26#include "llvm/Support/raw_ostream.h"
33class PaddingChecker :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
35 const BugType PaddingBug{
this,
"Excessive Padding",
"Performance"};
50 bool shouldVisitTemplateInstantiations()
const {
return true; }
51 bool shouldVisitImplicitCode()
const {
return true; }
57 bool VisitVarDecl(
const VarDecl *VD) {
64 LocalVisitor visitor(
this);
72 void visitRecord(
const RecordDecl *RD, uint64_t PadMultiplier = 1)
const {
73 if (shouldSkipDecl(RD))
85 if (
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
86 if (CXXRD->field_empty() && CXXRD->getNumBases() == 1)
87 return visitRecord(CXXRD->bases().begin()->getType()->getAsRecordDecl(),
100 std::tie(OptimalPad, OptimalFieldsOrder) =
103 CharUnits DiffPad = PadMultiplier * (BaselinePad - OptimalPad);
105 assert(!DiffPad.
isNegative() &&
"DiffPad should not be negative");
109 reportRecord(RD, BaselinePad, OptimalPad, OptimalFieldsOrder);
114 void visitVariable(
const VarDecl *VD)
const {
116 if (ArrTy ==
nullptr)
120 Elts = CArrTy->getZExtSize();
128 visitRecord(RT->
getDecl(), Elts);
131 bool shouldSkipDecl(
const RecordDecl *RD)
const {
139 if (!Location.isValid())
150 if (
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
155 if (!CXXRD->field_empty() && CXXRD->getNumBases() != 0)
157 if (CXXRD->field_empty() && CXXRD->getNumBases() != 1)
160 if (CXXRD->getNumVBases() != 0)
164 if (CXXRD->getTypeForDecl()->isDependentType())
166 if (CXXRD->getTypeForDecl()->isInstantiationDependentType())
173 auto IsTrickyField = [](
const FieldDecl *FD) ->
bool {
175 if (FD->isBitField())
185 if (llvm::any_of(RD->
fields(), IsTrickyField))
208 PaddingSum += (FieldOffset - Offset);
209 Offset = FieldOffset + FieldSize;
211 PaddingSum += RL.
getSize() - Offset;
231 static std::pair<CharUnits, SmallVector<const FieldDecl *, 20>>
238 bool operator<(
const FieldInfo &RHS)
const {
242 return std::make_tuple(Align, -Size,
243 Field ? -
static_cast<int>(
Field->getFieldIndex())
246 RHS.Align, -RHS.Size,
247 RHS.Field ? -
static_cast<int>(RHS.Field->getFieldIndex())
252 auto GatherSizesAndAlignments = [](
const FieldDecl *FD) {
255 auto &Ctx = FD->getASTContext();
256 auto Info = Ctx.getTypeInfoInChars(FD->getType());
258 RetVal.Align = Info.Align;
259 assert(llvm::isPowerOf2_64(RetVal.Align.getQuantity()));
260 if (
auto Max = FD->getMaxAlignment())
261 RetVal.Align = std::max(Ctx.toCharUnitsFromBits(
Max), RetVal.Align);
265 std::back_inserter(Fields), GatherSizesAndAlignments);
274 while (!Fields.empty()) {
275 unsigned TrailingZeros =
276 llvm::countr_zero((
unsigned long long)NewOffset.
getQuantity());
280 long long CurAlignmentBits = 1ull << (std::min)(TrailingZeros, 62u);
288 auto Iter = llvm::upper_bound(Fields, InsertPoint);
289 if (
Iter != Fields.begin()) {
292 NewOffset +=
Iter->Size;
293 OptimalFieldsOrder.push_back(
Iter->Field);
300 NewPad += NextOffset - NewOffset;
301 NewOffset = NextOffset;
306 NewPad += NewSize - NewOffset;
307 return {NewPad, std::move(OptimalFieldsOrder)};
314 llvm::raw_svector_ostream Os(Buf);
315 Os <<
"Excessive padding in '";
320 if (
auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
326 Os <<
" instantiated here: "
330 Os <<
" (" << BaselinePad.
getQuantity() <<
" padding bytes, where "
332 <<
"Optimal fields order: ";
333 for (
const auto *FD : OptimalFieldsOrder)
334 Os << FD->getName() <<
", ";
335 Os <<
"consider reordering the fields or adding explicit padding "
340 auto Report = std::make_unique<BasicBugReport>(PaddingBug, Os.str(), CELoc);
341 Report->setDeclWithIssue(RD);
354 Checker,
"AllowedPad",
"a non-negative value");
357bool ento::shouldRegisterPaddingChecker(
const CheckerManager &mgr) {
Defines the C++ template declaration subclasses.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
CharUnits getAlignment() const
getAlignment - Get the record alignment in characters.
CharUnits getSize() const
getSize - Get the record size in characters.
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
int getCheckerIntegerOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as an integer value.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
QualType getElementType() const
CharUnits - This is an opaque type for sizes expressed in character units.
bool isNegative() const
isNegative - Test whether the quantity is less than zero.
bool isZero() const
isZero - Test whether the quantity equals zero.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Represents the canonical version of C arrays with a specified constant size.
ASTContext & getASTContext() const LLVM_READONLY
SourceLocation getLocation() const
Represents a member of a struct/union/class.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
A (possibly-)qualified type.
std::string getAsString() const
The collection of all-type qualifiers we support.
Represents a struct/union/class.
field_iterator field_end() const
field_range fields() const
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
field_iterator field_begin() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
RecordDecl * getDecl() const
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Encodes a location in the source.
std::string printToString(const SourceManager &SM) const
bool isValid() const
Return true if this is a valid SourceLocation object.
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const
Return the file characteristic of the specified source location, indicating whether this is a normal ...
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
The top declaration context.
const Type * getTypeForDecl() const
bool isIncompleteArrayType() const
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
const T * getAs() const
Member-template getAs<specific type>'.
Represents a variable declaration or definition.
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
void reportInvalidCheckerOptionValue(const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const
Emits an error through a DiagnosticsEngine about an invalid user supplied checker option value.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
The JSON file list parser is used to communicate input to InstallAPI.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.