Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions clang/include/clang/CIR/Analysis/CIRAnalysisKind.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//===--- CIRAnalysisKind.h - CIR Analysis Pass Kinds -----------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Defines the CIR analysis pass kinds enum and related utilities.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_CIR_SEMA_CIRANALYSISKIND_H
#define LLVM_CLANG_CIR_SEMA_CIRANALYSISKIND_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
#include <string>
#include <vector>

namespace cir {

/// Enumeration of available CIR semantic analysis passes
enum class CIRAnalysisKind : unsigned {
Unrecognized = 0,
FallThrough = 1 << 0, // Fallthrough warning analysis
UnreachableCode = 1 << 1, // Unreachable code detection
NullCheck = 1 << 2, // Null pointer checks
UninitializedVar = 1 << 3, // Uninitialized variable detection
// Add more analysis passes here as needed
};

/// A set of CIR analysis passes (bitmask)
class CIRAnalysisSet {
unsigned mask = 0;

public:
CIRAnalysisSet() = default;
explicit CIRAnalysisSet(CIRAnalysisKind kind)
: mask(static_cast<unsigned>(kind)) {}
explicit CIRAnalysisSet(unsigned mask) : mask(mask) {}

/// Check if a specific analysis is enabled
bool has(CIRAnalysisKind kind) const {
return (mask & static_cast<unsigned>(kind)) != 0;
}

/// Enable a specific analysis
void enable(CIRAnalysisKind kind) {
mask |= static_cast<unsigned>(kind);
}

/// Disable a specific analysis
void disable(CIRAnalysisKind kind) {
mask &= ~static_cast<unsigned>(kind);
}

/// Check if any analysis is enabled
bool hasAny() const { return mask != 0; }

/// Check if no analysis is enabled
bool empty() const { return mask == 0; }

/// Get the raw mask value
unsigned getMask() const { return mask; }

/// Union with another set
CIRAnalysisSet &operator|=(const CIRAnalysisSet &other) {
mask |= other.mask;
return *this;
}

/// Union operator
CIRAnalysisSet operator|(const CIRAnalysisSet &other) const {
return CIRAnalysisSet(mask | other.mask);
}

/// Intersection with another set
CIRAnalysisSet &operator&=(const CIRAnalysisSet &other) {
mask &= other.mask;
return *this;
}

/// Intersection operator
CIRAnalysisSet operator&(const CIRAnalysisSet &other) const {
return CIRAnalysisSet(mask & other.mask);
}

bool operator==(const CIRAnalysisSet &other) const {
return mask == other.mask;
}

bool operator!=(const CIRAnalysisSet &other) const {
return mask != other.mask;
}

/// Print the analysis set to an output stream
void print(llvm::raw_ostream &OS) const;
};

/// Parse a single analysis name into a CIRAnalysisKind
/// Returns std::nullopt if the name is not recognized
CIRAnalysisKind parseCIRAnalysisKind(llvm::StringRef name);

/// Parse a list of analysis names (from command line) into a CIRAnalysisSet
/// Handles comma and semicolon separators
/// Invalid names are ignored and optionally reported via InvalidNames
CIRAnalysisSet parseCIRAnalysisList(
const std::vector<std::string> &analysisList,
llvm::SmallVectorImpl<std::string> *invalidNames = nullptr);

} // namespace cir

#endif // LLVM_CLANG_CIR_SEMA_CIRANALYSISKIND_H
73 changes: 73 additions & 0 deletions clang/include/clang/CIR/Analysis/FallThroughWarning.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//===--- FallThroughWarning.h - CIR Fall-Through Analysis ------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Defines the FallThroughWarningPass for CIR fall-through analysis.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_CIR_SEMA_FALLTHROUGHWARNING_H
#define LLVM_CLANG_CIR_SEMA_FALLTHROUGHWARNING_H

#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/AnalysisBasedWarnings.h"

#include "mlir/IR/Block.h"
#include "mlir/IR/Operation.h"
#include "mlir/Support/LLVM.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
namespace cir {
class FuncOp;
} // namespace cir

