summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJasmine Tang <jjasmine@igalia.com>2025-11-13 11:39:38 -0800
committerJasmine Tang <jjasmine@igalia.com>2025-11-16 22:24:44 -0800
commit9c069eac2cd69aa3f35718dd0b83bee98f74262b (patch)
tree873d3c16779fa0b322983f746b6b4a18295f122d
parentf5e2c5ddcec758ffdaff027a239a163331a73292 (diff)
-rw-r--r--clang/include/clang/CIR/Dialect/Passes.h1
-rw-r--r--clang/include/clang/CIR/Dialect/Passes.td10
-rw-r--r--clang/lib/CIR/Dialect/Analysis/CMakeLists.txt18
-rw-r--r--clang/lib/CIR/Dialect/Analysis/FallThroughWarning.cpp157
-rw-r--r--clang/lib/CIR/Dialect/CMakeLists.txt1
-rw-r--r--clang/lib/FrontendTool/CMakeLists.txt1
6 files changed, 188 insertions, 0 deletions
diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h
index 32c3e27d07df..4dba6b548029 100644
--- a/clang/include/clang/CIR/Dialect/Passes.h
+++ b/clang/include/clang/CIR/Dialect/Passes.h
@@ -27,6 +27,7 @@ std::unique_ptr<Pass> createHoistAllocasPass();
std::unique_ptr<Pass> createLoweringPreparePass();
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
std::unique_ptr<Pass> createGotoSolverPass();
+std::unique_ptr<Pass> createFallThroughWarningPass();
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td
index 0f5783945f8a..6e272ddeef85 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -93,4 +93,14 @@ def LoweringPrepare : Pass<"cir-lowering-prepare"> {
let dependentDialects = ["cir::CIRDialect"];
}
+def CFGFallThroughWarnings: Pass<"cir-fallthrough-warnings"> {
+ let summary = "This pass replicates "
+ "other dialects";
+ let description = [{
+ This pass does preparation work for lowering to other dialects. For example,
+ it may expand the global variable initialziation in a more ABI-friendly form.
+ }];
+ let constructor = "mlir::createFallThroughWarningPass()";
+ let dependentDialects = ["cir::CIRDialect"];
+}
#endif // CLANG_CIR_DIALECT_PASSES_TD
diff --git a/clang/lib/CIR/Dialect/Analysis/CMakeLists.txt b/clang/lib/CIR/Dialect/Analysis/CMakeLists.txt
new file mode 100644
index 000000000000..27a5606d2570
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Analysis/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_clang_library(MLIRCIRAnalysis
+ FallThroughWarning.cpp
+
+ DEPENDS
+ MLIRCIRPassIncGen
+
+ LINK_LIBS PUBLIC
+ clangAST
+ clangBasic
+
+ MLIRAnalysis
+ MLIRIR
+ MLIRPass
+ MLIRTransformUtils
+
+ MLIRCIR
+ MLIRCIRInterfaces
+)
diff --git a/clang/lib/CIR/Dialect/Analysis/FallThroughWarning.cpp b/clang/lib/CIR/Dialect/Analysis/FallThroughWarning.cpp
new file mode 100644
index 000000000000..57cd6c5d78ff
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Analysis/FallThroughWarning.cpp
@@ -0,0 +1,157 @@
+#include "mlir/IR/Block.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/Support/LLVM.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Basic/Module.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "clang/CIR/Dialect/Passes.h"
+#include "clang/CIR/MissingFeatures.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Path.h"
+
+#include <memory>
+
+namespace mlir {
+#define GEN_PASS_DEF_CFGFALLTHROUGHWARNINGS
+#include "clang/CIR/Dialect/Passes.h.inc"
+} // namespace mlir
+using namespace mlir;
+using namespace cir;
+using namespace clang;
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+// Check for missing return value.
+//===----------------------------------------------------------------------===//
+
+enum ControlFlowKind {
+ UnknownFallThrough,
+ NeverFallThrough,
+ MaybeFallThrough,
+ AlwaysFallThrough,
+ NeverFallThroughOrReturn
+};
+
+struct CheckFallThroughDiagnostics {
+ unsigned diagFallThroughHasNoReturn = 0;
+ unsigned diagFallThroughReturnsNonVoid = 0;
+ unsigned diagNeverFallThroughOrReturn = 0;
+ unsigned funKind;
+ SourceLocation funcLoc;
+ bool checkDiagnostics(DiagnosticsEngine &d, bool returnsVoid,
+ bool hasNoReturn) const {
+ if (funKind == diag::FalloffFunctionKind::Function) {
+ return (returnsVoid ||
+ d.isIgnored(diag::warn_falloff_nonvoid, funcLoc)) &&
+ (!hasNoReturn ||
+ d.isIgnored(diag::warn_noreturn_has_return_expr, funcLoc)) &&
+ (!returnsVoid ||
+ d.isIgnored(diag::warn_suggest_noreturn_block, funcLoc));
+ }
+ if (funKind == diag::FalloffFunctionKind::Coroutine) {
+ return (returnsVoid ||
+ d.isIgnored(diag::warn_falloff_nonvoid, funcLoc)) &&
+ (!hasNoReturn);
+ }
+ // For blocks / lambdas.
+ return returnsVoid && !hasNoReturn;
+ }
+};
+// TODO: Add a class for fall through config later
+
+struct FallThroughWarningPass
+ : public impl::CFGFallThroughWarningsBase<FallThroughWarningPass> {
+public:
+ FallThroughWarningPass() = default;
+ void runOnOperation() override;
+ void checkFallThroughForFuncBody(Sema &s, cir::FuncOp func,
+ QualType blockType,
+ const CheckFallThroughDiagnostics &cd);
+ ControlFlowKind checkFallThrough(cir::FuncOp cfg);
+ mlir::DenseSet<mlir::Block> getLiveSet(cir::FuncOp cfg, bool getAll) {
+ mlir::DenseSet<mlir::Block> liveSet;
+ if (cfg.getBody().empty())
+ return liveSet;
+
+ auto &body = cfg.getBody();
+ auto &first = cfg.getBody().getBlocks().front();
+
+ for (auto &block : body) {
+ if (getAll || block.isReachable(&first))
+ liveSet.insert(block);
+ }
+ return liveSet;
+ }
+};
+
+// TODO: This runs on func op only
+void FallThroughWarningPass::runOnOperation() {
+ mlir::Operation *op = getOperation();
+ if (!isa<cir::FuncOp>(op))
+ return;
+}
+
+void FallThroughWarningPass::checkFallThroughForFuncBody(
+ Sema &s, cir::FuncOp cfg, QualType blockType,
+ const CheckFallThroughDiagnostics &cd) {
+ bool returnsVoid = false;
+ bool hasNoReturn = false;
+
+ // Supposedly all function in cir is FuncOp
+ // 1. If normal function (FunctionDecl), check if it's coroutine.
+ // 1a. if coroutine -> check the fallthrough handler (idk what this means,
+ // TODO for now)
+ if (cfg.getCoroutine()) {
+ // TODO: Let's not worry about coroutine for now
+ } else
+ returnsVoid = isa<cir::VoidType>(cfg.getFunctionType().getReturnType());
+
+ // TODO: Do we need to check for InferredNoReturnAttr just like in OG?
+ hasNoReturn = cfg.getFunctionType().getReturnTypes().empty();
+
+ DiagnosticsEngine &diags = s.getDiagnostics();
+ if (cd.checkDiagnostics(diags, returnsVoid, hasNoReturn)) {
+ return;
+ }
+
+ // cpu_dispatch functions permit empty function bodies for ICC compatibility.
+ // TODO: Do we have isCPUDispatchMultiVersion?
+
+
+
+}
+
+ControlFlowKind FallThroughWarningPass::checkFallThrough(cir::FuncOp cfg) {
+ assert(!cfg && "there can't be a null func op");
+
+ // TODO: Is no CFG akin to a declaration?
+ if (cfg.isDeclaration()) {
+ return UnknownFallThrough;
+ }
+
+ mlir::DenseSet<mlir::Block> liveSet =
+ this->getLiveSet(cfg, /*bool getAll=*/false);
+
+ unsigned count = liveSet.size();
+
+ bool hasLiveReturn = false;
+ bool hasFakeEdge = false;
+ bool hasPlainEdge = false;
+ bool hasAbnormalEdge = false;
+
+ // TODO: Do more here
+}
+} // namespace
+
+namespace mlir {
+std::unique_ptr<Pass> createFallThroughWarningPass() {
+ return std::make_unique<FallThroughWarningPass>();
+}
+} // namespace mlir
diff --git a/clang/lib/CIR/Dialect/CMakeLists.txt b/clang/lib/CIR/Dialect/CMakeLists.txt
index c825a61b2779..4c17fef0482e 100644
--- a/clang/lib/CIR/Dialect/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/CMakeLists.txt
@@ -1,3 +1,4 @@
add_subdirectory(IR)
add_subdirectory(OpenACC)
add_subdirectory(Transforms)
+add_subdirectory(Analysis)
diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt
index 66213f76eb96..0ad7141669d9 100644
--- a/clang/lib/FrontendTool/CMakeLists.txt
+++ b/clang/lib/FrontendTool/CMakeLists.txt
@@ -22,6 +22,7 @@ if(CLANG_ENABLE_CIR)
list(APPEND link_libs
clangCIRFrontendAction
MLIRCIRTransforms
+ MLIRCIRAnalysis
MLIRIR
MLIRPass
)