CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
198 lines
7.5 KiB
C++
198 lines
7.5 KiB
C++
//===- PairsAnalysis.cpp - Pairs analysis for ExamplePlugin ---------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "AnalysisResults.h"
|
|
#include "clang/ScalableStaticAnalysisFramework/Core/Model/SummaryName.h"
|
|
#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
|
|
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
|
|
#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/AnalysisRegistry.h"
|
|
#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/SummaryAnalysis.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/JSON.h"
|
|
#include "llvm/Support/Registry.h"
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
using namespace clang::ssaf;
|
|
using namespace llvm;
|
|
using example_plugin::PairsAnalysisResult;
|
|
|
|
namespace {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// PairsEntitySummary
|
|
//
|
|
// Per-entity data: a list of (EntityId, EntityId) pairs. Stored in the LU
|
|
// data section under summary_name "PairsEntitySummary". Serialized as:
|
|
// { "pairs": [{"first": {...}, "second": {...}}, ...] }
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct PairsEntitySummary final : EntitySummary {
|
|
static SummaryName summaryName() { return SummaryName("PairsEntitySummary"); }
|
|
|
|
SummaryName getSummaryName() const override {
|
|
return SummaryName("PairsEntitySummary");
|
|
}
|
|
|
|
std::vector<std::pair<EntityId, EntityId>> Pairs;
|
|
};
|
|
|
|
json::Object serializePairsEntitySummary(const EntitySummary &ES,
|
|
JSONFormat::EntityIdToJSONFn ToJSON) {
|
|
const auto &S = static_cast<const PairsEntitySummary &>(ES);
|
|
json::Array PairsArray;
|
|
for (const auto &[First, Second] : S.Pairs) {
|
|
PairsArray.push_back(json::Object{
|
|
{"first", ToJSON(First)},
|
|
{"second", ToJSON(Second)},
|
|
});
|
|
}
|
|
return json::Object{{"pairs", std::move(PairsArray)}};
|
|
}
|
|
|
|
Expected<std::unique_ptr<EntitySummary>>
|
|
deserializePairsEntitySummary(const json::Object &Obj, EntityIdTable &,
|
|
JSONFormat::EntityIdFromJSONFn FromJSON) {
|
|
auto Result = std::make_unique<PairsEntitySummary>();
|
|
const json::Array *PairsArray = Obj.getArray("pairs");
|
|
if (!PairsArray) {
|
|
return createStringError(inconvertibleErrorCode(),
|
|
"missing or invalid field 'pairs'");
|
|
}
|
|
for (const auto &[Index, Value] : llvm::enumerate(*PairsArray)) {
|
|
const json::Object *Pair = Value.getAsObject();
|
|
if (!Pair) {
|
|
return createStringError(
|
|
inconvertibleErrorCode(),
|
|
"pairs element at index %zu is not a JSON object", Index);
|
|
}
|
|
const json::Object *FirstObj = Pair->getObject("first");
|
|
if (!FirstObj) {
|
|
return createStringError(
|
|
inconvertibleErrorCode(),
|
|
"missing or invalid 'first' field at index '%zu'", Index);
|
|
}
|
|
const json::Object *SecondObj = Pair->getObject("second");
|
|
if (!SecondObj) {
|
|
return createStringError(
|
|
inconvertibleErrorCode(),
|
|
"missing or invalid 'second' field at index '%zu'", Index);
|
|
}
|
|
auto ExpectedFirst = FromJSON(*FirstObj);
|
|
if (!ExpectedFirst) {
|
|
return createStringError(inconvertibleErrorCode(),
|
|
"invalid 'first' entity id at index '%zu': %s",
|
|
Index,
|
|
toString(ExpectedFirst.takeError()).c_str());
|
|
}
|
|
auto ExpectedSecond = FromJSON(*SecondObj);
|
|
if (!ExpectedSecond) {
|
|
return createStringError(inconvertibleErrorCode(),
|
|
"invalid 'second' entity id at index '%zu': %s",
|
|
Index,
|
|
toString(ExpectedSecond.takeError()).c_str());
|
|
}
|
|
Result->Pairs.emplace_back(*ExpectedFirst, *ExpectedSecond);
|
|
}
|
|
return std::move(Result);
|
|
}
|
|
|
|
struct PairsEntitySummaryFormatInfo final : JSONFormat::FormatInfo {
|
|
PairsEntitySummaryFormatInfo()
|
|
: JSONFormat::FormatInfo(SummaryName("PairsEntitySummary"),
|
|
serializePairsEntitySummary,
|
|
deserializePairsEntitySummary) {}
|
|
};
|
|
|
|
llvm::Registry<JSONFormat::FormatInfo>::Add<PairsEntitySummaryFormatInfo>
|
|
RegisterPairsEntitySummaryForJSON(
|
|
"PairsEntitySummary", "JSON format info for PairsEntitySummary");
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// PairsAnalysisResult serialization
|
|
//
|
|
// Per-entity pair count. Serialized as:
|
|
// { "pair_counts": [{"entity_id": {...}, "count": N}, ...] }
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
json::Object serializePairsAnalysisResult(const PairsAnalysisResult &R,
|
|
JSONFormat::EntityIdToJSONFn ToJSON) {
|
|
json::Array Arr;
|
|
for (const auto &[EI, Count] : R.PairCounts) {
|
|
Arr.push_back(json::Object{{"entity_id", ToJSON(EI)}, {"count", Count}});
|
|
}
|
|
return json::Object{{"pair_counts", std::move(Arr)}};
|
|
}
|
|
|
|
Expected<std::unique_ptr<AnalysisResult>>
|
|
deserializePairsAnalysisResult(const json::Object &Obj,
|
|
JSONFormat::EntityIdFromJSONFn FromJSON) {
|
|
const json::Array *Arr = Obj.getArray("pair_counts");
|
|
if (!Arr) {
|
|
return createStringError(inconvertibleErrorCode(),
|
|
"missing or invalid field 'pair_counts'");
|
|
}
|
|
|
|
auto R = std::make_unique<PairsAnalysisResult>();
|
|
for (const auto &[Index, Val] : llvm::enumerate(*Arr)) {
|
|
const json::Object *Entry = Val.getAsObject();
|
|
if (!Entry) {
|
|
return createStringError(
|
|
inconvertibleErrorCode(),
|
|
"pair_counts element at index %zu is not an object", Index);
|
|
}
|
|
const json::Object *EIObj = Entry->getObject("entity_id");
|
|
if (!EIObj) {
|
|
return createStringError(
|
|
inconvertibleErrorCode(),
|
|
"missing or invalid 'entity_id' field at index %zu", Index);
|
|
}
|
|
auto ExpectedEI = FromJSON(*EIObj);
|
|
if (!ExpectedEI) {
|
|
return ExpectedEI.takeError();
|
|
}
|
|
|
|
auto CountVal = Entry->getInteger("count");
|
|
if (!CountVal) {
|
|
return createStringError(inconvertibleErrorCode(),
|
|
"missing or invalid 'count' field at index %zu",
|
|
Index);
|
|
}
|
|
R->PairCounts.emplace_back(*ExpectedEI, static_cast<int>(*CountVal));
|
|
}
|
|
return std::move(R);
|
|
}
|
|
|
|
JSONFormat::AnalysisResultRegistry::Add<PairsAnalysisResult>
|
|
RegisterPairsResultForJSON(serializePairsAnalysisResult,
|
|
deserializePairsAnalysisResult);
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// PairsAnalysis
|
|
//
|
|
// SummaryAnalysis that reads per-entity PairsEntitySummary data and counts
|
|
// the number of pairs per entity, producing (EntityId, count) pairs.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
class PairsAnalysis final
|
|
: public SummaryAnalysis<PairsAnalysisResult, PairsEntitySummary> {
|
|
public:
|
|
using ResultType = PairsAnalysisResult;
|
|
|
|
llvm::Error add(EntityId Id, const PairsEntitySummary &S) override {
|
|
getResult().PairCounts.emplace_back(Id, static_cast<int>(S.Pairs.size()));
|
|
return llvm::Error::success();
|
|
}
|
|
};
|
|
|
|
AnalysisRegistry::Add<PairsAnalysis>
|
|
RegisterPairsAnalysis("Counts pairs per entity");
|
|
|
|
} // namespace
|