namespace clang {
class Sema;
Decl *getDeclByName(ASTContext &context, StringRef name);
enum ControlFlowKind {
UnknownFallThrough,
NeverFallThrough,
MaybeFallThrough,
AlwaysFallThrough,
NeverFallThroughOrReturn
};

/// Configuration for fall-through diagnostics
struct CheckFallThroughDiagnostics {
unsigned diagFallThroughHasNoReturn = 0;
unsigned diagFallThroughReturnsNonVoid = 0;
unsigned diagNeverFallThroughOrReturn = 0;
unsigned funKind = 0;
SourceLocation funcLoc;

static CheckFallThroughDiagnostics makeForFunction(Sema &s, const Decl *func);
static CheckFallThroughDiagnostics makeForCoroutine(const Decl *func);
static CheckFallThroughDiagnostics makeForBlock();
static CheckFallThroughDiagnostics makeForLambda();
bool checkDiagnostics(DiagnosticsEngine &d, bool returnsVoid,
bool hasNoReturn) const;
};
/// Check if a return operation returns a phony value (uninitialized __retval)
bool isPhonyReturn(cir::ReturnOp returnOp);

/// Pass for analyzing fall-through behavior in CIR functions
class FallThroughWarningPass {
public:
FallThroughWarningPass() = default;

/// Check fall-through behavior for a CIR function body
void checkFallThroughForFuncBody(Sema &s, cir::FuncOp cfg, QualType blockType,
const CheckFallThroughDiagnostics &cd);
ControlFlowKind checkFallThrough(cir::FuncOp cfg);
mlir::DenseSet<mlir::Block *> getLiveSet(cir::FuncOp cfg);
};

} // namespace clang

#endif // LLVM_CLANG_CIR_SEMA_FALLTHROUGHWARNING_H
3 changes: 3 additions & 0 deletions clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ class FrontendOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned ClangIRDisableCIRVerifier : 1;

/// List of ClangIR semantic analysis passes to enable
std::vector<std::string> ClangIRAnalysisList;

CodeCompleteOptions CodeCompleteOpts;

/// Specifies the output format of the AST.
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Options/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3150,6 +3150,11 @@ def clangir_disable_verifier : Flag<["-"], "clangir-disable-verifier">,
HelpText<"ClangIR: Disable MLIR module verifier">,
MarshallingInfoFlag<FrontendOpts<"ClangIRDisableCIRVerifier">>;

def fclangir_analysis_EQ : CommaJoined<["-"], "fclangir-analysis=">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Enable ClangIR semantic analysis passes. Pass comma or semicolon separated list of analysis names">,
MarshallingInfoStringVector<FrontendOpts<"ClangIRAnalysisList">>;

defm clangir : BoolFOption<"clangir",
FrontendOpts<"UseClangIRPipeline">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Use the ClangIR pipeline to compile">,
Expand Down
67 changes: 67 additions & 0 deletions clang/lib/CIR/Analysis/CIRAnalysisKind.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//===--- CIRAnalysisKind.cpp - CIR Analysis Pass Kinds -------------------===//
//
// 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 "clang/CIR/Analysis/CIRAnalysisKind.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>

namespace cir {

CIRAnalysisKind parseCIRAnalysisKind(llvm::StringRef name) {
auto parseResult = llvm::StringSwitch<CIRAnalysisKind>(name)
.Case("fallthrough", CIRAnalysisKind::FallThrough)
.Case("fall-through", CIRAnalysisKind::FallThrough)
.Default(CIRAnalysisKind::Unrecognized);

return parseResult;
}


CIRAnalysisSet parseCIRAnalysisList(
const std::vector<std::string> &analysisList,
llvm::SmallVectorImpl<std::string> *invalidNames) {
CIRAnalysisSet result;

for (const std::string &item : analysisList) {
llvm::StringRef remaining = item;
CIRAnalysisKind parseKind = parseCIRAnalysisKind(remaining);
if (parseKind == CIRAnalysisKind::Unrecognized) {
llvm::errs() << "Unrecognized CIR analysis option: " << remaining << "\n";
continue;
}
result.enable(parseKind);
}

return result;
}

void CIRAnalysisSet::print(llvm::raw_ostream &OS) const {
if (empty()) {
OS << "none";
return;
}

bool first = true;
auto printIfEnabled = [&](CIRAnalysisKind kind, llvm::StringRef name) {
if (has(kind)) {
if (!first)
OS << ", ";
OS << name;
first = false;
}
};

printIfEnabled(CIRAnalysisKind::FallThrough, "fallthrough");
printIfEnabled(CIRAnalysisKind::UnreachableCode, "unreachable-code");
printIfEnabled(CIRAnalysisKind::NullCheck, "null-check");
printIfEnabled(CIRAnalysisKind::UninitializedVar, "uninitialized-var");
}

} // namespace cir
19 changes: 19 additions & 0 deletions clang/lib/CIR/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
add_clang_library(clangCIRSema
FallThroughWarning.cpp
CIRAnalysisKind.cpp

DEPENDS
MLIRCIRPassIncGen

LINK_LIBS PUBLIC
clangAST
clangBasic

MLIRAnalysis
MLIRIR
MLIRPass
MLIRTransformUtils

MLIRCIR
MLIRCIRInterfaces
)
Loading
Loading