mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-09-01 04:29:57 +00:00
Manage Inits in a FoldingSet. This provides several benefits: - Memory for Inits is properly managed - Duplicate Inits are folded into Flyweights, saving memory - It enforces const-correctness, protecting against certain classes of bugs The above benefits allow Inits to be used in more contexts, which in turn provides more dynamism to TableGen. This enhanced capability will be used by the AVX code generator to a fold common patterns together. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134907 91177308-0d34-0410-b5e6-96231b3b80d8
326 lines
11 KiB
C++
326 lines
11 KiB
C++
//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This tablegen backend emits Clang Static Analyzer checkers tables.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ClangSACheckersEmitter.h"
|
|
#include "Record.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include <map>
|
|
#include <string>
|
|
using namespace llvm;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Static Analyzer Checkers Tables generation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// \brief True if it is specified hidden or a parent package is specified
|
|
/// as hidden, otherwise false.
|
|
static bool isHidden(const Record &R) {
|
|
if (R.getValueAsBit("Hidden"))
|
|
return true;
|
|
// Not declared as hidden, check the parent package if it is hidden.
|
|
if (const DefInit *DI =
|
|
dynamic_cast<const DefInit*>(R.getValueInit("ParentPackage")))
|
|
return isHidden(*DI->getDef());
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool isCheckerNamed(const Record *R) {
|
|
return !R->getValueAsString("CheckerName").empty();
|
|
}
|
|
|
|
static std::string getPackageFullName(const Record *R);
|
|
|
|
static std::string getParentPackageFullName(const Record *R) {
|
|
std::string name;
|
|
if (const DefInit *DI =
|
|
dynamic_cast<const DefInit*>(R->getValueInit("ParentPackage")))
|
|
name = getPackageFullName(DI->getDef());
|
|
return name;
|
|
}
|
|
|
|
static std::string getPackageFullName(const Record *R) {
|
|
std::string name = getParentPackageFullName(R);
|
|
if (!name.empty()) name += ".";
|
|
return name + R->getValueAsString("PackageName");
|
|
}
|
|
|
|
static std::string getCheckerFullName(const Record *R) {
|
|
std::string name = getParentPackageFullName(R);
|
|
if (isCheckerNamed(R)) {
|
|
if (!name.empty()) name += ".";
|
|
name += R->getValueAsString("CheckerName");
|
|
}
|
|
return name;
|
|
}
|
|
|
|
static std::string getStringValue(const Record &R, StringRef field) {
|
|
if (const StringInit *
|
|
SI = dynamic_cast<const StringInit*>(R.getValueInit(field)))
|
|
return SI->getValue();
|
|
return std::string();
|
|
}
|
|
|
|
namespace {
|
|
struct GroupInfo {
|
|
llvm::DenseSet<const Record*> Checkers;
|
|
llvm::DenseSet<const Record *> SubGroups;
|
|
bool Hidden;
|
|
unsigned Index;
|
|
|
|
GroupInfo() : Hidden(false) { }
|
|
};
|
|
}
|
|
|
|
static void addPackageToCheckerGroup(const Record *package, const Record *group,
|
|
llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) {
|
|
llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers;
|
|
for (llvm::DenseSet<const Record *>::iterator
|
|
I = checkers.begin(), E = checkers.end(); I != E; ++I)
|
|
recordGroupMap[group]->Checkers.insert(*I);
|
|
|
|
llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups;
|
|
for (llvm::DenseSet<const Record *>::iterator
|
|
I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
|
|
addPackageToCheckerGroup(*I, group, recordGroupMap);
|
|
}
|
|
|
|
void ClangSACheckersEmitter::run(raw_ostream &OS) {
|
|
std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
|
|
llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
|
|
for (unsigned i = 0, e = checkers.size(); i != e; ++i)
|
|
checkerRecIndexMap[checkers[i]] = i;
|
|
|
|
// Invert the mapping of checkers to package/group into a one to many
|
|
// mapping of packages/groups to checkers.
|
|
std::map<std::string, GroupInfo> groupInfoByName;
|
|
llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
|
|
|
|
std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
|
|
for (unsigned i = 0, e = packages.size(); i != e; ++i) {
|
|
Record *R = packages[i];
|
|
std::string fullName = getPackageFullName(R);
|
|
if (!fullName.empty()) {
|
|
GroupInfo &info = groupInfoByName[fullName];
|
|
info.Hidden = isHidden(*R);
|
|
recordGroupMap[R] = &info;
|
|
}
|
|
}
|
|
|
|
std::vector<Record*>
|
|
checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
|
|
for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
|
|
Record *R = checkerGroups[i];
|
|
std::string name = R->getValueAsString("GroupName");
|
|
if (!name.empty()) {
|
|
GroupInfo &info = groupInfoByName[name];
|
|
recordGroupMap[R] = &info;
|
|
}
|
|
}
|
|
|
|
for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
|
|
Record *R = checkers[i];
|
|
Record *package = 0;
|
|
if (const DefInit *
|
|
DI = dynamic_cast<const DefInit*>(R->getValueInit("ParentPackage")))
|
|
package = DI->getDef();
|
|
if (!isCheckerNamed(R) && !package)
|
|
throw "Checker '" + R->getName() + "' is neither named, nor in a package!";
|
|
|
|
if (isCheckerNamed(R)) {
|
|
// Create a pseudo-group to hold this checker.
|
|
std::string fullName = getCheckerFullName(R);
|
|
GroupInfo &info = groupInfoByName[fullName];
|
|
info.Hidden = R->getValueAsBit("Hidden");
|
|
recordGroupMap[R] = &info;
|
|
info.Checkers.insert(R);
|
|
} else {
|
|
recordGroupMap[package]->Checkers.insert(R);
|
|
}
|
|
|
|
Record *currR = isCheckerNamed(R) ? R : package;
|
|
// Insert the checker and its parent packages into the subgroups set of
|
|
// the corresponding parent package.
|
|
while (const DefInit *DI =
|
|
dynamic_cast<const DefInit*>(currR->getValueInit("ParentPackage"))) {
|
|
Record *parentPackage = DI->getDef();
|
|
recordGroupMap[parentPackage]->SubGroups.insert(currR);
|
|
currR = parentPackage;
|
|
}
|
|
// Insert the checker into the set of its group.
|
|
if (const DefInit *DI =
|
|
dynamic_cast<const DefInit*>(R->getValueInit("Group")))
|
|
recordGroupMap[DI->getDef()]->Checkers.insert(R);
|
|
}
|
|
|
|
// If a package is in group, add all its checkers and its sub-packages
|
|
// checkers into the group.
|
|
for (unsigned i = 0, e = packages.size(); i != e; ++i)
|
|
if (const DefInit *DI =
|
|
dynamic_cast<const DefInit*>(packages[i]->getValueInit("Group")))
|
|
addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
|
|
|
|
typedef std::map<std::string, const Record *> SortedRecords;
|
|
typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex;
|
|
|
|
SortedRecords sortedGroups;
|
|
RecToSortIndex groupToSortIndex;
|
|
OS << "\n#ifdef GET_GROUPS\n";
|
|
{
|
|
for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i)
|
|
sortedGroups[checkerGroups[i]->getValueAsString("GroupName")]
|
|
= checkerGroups[i];
|
|
|
|
unsigned sortIndex = 0;
|
|
for (SortedRecords::iterator
|
|
I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) {
|
|
const Record *R = I->second;
|
|
|
|
OS << "GROUP(" << "\"";
|
|
OS.write_escaped(R->getValueAsString("GroupName")) << "\"";
|
|
OS << ")\n";
|
|
|
|
groupToSortIndex[R] = sortIndex++;
|
|
}
|
|
}
|
|
OS << "#endif // GET_GROUPS\n\n";
|
|
|
|
OS << "\n#ifdef GET_PACKAGES\n";
|
|
{
|
|
SortedRecords sortedPackages;
|
|
for (unsigned i = 0, e = packages.size(); i != e; ++i)
|
|
sortedPackages[getPackageFullName(packages[i])] = packages[i];
|
|
|
|
for (SortedRecords::iterator
|
|
I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
|
|
const Record &R = *I->second;
|
|
|
|
OS << "PACKAGE(" << "\"";
|
|
OS.write_escaped(getPackageFullName(&R)) << "\", ";
|
|
// Group index
|
|
if (const DefInit *DI =
|
|
dynamic_cast<const DefInit*>(R.getValueInit("Group")))
|
|
OS << groupToSortIndex[DI->getDef()] << ", ";
|
|
else
|
|
OS << "-1, ";
|
|
// Hidden bit
|
|
if (isHidden(R))
|
|
OS << "true";
|
|
else
|
|
OS << "false";
|
|
OS << ")\n";
|
|
}
|
|
}
|
|
OS << "#endif // GET_PACKAGES\n\n";
|
|
|
|
OS << "\n#ifdef GET_CHECKERS\n";
|
|
for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
|
|
const Record &R = *checkers[i];
|
|
|
|
OS << "CHECKER(" << "\"";
|
|
std::string name;
|
|
if (isCheckerNamed(&R))
|
|
name = getCheckerFullName(&R);
|
|
OS.write_escaped(name) << "\", ";
|
|
OS << R.getName() << ", ";
|
|
OS << getStringValue(R, "DescFile") << ", ";
|
|
OS << "\"";
|
|
OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
|
|
// Group index
|
|
if (const DefInit *DI =
|
|
dynamic_cast<const DefInit*>(R.getValueInit("Group")))
|
|
OS << groupToSortIndex[DI->getDef()] << ", ";
|
|
else
|
|
OS << "-1, ";
|
|
// Hidden bit
|
|
if (isHidden(R))
|
|
OS << "true";
|
|
else
|
|
OS << "false";
|
|
OS << ")\n";
|
|
}
|
|
OS << "#endif // GET_CHECKERS\n\n";
|
|
|
|
unsigned index = 0;
|
|
for (std::map<std::string, GroupInfo>::iterator
|
|
I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
|
|
I->second.Index = index++;
|
|
|
|
// Walk through the packages/groups/checkers emitting an array for each
|
|
// set of checkers and an array for each set of subpackages.
|
|
|
|
OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
|
|
unsigned maxLen = 0;
|
|
for (std::map<std::string, GroupInfo>::iterator
|
|
I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
|
|
maxLen = std::max(maxLen, (unsigned)I->first.size());
|
|
|
|
llvm::DenseSet<const Record *> &checkers = I->second.Checkers;
|
|
if (!checkers.empty()) {
|
|
OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
|
|
// Make the output order deterministic.
|
|
std::map<int, const Record *> sorted;
|
|
for (llvm::DenseSet<const Record *>::iterator
|
|
I = checkers.begin(), E = checkers.end(); I != E; ++I)
|
|
sorted[(*I)->getID()] = *I;
|
|
|
|
for (std::map<int, const Record *>::iterator
|
|
I = sorted.begin(), E = sorted.end(); I != E; ++I)
|
|
OS << checkerRecIndexMap[I->second] << ", ";
|
|
OS << "-1 };\n";
|
|
}
|
|
|
|
llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
|
|
if (!subGroups.empty()) {
|
|
OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
|
|
// Make the output order deterministic.
|
|
std::map<int, const Record *> sorted;
|
|
for (llvm::DenseSet<const Record *>::iterator
|
|
I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
|
|
sorted[(*I)->getID()] = *I;
|
|
|
|
for (std::map<int, const Record *>::iterator
|
|
I = sorted.begin(), E = sorted.end(); I != E; ++I) {
|
|
OS << recordGroupMap[I->second]->Index << ", ";
|
|
}
|
|
OS << "-1 };\n";
|
|
}
|
|
}
|
|
OS << "#endif // GET_MEMBER_ARRAYS\n\n";
|
|
|
|
OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
|
|
for (std::map<std::string, GroupInfo>::iterator
|
|
I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
|
|
// Group option string.
|
|
OS << " { \"";
|
|
OS.write_escaped(I->first) << "\","
|
|
<< std::string(maxLen-I->first.size()+1, ' ');
|
|
|
|
if (I->second.Checkers.empty())
|
|
OS << "0, ";
|
|
else
|
|
OS << "CheckerArray" << I->second.Index << ", ";
|
|
|
|
// Subgroups.
|
|
if (I->second.SubGroups.empty())
|
|
OS << "0, ";
|
|
else
|
|
OS << "SubPackageArray" << I->second.Index << ", ";
|
|
|
|
OS << (I->second.Hidden ? "true" : "false");
|
|
|
|
OS << " },\n";
|
|
}
|
|
OS << "#endif // GET_CHECKNAME_TABLE\n\n";
|
|
}
|