https://github.com/ianayl updated 
https://github.com/llvm/llvm-project/pull/230003

>From 3d967e6f36629898ecef72528512b269f163eddb Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 16:41:26 -0700
Subject: [PATCH 01/16] issue diagnostics on bad cir.triple instead of asserts

---
 .../CIR/Dialect/Transforms/CXXABILowering.cpp | 12 ++++----
 .../Dialect/Transforms/LoweringPrepare.cpp    | 10 +++++--
 .../CIR/Dialect/Transforms/TargetLowering.cpp | 12 ++++----
 .../Transforms/TargetLowering/LowerModule.cpp | 30 +++++++++++++++----
 .../Transforms/TargetLowering/LowerModule.h   |  4 ++-
 5 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index 735146b04c64f..b57b994bea88c 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -893,13 +893,15 @@ void CXXABILoweringPass::runOnOperation() {
   auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
   mlir::MLIRContext *ctx = mod.getContext();
 
-  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(mod);
+  auto diag = [&] {
+    return mod.emitWarning("cannot create a CIR lower module, skipping the ")
+              << getName() << " pass: ";
+  };
+  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(
+      mod, diag);
   // If lower module is not available, skip the ABI lowering pass.
-  if (!lowerModule) {
-    mod.emitWarning("Cannot create a CIR lower module, skipping the ")
-        << getName() << " pass";
+  if (!lowerModule)
     return;
-  }
 
   mlir::DataLayout dataLayout(mod);
   CIRABITypeConverter typeConverter(*ctx, dataLayout, *lowerModule);
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 23fb81e2f706d..106298629c65e 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -3061,9 +3061,13 @@ void 
LoweringPreparePass::buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder,
 void LoweringPreparePass::runOnOperation() {
   mlirModule = getOperation();
 
-  // CIRGen always sets the triple, so this cannot fail.
-  lowerModule = cir::createLowerModule(mlirModule);
-  assert(lowerModule && "requires a module with a triple");
+  auto diag = [&] {
+    return mlirModule.emitError("cannot create a CIR lower module for ")
+       << getName() << " pass: ";
+  };
+  lowerModule = cir::createLowerModule(mlirModule, diag);
+  if (!lowerModule)
+    return signalPassFailure();
 
   llvm::SmallVector<mlir::Operation *> opsToTransform;
 
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
index 76ca7114ee5ce..e978acda6cca9 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
@@ -296,13 +296,15 @@ 
populateTargetLoweringConversionTarget(mlir::ConversionTarget &target,
 
 void TargetLoweringPass::runOnOperation() {
   auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
-  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(mod);
+  auto diag = [&] {
+    return mod.emitWarning("cannot create a CIR lower module, skipping the ")
+              << getName() << " pass: ";
+  };
+  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(
+      mod, diag);
   // If lower module is not available, skip the target lowering pass.
-  if (!lowerModule) {
-    mod.emitWarning("Cannot create a CIR lower module, skipping the ")
-        << getName() << " pass";
+  if (!lowerModule)
     return;
-  }
 
   const auto &targetInfo = lowerModule->getTargetLoweringInfo();
 
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
index 03044286e8cf7..313661ba959f4 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
@@ -79,20 +79,39 @@ const TargetLoweringInfo 
&LowerModule::getTargetLoweringInfo() {
 }
 
 // TODO: not to create it every time
-std::unique_ptr<LowerModule> createLowerModule(mlir::ModuleOp module) {
+std::unique_ptr<LowerModule>
+createLowerModule(mlir::ModuleOp module,
+                  llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag) {
   // If the triple is not present, e.g. CIR modules parsed from text, we
   // cannot init LowerModule properly.
   assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
-  if (!module->hasAttr(cir::CIRDialect::getTripleAttrName()))
+  // TODO(triple) what this line do? ^^^
+  if (!module->hasAttr(cir::CIRDialect::getTripleAttrName())) {
+    if (emitDiag)
+      emitDiag() << "module is missing " << 
cir::CIRDialect::getTripleAttrName()
+                 << " attribute";
     return nullptr;
+  }
 
   // Fetch target information.
-  llvm::Triple triple(mlir::cast<mlir::StringAttr>(
-                          
module->getAttr(cir::CIRDialect::getTripleAttrName()))
-                          .getValue());
+  auto tripleAttr = module->getAttrOfType<mlir::StringAttr>(
+      cir::CIRDialect::getTripleAttrName());
+  if (!tripleAttr) {
+    if (emitDiag)
+      emitDiag() << "expected module's " << 
cir::CIRDialect::getTripleAttrName()
+                 << " attribute to be a string";
+    return nullptr;
+  }
+  llvm::Triple triple(tripleAttr.getValue());
   clang::TargetOptions targetOptions;
   targetOptions.Triple = triple.str();
   auto targetInfo = clang::targets::AllocateTarget(triple, targetOptions);
+  if (!targetInfo) {
+    if (emitDiag)
+      emitDiag() << "unknown triple '" << tripleAttr.getValue() << "' in "
+                 << cir::CIRDialect::getTripleAttrName() << " attribute";
+    return nullptr;
+  }
 
   // Populate the lowering-relevant LangOptions from the module's
   // #cir.lowering_lang_options attribute so a reloaded .cir lowers the same
@@ -120,6 +139,7 @@ std::unique_ptr<LowerModule> 
createLowerModule(mlir::ModuleOp module) {
   assert(!cir::MissingFeatures::lowerModuleCodeGenOpts());
   clang::CodeGenOptions codeGenOpts;
 
+  // TODO(optinfo): this cast should be more secure?
   if (auto optInfo = mlir::cast_if_present<cir::OptInfoAttr>(
           module->getAttr(cir::CIRDialect::getOptInfoAttrName()))) {
     codeGenOpts.OptimizationLevel = optInfo.getLevel();
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
index 56fcd0a9b58cd..588bc496bdaba 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
@@ -57,7 +57,9 @@ class LowerModule {
   const TargetLoweringInfo &getTargetLoweringInfo();
 };
 
-std::unique_ptr<LowerModule> createLowerModule(mlir::ModuleOp module);
+std::unique_ptr<LowerModule>
+createLowerModule(mlir::ModuleOp module,
+    llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
 
 } // namespace cir
 

>From 7148a33516414e640d560bff21c033763da991cc Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 17:13:28 -0700
Subject: [PATCH 02/16] issue diagnostics on malformed opt_info attrs

---
 .../Dialect/Transforms/TargetLowering/LowerModule.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
index 313661ba959f4..afbacbd7987a6 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
@@ -139,9 +139,14 @@ createLowerModule(mlir::ModuleOp module,
   assert(!cir::MissingFeatures::lowerModuleCodeGenOpts());
   clang::CodeGenOptions codeGenOpts;
 
-  // TODO(optinfo): this cast should be more secure?
-  if (auto optInfo = mlir::cast_if_present<cir::OptInfoAttr>(
-          module->getAttr(cir::CIRDialect::getOptInfoAttrName()))) {
+  if (auto optAttr = module->getAttr(cir::CIRDialect::getOptInfoAttrName())) {
+    auto optInfo = mlir::dyn_cast<cir::OptInfoAttr>(optAttr);
+    if (!optInfo) {
+      if (emitDiag)
+        emitDiag() << "malformed " << cir::CIRDialect::getOptInfoAttrName()
+                   << " attribute";
+      return nullptr;
+    }
     codeGenOpts.OptimizationLevel = optInfo.getLevel();
     codeGenOpts.OptimizeSize = optInfo.getSize();
   }

>From 9a939caf75ae9d058a1a5ef55ff8268191096264 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 18:28:46 -0700
Subject: [PATCH 03/16] patch up reading triples for cpuid op lowering

---
 .../Transforms/TargetLowering/LowerModule.cpp  |  1 -
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp  | 18 ++++++++++++++----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
index afbacbd7987a6..4190947e0cb4d 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
@@ -85,7 +85,6 @@ createLowerModule(mlir::ModuleOp module,
   // If the triple is not present, e.g. CIR modules parsed from text, we
   // cannot init LowerModule properly.
   assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
-  // TODO(triple) what this line do? ^^^
   if (!module->hasAttr(cir::CIRDialect::getTripleAttrName())) {
     if (emitDiag)
       emitDiag() << "module is missing " << 
cir::CIRDialect::getTripleAttrName()
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6426841e6237f..d539ad50db866 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4508,6 +4508,7 @@ void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp 
module) {
           module->getAttr(cir::CIRDialect::getTripleAttrName()))
     module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),
                     tripleAttr);
+  // TODO(triple) handle triple exception here?
 
   if (mlir::Attribute asmAttr =
           module->getAttr(cir::CIRDialect::getModuleLevelAsmAttrName()))
@@ -5819,10 +5820,19 @@ mlir::LogicalResult 
CIRToLLVMCpuIdOpLowering::matchAndRewrite(
 
   StringRef asmString, constraints;
   mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>();
-  llvm::Triple triple(
-      mlir::cast<mlir::StringAttr>(
-          moduleOp->getAttr(cir::CIRDialect::getTripleAttrName()))
-          .getValue());
+  auto tripleAttr = moduleOp->getAttr(cir::CIRDialect::getTripleAttrName());
+  if (!tripleAttr) {
+    moduleOp->emitError("module is missing a ")
+       << cir::CIRDialect::getTripleAttrName() << " attribute";
+    return mlir::failure();
+  }
+  mlir::StringAttr tripleStr = mlir::dyn_cast<mlir::StringAttr>(tripleAttr);
+  if (!tripleStr) {
+    moduleOp->emitError("expected string from module ")
+                << cir::CIRDialect::getTripleAttrName() << " attribute";
+    return mlir::failure();
+  }
+  llvm::Triple triple(tripleStr.getValue());
   if (triple.getArch() == llvm::Triple::x86) {
     asmString = "cpuid";
     constraints = "={ax},={bx},={cx},={dx},{ax},{cx}";

>From fd373da1e099dbad33241e2ab7c8afd94ebe7f7b Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 21:04:51 -0700
Subject: [PATCH 04/16] switch to unified helper for triple processing

---
 .../include/clang/CIR/Dialect/IR/CIRDialect.h |  6 +++++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 22 +++++++++++++++++++
 .../CIR/Dialect/Transforms/EHABILowering.cpp  | 10 +++------
 .../Transforms/TargetLowering/LowerModule.cpp | 22 +++++--------------
 clang/lib/CIR/Lowering/CIRPasses.cpp          | 12 +++++-----
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 ++++-----------
 6 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index d9018e93628b6..baece7ab02fc7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -99,6 +99,12 @@ RecordLayoutAttr getRecordLayout(mlir::ModuleOp mod, 
mlir::StringAttr name);
 /// Same lookup as getRecordLayout, but returns a null attribute instead of
 /// asserting when the record has no layout entry.
 RecordLayoutAttr tryGetRecordLayout(mlir::ModuleOp mod, mlir::StringAttr name);
+
+/// Attempts to construct an llvm::Triple from a module's cir.triple attribute.
+/// If emitDiag is not null, additional diagnostics information is passed into
+/// emitDiag upon failure.
+mlir::FailureOr<llvm::Triple>
+getTripleFromModule(mlir::ModuleOp mod, 
llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
 } // namespace cir
 
 // TableGen'erated files for MLIR dialects require that a macro be defined when
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 2a5cb9a908a1d..caa3527a02f11 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -402,6 +402,28 @@ static LogicalResult verifyProducedBy(Operation *op, Value 
operand,
   return success();
 }
 
+mlir::FailureOr<llvm::Triple> cir::getTripleFromModule(
+  mlir::ModuleOp mod,
+  llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag) {
+  if (!mod->hasAttr(cir::CIRDialect::getTripleAttrName())) {
+    if (emitDiag)
+      emitDiag() << "module is missing " << 
cir::CIRDialect::getTripleAttrName()
+                 << " attribute";
+    return mlir::failure();
+  }
+
+  auto tripleAttr = mod->getAttrOfType<mlir::StringAttr>(
+      cir::CIRDialect::getTripleAttrName());
+  if (!tripleAttr) {
+    if (emitDiag)
+      emitDiag() << "expected a string from module attribute "
+                 << cir::CIRDialect::getTripleAttrName();
+    return mlir::failure();
+  }
+
+  return llvm::Triple{tripleAttr.getValue()};
+}
+
 
//===----------------------------------------------------------------------===//
 // InlineKindAttr (FIXME: remove once FuncOp uses assembly format)
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index 77ce7434c8ed3..e3306227aac5e 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -1088,19 +1088,15 @@ void CIREHABILoweringPass::runOnOperation() {
   // The target triple is attached to the module as the "cir.triple"
   // attribute. If it is absent (e.g. a CIR module parsed from text without a
   // triple) we cannot determine the ABI and must skip the pass.
-  auto tripleAttr = mlir::dyn_cast_if_present<mlir::StringAttr>(
-      mod->getAttr(cir::CIRDialect::getTripleAttrName()));
-  if (!tripleAttr) {
-    mod.emitError("Module has no target triple");
+  auto triple = cir::getTripleFromModule(mod, [&] { return mod.emitWarning(); 
});
+  if (mlir::failed(triple))
     return;
-  }
 
   // Select the ABI-specific lowering handler from the triple. The Microsoft
   // C++ ABI targets a Windows MSVC environment; everything else uses Itanium.
   // Extend this when Microsoft ABI lowering is added.
-  llvm::Triple triple(tripleAttr.getValue());
   std::unique_ptr<EHABILowering> lowering;
-  if (triple.isWindowsMSVCEnvironment()) {
+  if (triple->isWindowsMSVCEnvironment()) {
     mod.emitError(
         "EH ABI lowering is not yet implemented for the Microsoft ABI");
     return signalPassFailure();
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
index 4190947e0cb4d..91a6f27ea8b16 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
@@ -85,29 +85,17 @@ createLowerModule(mlir::ModuleOp module,
   // If the triple is not present, e.g. CIR modules parsed from text, we
   // cannot init LowerModule properly.
   assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
-  if (!module->hasAttr(cir::CIRDialect::getTripleAttrName())) {
-    if (emitDiag)
-      emitDiag() << "module is missing " << 
cir::CIRDialect::getTripleAttrName()
-                 << " attribute";
-    return nullptr;
-  }
 
   // Fetch target information.
-  auto tripleAttr = module->getAttrOfType<mlir::StringAttr>(
-      cir::CIRDialect::getTripleAttrName());
-  if (!tripleAttr) {
-    if (emitDiag)
-      emitDiag() << "expected module's " << 
cir::CIRDialect::getTripleAttrName()
-                 << " attribute to be a string";
+  auto triple = cir::getTripleFromModule(module, emitDiag);
+  if (mlir::failed(triple))
     return nullptr;
-  }
-  llvm::Triple triple(tripleAttr.getValue());
   clang::TargetOptions targetOptions;
-  targetOptions.Triple = triple.str();
-  auto targetInfo = clang::targets::AllocateTarget(triple, targetOptions);
+  targetOptions.Triple = triple->str();
+  auto targetInfo = clang::targets::AllocateTarget(*triple, targetOptions);
   if (!targetInfo) {
     if (emitDiag)
-      emitDiag() << "unknown triple '" << tripleAttr.getValue() << "' in "
+      emitDiag() << "unknown triple '" << triple->str() << "' in "
                  << cir::CIRDialect::getTripleAttrName() << " attribute";
     return nullptr;
   }
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp 
b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 6e75ce03d14ff..dc4e3128ca26d 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -78,13 +78,11 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, 
mlir::MLIRContext &mlirContext,
 
   llvm::TimeTraceScope scope("CIR To CIR Passes");
 
-  auto tripleAttr = theModule->getAttrOfType<mlir::StringAttr>(
-      cir::CIRDialect::getTripleAttrName());
-  if (!tripleAttr)
-    return theModule.emitError()
-           << "missing '" << cir::CIRDialect::getTripleAttrName()
-           << "' attribute";
-  llvm::Triple triple(tripleAttr.getValue());
+  auto maybeTriple = cir::getTripleFromModule(theModule,
+      [&]{ return theModule.emitError(); });
+  if (mlir::failed(maybeTriple))
+    return mlir::LogicalResult::failure();
+  llvm::Triple &triple = *maybeTriple;
 
   auto abiAttr = theModule->getAttrOfType<mlir::StringAttr>(
       cir::CIRDialect::getTargetABIAttrName());
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index d539ad50db866..628dc160e251d 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4508,7 +4508,6 @@ void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp 
module) {
           module->getAttr(cir::CIRDialect::getTripleAttrName()))
     module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),
                     tripleAttr);
-  // TODO(triple) handle triple exception here?
 
   if (mlir::Attribute asmAttr =
           module->getAttr(cir::CIRDialect::getModuleLevelAsmAttrName()))
@@ -5820,20 +5819,11 @@ mlir::LogicalResult 
CIRToLLVMCpuIdOpLowering::matchAndRewrite(
 
   StringRef asmString, constraints;
   mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>();
-  auto tripleAttr = moduleOp->getAttr(cir::CIRDialect::getTripleAttrName());
-  if (!tripleAttr) {
-    moduleOp->emitError("module is missing a ")
-       << cir::CIRDialect::getTripleAttrName() << " attribute";
+  auto triple = cir::getTripleFromModule(moduleOp,
+      [&] { return moduleOp.emitError(); }); 
+  if (mlir::failed(triple))
     return mlir::failure();
-  }
-  mlir::StringAttr tripleStr = mlir::dyn_cast<mlir::StringAttr>(tripleAttr);
-  if (!tripleStr) {
-    moduleOp->emitError("expected string from module ")
-                << cir::CIRDialect::getTripleAttrName() << " attribute";
-    return mlir::failure();
-  }
-  llvm::Triple triple(tripleStr.getValue());
-  if (triple.getArch() == llvm::Triple::x86) {
+  if (triple->getArch() == llvm::Triple::x86) {
     asmString = "cpuid";
     constraints = "={ax},={bx},={cx},={dx},{ax},{cx}";
   } else {

>From 3c65330e55b1a8fc479a554123683a9587b785cb Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 21:16:22 -0700
Subject: [PATCH 05/16] I don't think there were any tangible benefits to using
 mlir::FailureOr, and if anything it reads worse than std::optional

---
 clang/include/clang/CIR/Dialect/IR/CIRDialect.h       |  2 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp               |  6 +++---
 clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp    |  4 ++--
 .../Dialect/Transforms/TargetLowering/LowerModule.cpp |  4 ++--
 clang/lib/CIR/Lowering/CIRPasses.cpp                  | 11 +++++------
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp   |  4 ++--
 6 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index baece7ab02fc7..732d065f81cb3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -103,7 +103,7 @@ RecordLayoutAttr tryGetRecordLayout(mlir::ModuleOp mod, 
mlir::StringAttr name);
 /// Attempts to construct an llvm::Triple from a module's cir.triple attribute.
 /// If emitDiag is not null, additional diagnostics information is passed into
 /// emitDiag upon failure.
-mlir::FailureOr<llvm::Triple>
+std::optional<llvm::Triple>
 getTripleFromModule(mlir::ModuleOp mod, 
llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
 } // namespace cir
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index caa3527a02f11..0136ed1ccd0dc 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -402,14 +402,14 @@ static LogicalResult verifyProducedBy(Operation *op, 
Value operand,
   return success();
 }
 
-mlir::FailureOr<llvm::Triple> cir::getTripleFromModule(
+std::optional<llvm::Triple> cir::getTripleFromModule(
   mlir::ModuleOp mod,
   llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag) {
   if (!mod->hasAttr(cir::CIRDialect::getTripleAttrName())) {
     if (emitDiag)
       emitDiag() << "module is missing " << 
cir::CIRDialect::getTripleAttrName()
                  << " attribute";
-    return mlir::failure();
+    return std::nullopt;
   }
 
   auto tripleAttr = mod->getAttrOfType<mlir::StringAttr>(
@@ -418,7 +418,7 @@ mlir::FailureOr<llvm::Triple> cir::getTripleFromModule(
     if (emitDiag)
       emitDiag() << "expected a string from module attribute "
                  << cir::CIRDialect::getTripleAttrName();
-    return mlir::failure();
+    return std::nullopt;
   }
 
   return llvm::Triple{tripleAttr.getValue()};
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index e3306227aac5e..72f9c786db08e 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -1088,8 +1088,8 @@ void CIREHABILoweringPass::runOnOperation() {
   // The target triple is attached to the module as the "cir.triple"
   // attribute. If it is absent (e.g. a CIR module parsed from text without a
   // triple) we cannot determine the ABI and must skip the pass.
-  auto triple = cir::getTripleFromModule(mod, [&] { return mod.emitWarning(); 
});
-  if (mlir::failed(triple))
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(mod, [&] { 
return mod.emitWarning(); });
+  if (!triple)
     return;
 
   // Select the ABI-specific lowering handler from the triple. The Microsoft
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
index 91a6f27ea8b16..b6f6031ddaf2d 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
@@ -87,8 +87,8 @@ createLowerModule(mlir::ModuleOp module,
   assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
 
   // Fetch target information.
-  auto triple = cir::getTripleFromModule(module, emitDiag);
-  if (mlir::failed(triple))
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(module, 
emitDiag);
+  if (!triple)
     return nullptr;
   clang::TargetOptions targetOptions;
   targetOptions.Triple = triple->str();
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp 
b/clang/lib/CIR/Lowering/CIRPasses.cpp
index dc4e3128ca26d..0158c7fe37309 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -78,11 +78,10 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, 
mlir::MLIRContext &mlirContext,
 
   llvm::TimeTraceScope scope("CIR To CIR Passes");
 
-  auto maybeTriple = cir::getTripleFromModule(theModule,
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(theModule,
       [&]{ return theModule.emitError(); });
-  if (mlir::failed(maybeTriple))
+  if (!triple)
     return mlir::LogicalResult::failure();
-  llvm::Triple &triple = *maybeTriple;
 
   auto abiAttr = theModule->getAttrOfType<mlir::StringAttr>(
       cir::CIRDialect::getTargetABIAttrName());
@@ -126,7 +125,7 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, 
mlir::MLIRContext &mlirContext,
     // so it must run after CXXABILowering has lowered C++ ABI types to plain
     // records the classifier can handle.  Only the x86_64 System V classifier
     // is implemented; other targets are left unchanged.
-    CallConvTarget target = getCallConvTarget(triple);
+    CallConvTarget target = getCallConvTarget(triple.value());
     if (target != CallConvTarget::None) {
       // Source the ABI-compatibility version from the module's serialized
       // #cir.lowering_lang_options so a reloaded .cir classifies the same way
@@ -141,8 +140,8 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, 
mlir::MLIRContext &mlirContext,
             loweringLangOpts.getClangAbiCompat());
       pm.addPass(mlir::createCallConvLoweringPass(
           target, getX86AVXABILevel(abiAttr.getValue()),
-          allowsX86TargetAttrAvx(triple, compat),
-          getX86ABICompatInfo(triple, compat)));
+          allowsX86TargetAttrAvx(triple.value(), compat),
+          getX86ABICompatInfo(triple.value(), compat)));
     }
   }
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 628dc160e251d..0903de9c77f20 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -5819,9 +5819,9 @@ mlir::LogicalResult 
CIRToLLVMCpuIdOpLowering::matchAndRewrite(
 
   StringRef asmString, constraints;
   mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>();
-  auto triple = cir::getTripleFromModule(moduleOp,
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(moduleOp,
       [&] { return moduleOp.emitError(); }); 
-  if (mlir::failed(triple))
+  if (!triple)
     return mlir::failure();
   if (triple->getArch() == llvm::Triple::x86) {
     asmString = "cpuid";

>From 72963ed03bbd69e613943ae2dbdf68a030dcc87a Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 21:21:56 -0700
Subject: [PATCH 06/16] copy cir-opt additions from #229575

---
 clang/tools/cir-opt/cir-opt.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/clang/tools/cir-opt/cir-opt.cpp b/clang/tools/cir-opt/cir-opt.cpp
index fdaf405441003..0a0c791ae494e 100644
--- a/clang/tools/cir-opt/cir-opt.cpp
+++ b/clang/tools/cir-opt/cir-opt.cpp
@@ -82,6 +82,18 @@ int main(int argc, char **argv) {
     return mlir::createCXXABILoweringPass();
   });
 
+  ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> {
+    return mlir::createTargetLoweringPass();
+  });
+
+  ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> {
+    return mlir::createLoweringPreparePass();
+  });
+
+  ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> {
+    return mlir::createLibOptPass();
+  });
+
   ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> {
     return mlir::createIdiomRecognizerPass();
   });

>From 362290cca48ef863cc0ad67290338d0d85fbca7e Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 21:35:01 -0700
Subject: [PATCH 07/16] clang-format

---
 clang/include/clang/CIR/Dialect/IR/CIRDialect.h             | 5 +++--
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp                     | 4 ++--
 clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp         | 6 +++---
 clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp          | 3 ++-
 clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp        | 2 +-
 clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp         | 6 +++---
 .../CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp   | 3 ++-
 .../lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h | 4 ++--
 clang/lib/CIR/Lowering/CIRPasses.cpp                        | 4 ++--
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp         | 4 ++--
 10 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index 732d065f81cb3..662942fdeda04 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -103,8 +103,9 @@ RecordLayoutAttr tryGetRecordLayout(mlir::ModuleOp mod, 
mlir::StringAttr name);
 /// Attempts to construct an llvm::Triple from a module's cir.triple attribute.
 /// If emitDiag is not null, additional diagnostics information is passed into
 /// emitDiag upon failure.
-std::optional<llvm::Triple>
-getTripleFromModule(mlir::ModuleOp mod, 
llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
+std::optional<llvm::Triple> getTripleFromModule(
+    mlir::ModuleOp mod,
+    llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
 } // namespace cir
 
 // TableGen'erated files for MLIR dialects require that a macro be defined when
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 0136ed1ccd0dc..7a208cf4f1b00 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -403,8 +403,8 @@ static LogicalResult verifyProducedBy(Operation *op, Value 
operand,
 }
 
 std::optional<llvm::Triple> cir::getTripleFromModule(
-  mlir::ModuleOp mod,
-  llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag) {
+    mlir::ModuleOp mod,
+    llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag) {
   if (!mod->hasAttr(cir::CIRDialect::getTripleAttrName())) {
     if (emitDiag)
       emitDiag() << "module is missing " << 
cir::CIRDialect::getTripleAttrName()
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index b57b994bea88c..7c7de931fdc70 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -895,10 +895,10 @@ void CXXABILoweringPass::runOnOperation() {
 
   auto diag = [&] {
     return mod.emitWarning("cannot create a CIR lower module, skipping the ")
-              << getName() << " pass: ";
+           << getName() << " pass: ";
   };
-  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(
-      mod, diag);
+  std::unique_ptr<cir::LowerModule> lowerModule =
+      cir::createLowerModule(mod, diag);
   // If lower module is not available, skip the ABI lowering pass.
   if (!lowerModule)
     return;
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index 72f9c786db08e..668016a432308 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -1088,7 +1088,8 @@ void CIREHABILoweringPass::runOnOperation() {
   // The target triple is attached to the module as the "cir.triple"
   // attribute. If it is absent (e.g. a CIR module parsed from text without a
   // triple) we cannot determine the ABI and must skip the pass.
-  std::optional<llvm::Triple> triple = cir::getTripleFromModule(mod, [&] { 
return mod.emitWarning(); });
+  std::optional<llvm::Triple> triple =
+      cir::getTripleFromModule(mod, [&] { return mod.emitWarning(); });
   if (!triple)
     return;
 
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 106298629c65e..e35eb52fabda2 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -3063,7 +3063,7 @@ void LoweringPreparePass::runOnOperation() {
 
   auto diag = [&] {
     return mlirModule.emitError("cannot create a CIR lower module for ")
-       << getName() << " pass: ";
+           << getName() << " pass: ";
   };
   lowerModule = cir::createLowerModule(mlirModule, diag);
   if (!lowerModule)
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
index e978acda6cca9..f545fbb6bbecf 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
@@ -298,10 +298,10 @@ void TargetLoweringPass::runOnOperation() {
   auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
   auto diag = [&] {
     return mod.emitWarning("cannot create a CIR lower module, skipping the ")
-              << getName() << " pass: ";
+           << getName() << " pass: ";
   };
-  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(
-      mod, diag);
+  std::unique_ptr<cir::LowerModule> lowerModule =
+      cir::createLowerModule(mod, diag);
   // If lower module is not available, skip the target lowering pass.
   if (!lowerModule)
     return;
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
index b6f6031ddaf2d..a5ee43c544344 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
@@ -87,7 +87,8 @@ createLowerModule(mlir::ModuleOp module,
   assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
 
   // Fetch target information.
-  std::optional<llvm::Triple> triple = cir::getTripleFromModule(module, 
emitDiag);
+  std::optional<llvm::Triple> triple =
+      cir::getTripleFromModule(module, emitDiag);
   if (!triple)
     return nullptr;
   clang::TargetOptions targetOptions;
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
index 588bc496bdaba..dbd28430c6df3 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
@@ -57,8 +57,8 @@ class LowerModule {
   const TargetLoweringInfo &getTargetLoweringInfo();
 };
 
-std::unique_ptr<LowerModule>
-createLowerModule(mlir::ModuleOp module,
+std::unique_ptr<LowerModule> createLowerModule(
+    mlir::ModuleOp module,
     llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
 
 } // namespace cir
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp 
b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 0158c7fe37309..cbc0c515bf275 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -78,8 +78,8 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext 
&mlirContext,
 
   llvm::TimeTraceScope scope("CIR To CIR Passes");
 
-  std::optional<llvm::Triple> triple = cir::getTripleFromModule(theModule,
-      [&]{ return theModule.emitError(); });
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(
+      theModule, [&] { return theModule.emitError(); });
   if (!triple)
     return mlir::LogicalResult::failure();
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0903de9c77f20..dc99dd0b439b0 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -5819,8 +5819,8 @@ mlir::LogicalResult 
CIRToLLVMCpuIdOpLowering::matchAndRewrite(
 
   StringRef asmString, constraints;
   mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>();
-  std::optional<llvm::Triple> triple = cir::getTripleFromModule(moduleOp,
-      [&] { return moduleOp.emitError(); }); 
+  std::optional<llvm::Triple> triple =
+      cir::getTripleFromModule(moduleOp, [&] { return moduleOp.emitError(); });
   if (!triple)
     return mlir::failure();
   if (triple->getArch() == llvm::Triple::x86) {

>From 15677e38ac14face59e9174713c7cc2e87596d00 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Wed, 7 Oct 2026 23:36:53 -0700
Subject: [PATCH 08/16] draft up test cases

---
 .../CIR/Lowering/cir-to-llvm-module-attrs.cir |  49 +++++++
 .../Transforms/cxx-abi-lowering-bad-attrs.cir | 137 ++++++++++++++++++
 .../Transforms/eh-abi-lowering-bad-attrs.cir  |  41 ++++++
 .../lowering-prepare-module-attrs.cir         | 130 +++++++++++++++++
 .../target-lowering-module-attrs.cir          | 137 ++++++++++++++++++
 5 files changed, 494 insertions(+)
 create mode 100644 clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
 create mode 100644 clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir
 create mode 100644 clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir
 create mode 100644 clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir
 create mode 100644 clang/test/CIR/Transforms/target-lowering-module-attrs.cir

diff --git a/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir 
b/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
new file mode 100644
index 0000000000000..ed861075a5c36
--- /dev/null
+++ b/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
@@ -0,0 +1,49 @@
+// RUN: cir-opt %s -cir-to-llvm -verify-diagnostics -split-input-file
+// RUN: not cir-opt %s -cir-to-llvm -split-input-file 2>/dev/null \
+// RUN:   | FileCheck %s --implicit-check-not=llvm.func
+
+// -cir-to-llvm relies on cir.triple module attributes: Check that missing or
+// malformed cir.triple attributes read by -cir-to-llvm do not cause asserts or
+// compiler crashes, and are diagnosed properly.
+
+
+// Missing cir.triple.
+
+!s32i = !cir.int<s, 32>
+// expected-warning @below {{module is missing cir.triple attribute}}
+// expected-error @below {{module is missing cir.triple attribute}}
+module {
+  cir.func @missing_triple(%p: !cir.ptr<!s32i>, %a: !s32i, %b: !s32i) {
+    // expected-error @below {{failed to legalize operation 'cir.cpuid'}}
+    cir.cpuid %p, %a, %b : !cir.ptr<!s32i>, !s32i, !s32i
+    cir.return
+  }
+}
+
+// -----
+
+// Non-string cir.triple.
+
+!s32i = !cir.int<s, 32>
+// expected-warning @below {{expected a string from module attribute 
cir.triple}}
+// expected-error @below {{expected a string from module attribute cir.triple}}
+module attributes {cir.triple = 42 : i32} {
+  cir.func @non_string_triple(%p: !cir.ptr<!s32i>, %a: !s32i, %b: !s32i) {
+    // expected-error @below {{failed to legalize operation 'cir.cpuid'}}
+    cir.cpuid %p, %a, %b : !cir.ptr<!s32i>, !s32i, !s32i
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple.
+
+!s32i = !cir.int<s, 32>
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // CHECK-LABEL: llvm.func @valid_triple(
+  cir.func @valid_triple(%p: !cir.ptr<!s32i>, %a: !s32i, %b: !s32i) {
+    cir.cpuid %p, %a, %b : !cir.ptr<!s32i>, !s32i, !s32i
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir 
b/clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir
new file mode 100644
index 0000000000000..5d13956c63af4
--- /dev/null
+++ b/clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir
@@ -0,0 +1,137 @@
+// RUN: cir-opt %s -cir-cxxabi-lowering -verify-diagnostics -split-input-file
+// RUN: cir-opt %s -cir-cxxabi-lowering -split-input-file 2>/dev/null | 
FileCheck %s
+
+// Check that missing or malformed module attributes required/used by
+// -cir-cxxabi-lowering do not cause asserts or compiler crashes, and are
+// diagnosed properly. The pass should warn and skip instead of failing, so
+// every module is still printed.
+
+
+// Missing cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: module is missing cir.triple attribute}}
+module {
+  // CHECK-LABEL: cir.func @missing_triple(
+  cir.func @missing_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Non-string cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: expected a string from module attribute cir.triple}}
+module attributes {cir.triple = 42 : i32} {
+  // CHECK-LABEL: cir.func @non_string_triple(
+  cir.func @non_string_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Empty cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: unknown triple '' in cir.triple attribute}}
+module attributes {cir.triple = ""} {
+  // CHECK-LABEL: cir.func @empty_triple(
+  cir.func @empty_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Malformed cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: unknown triple 'garbage' in cir.triple attribute}}
+module attributes {cir.triple = "garbage"} {
+  // CHECK-LABEL: cir.func @malformed_triple(
+  cir.func @malformed_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Well-formed cir.triple with an unknown target.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: unknown triple 'foobar-unknown-unknown' in cir.triple 
attribute}}
+module attributes {cir.triple = "foobar-unknown-unknown"} {
+  // CHECK-LABEL: cir.func @unknown_triple(
+  cir.func @unknown_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple without cir.opt_info.
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // CHECK-LABEL: cir.func @valid_triple(
+  cir.func @valid_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a valid cir.opt_info.
+
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = #cir.opt_info<level = 2, size = 1>
+} {
+  // CHECK-LABEL: cir.func @valid_opt_info(
+  cir.func @valid_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a cir.opt_info that is not an OptInfoAttr.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = 1 : i32
+} {
+  // CHECK-LABEL: cir.func @malformed_opt_info(
+  cir.func @malformed_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a string cir.opt_info.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = "O2"
+} {
+  // CHECK-LABEL: cir.func @string_opt_info(
+  cir.func @string_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a dictionary cir.opt_info that mimics OptInfoAttr's
+// fields.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = {level = 2 : i32, size = 1 : i32}
+} {
+  // CHECK-LABEL: cir.func @dict_opt_info(
+  cir.func @dict_opt_info() {
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir 
b/clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir
new file mode 100644
index 0000000000000..fc4be2550cb3b
--- /dev/null
+++ b/clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir
@@ -0,0 +1,41 @@
+// RUN: cir-opt %s -cir-eh-abi-lowering -verify-diagnostics -split-input-file
+// RUN: cir-opt %s -cir-eh-abi-lowering -split-input-file 2>/dev/null | 
FileCheck %s
+
+// Check that missing or malformed cir.triple attributes required by
+// -cir-eh-abi-lowering do not cause asserts or compiler crashes, and are
+// diagnosed properly. The pass should warn and skip instead of failing, so
+// every module is still printed.
+
+
+// Missing cir.triple.
+
+// expected-warning @below {{module is missing cir.triple attribute}}
+module {
+  // CHECK-LABEL: cir.func @missing_triple(
+  cir.func @missing_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Non-string cir.triple.
+
+// expected-warning @below {{expected a string from module attribute 
cir.triple}}
+module attributes {cir.triple = 42 : i32} {
+  // CHECK-LABEL: cir.func @non_string_triple(
+  cir.func @non_string_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple.
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // CHECK-LABEL: cir.func @valid_triple(
+  cir.func @valid_triple() {
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir 
b/clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir
new file mode 100644
index 0000000000000..f42bad16d7bc3
--- /dev/null
+++ b/clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir
@@ -0,0 +1,130 @@
+// RUN: cir-opt %s -cir-lowering-prepare -verify-diagnostics -split-input-file
+// RUN: not cir-opt %s -cir-lowering-prepare -split-input-file 2>/dev/null \
+// RUN:   | FileCheck %s --implicit-check-not=cir.func
+
+// Check that missing or malformed module attributes required/used by
+// -cir-lowering-prepare do not cause asserts or compiler crashes, and are
+// diagnosed properly. The pass should fail on bad attributes, so only modules
+// with valid attributes are printed.
+
+
+// Missing cir.triple.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: module is missing cir.triple attribute}}
+module {
+  cir.func @missing_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Non-string cir.triple.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: expected a string from module attribute cir.triple}}
+module attributes {cir.triple = 42 : i32} {
+  cir.func @non_string_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Empty cir.triple.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: unknown triple '' in cir.triple attribute}}
+module attributes {cir.triple = ""} {
+  cir.func @empty_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Malformed cir.triple.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: unknown triple 'garbage' in cir.triple attribute}}
+module attributes {cir.triple = "garbage"} {
+  cir.func @malformed_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Well-formed cir.triple with an unknown target.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: unknown triple 'foobar-unknown-unknown' in cir.triple 
attribute}}
+module attributes {cir.triple = "foobar-unknown-unknown"} {
+  cir.func @unknown_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple without cir.opt_info.
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // CHECK-LABEL: cir.func @valid_triple(
+  cir.func @valid_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a valid cir.opt_info.
+
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = #cir.opt_info<level = 2, size = 1>
+} {
+  // CHECK-LABEL: cir.func @valid_opt_info(
+  cir.func @valid_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a cir.opt_info that is not an OptInfoAttr.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = 1 : i32
+} {
+  cir.func @malformed_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a string cir.opt_info.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = "O2"
+} {
+  cir.func @string_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a dictionary cir.opt_info that mimics OptInfoAttr's
+// fields.
+
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = {level = 2 : i32, size = 1 : i32}
+} {
+  cir.func @dict_opt_info() {
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/Transforms/target-lowering-module-attrs.cir 
b/clang/test/CIR/Transforms/target-lowering-module-attrs.cir
new file mode 100644
index 0000000000000..36813d4d707a4
--- /dev/null
+++ b/clang/test/CIR/Transforms/target-lowering-module-attrs.cir
@@ -0,0 +1,137 @@
+// RUN: cir-opt %s -cir-target-lowering -verify-diagnostics -split-input-file
+// RUN: cir-opt %s -cir-target-lowering -split-input-file 2>/dev/null | 
FileCheck %s
+
+// Check that missing or malformed module attributes required/used by
+// -cir-target-lowering do not cause asserts or compiler crashes, and are
+// diagnosed properly. The pass should warn and skip instead of failing, so
+// every module is still printed.
+
+
+// Missing cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: module is missing cir.triple attribute}}
+module {
+  // CHECK-LABEL: cir.func @missing_triple(
+  cir.func @missing_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Non-string cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: expected a string from module attribute cir.triple}}
+module attributes {cir.triple = 42 : i32} {
+  // CHECK-LABEL: cir.func @non_string_triple(
+  cir.func @non_string_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Empty cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: unknown triple '' in cir.triple attribute}}
+module attributes {cir.triple = ""} {
+  // CHECK-LABEL: cir.func @empty_triple(
+  cir.func @empty_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Malformed cir.triple.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: unknown triple 'garbage' in cir.triple attribute}}
+module attributes {cir.triple = "garbage"} {
+  // CHECK-LABEL: cir.func @malformed_triple(
+  cir.func @malformed_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Well-formed cir.triple with an unknown target.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: unknown triple 'foobar-unknown-unknown' in cir.triple 
attribute}}
+module attributes {cir.triple = "foobar-unknown-unknown"} {
+  // CHECK-LABEL: cir.func @unknown_triple(
+  cir.func @unknown_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple without cir.opt_info.
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // CHECK-LABEL: cir.func @valid_triple(
+  cir.func @valid_triple() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a valid cir.opt_info.
+
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = #cir.opt_info<level = 2, size = 1>
+} {
+  // CHECK-LABEL: cir.func @valid_opt_info(
+  cir.func @valid_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a cir.opt_info that is not an OptInfoAttr.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = 1 : i32
+} {
+  // CHECK-LABEL: cir.func @malformed_opt_info(
+  cir.func @malformed_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a string cir.opt_info.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = "O2"
+} {
+  // CHECK-LABEL: cir.func @string_opt_info(
+  cir.func @string_opt_info() {
+    cir.return
+  }
+}
+
+// -----
+
+// Valid cir.triple with a dictionary cir.opt_info that mimics OptInfoAttr's
+// fields.
+
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: malformed cir.opt_info attribute}}
+module attributes {
+  cir.triple = "x86_64-unknown-linux-gnu",
+  cir.opt_info = {level = 2 : i32, size = 1 : i32}
+} {
+  // CHECK-LABEL: cir.func @dict_opt_info(
+  cir.func @dict_opt_info() {
+    cir.return
+  }
+}

>From aeaa75c8a3307620b83229d3d6a8b2ad12815926 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Thu, 8 Oct 2026 00:28:43 -0700
Subject: [PATCH 09/16] this test case is already covered in
 lowering-prepare-module-attrs.cir

---
 clang/test/CIR/Transforms/lowering-prepare-no-triple.cir | 5 -----
 1 file changed, 5 deletions(-)
 delete mode 100644 clang/test/CIR/Transforms/lowering-prepare-no-triple.cir

diff --git a/clang/test/CIR/Transforms/lowering-prepare-no-triple.cir 
b/clang/test/CIR/Transforms/lowering-prepare-no-triple.cir
deleted file mode 100644
index bebdf3dd57f73..0000000000000
--- a/clang/test/CIR/Transforms/lowering-prepare-no-triple.cir
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: cir-opt %s --cir-lowering-prepare -verify-diagnostics
-
-// expected-error @below {{cir-lowering-prepare requires a module with a 
triple}}
-module {
-}

>From 12140d978c541100c9fbad75c5a79a12ae5d839e Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Thu, 8 Oct 2026 18:53:32 -0700
Subject: [PATCH 10/16] update cir.cpuid op lowering diagnostics to provide
 more info

---
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp  |  7 +++++--
 clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir | 10 +++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index a74cdbff3d3bd..8a49790120c5f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -5830,8 +5830,11 @@ mlir::LogicalResult 
CIRToLLVMCpuIdOpLowering::matchAndRewrite(
 
   StringRef asmString, constraints;
   mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>();
-  std::optional<llvm::Triple> triple =
-      cir::getTripleFromModule(moduleOp, [&] { return moduleOp.emitError(); });
+  auto diag = [&] {
+    return moduleOp.emitError("cannot lower ")
+           << op.getOperationName() << " op: ";
+  };
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(moduleOp, 
diag);
   if (!triple)
     return mlir::failure();
   if (triple->getArch() == llvm::Triple::x86) {
diff --git a/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir 
b/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
index ed861075a5c36..0cf5c4a3327c3 100644
--- a/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
+++ b/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
@@ -2,16 +2,16 @@
 // RUN: not cir-opt %s -cir-to-llvm -split-input-file 2>/dev/null \
 // RUN:   | FileCheck %s --implicit-check-not=llvm.func
 
-// -cir-to-llvm relies on cir.triple module attributes: Check that missing or
-// malformed cir.triple attributes read by -cir-to-llvm do not cause asserts or
-// compiler crashes, and are diagnosed properly.
+// -cir-to-llvm relies on cir.triple module attributes to handle cir.cpuid ops:
+// Check that missing or malformed cir.triple attributes read by -cir-to-llvm 
do
+// not cause asserts or compiler crashes, and are diagnosed properly.
 
 
 // Missing cir.triple.
 
 !s32i = !cir.int<s, 32>
 // expected-warning @below {{module is missing cir.triple attribute}}
-// expected-error @below {{module is missing cir.triple attribute}}
+// expected-error @below {{cannot lower cir.cpuid op: module is missing 
cir.triple attribute}}
 module {
   cir.func @missing_triple(%p: !cir.ptr<!s32i>, %a: !s32i, %b: !s32i) {
     // expected-error @below {{failed to legalize operation 'cir.cpuid'}}
@@ -26,7 +26,7 @@ module {
 
 !s32i = !cir.int<s, 32>
 // expected-warning @below {{expected a string from module attribute 
cir.triple}}
-// expected-error @below {{expected a string from module attribute cir.triple}}
+// expected-error @below {{cannot lower cir.cpuid op: expected a string from 
module attribute cir.triple}}
 module attributes {cir.triple = 42 : i32} {
   cir.func @non_string_triple(%p: !cir.ptr<!s32i>, %a: !s32i, %b: !s32i) {
     // expected-error @below {{failed to legalize operation 'cir.cpuid'}}

>From 9f08e15b96a4302654f397cd5302e788c0b282ff Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 13 Oct 2026 13:05:35 -0700
Subject: [PATCH 11/16] WIP: remove diagnostics from createLowerModule and move
 checking and validation to verifyOperationAttrs

---
 .../include/clang/CIR/Dialect/IR/CIRDialect.h |  6 +--
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 45 +++++++++++++------
 .../CIR/Dialect/Transforms/CXXABILowering.cpp | 12 +++--
 .../Dialect/Transforms/LoweringPrepare.cpp    |  9 ++--
 .../CIR/Dialect/Transforms/TargetLowering.cpp | 12 +++--
 .../Transforms/TargetLowering/LowerModule.cpp | 18 ++------
 .../Transforms/TargetLowering/LowerModule.h   |  4 +-
 7 files changed, 52 insertions(+), 54 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index 662942fdeda04..764a48787dbd0 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -101,11 +101,7 @@ RecordLayoutAttr getRecordLayout(mlir::ModuleOp mod, 
mlir::StringAttr name);
 RecordLayoutAttr tryGetRecordLayout(mlir::ModuleOp mod, mlir::StringAttr name);
 
 /// Attempts to construct an llvm::Triple from a module's cir.triple attribute.
-/// If emitDiag is not null, additional diagnostics information is passed into
-/// emitDiag upon failure.
-std::optional<llvm::Triple> getTripleFromModule(
-    mlir::ModuleOp mod,
-    llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
+std::optional<llvm::Triple> getTripleFromModule(mlir::ModuleOp mod);
 } // namespace cir
 
 // TableGen'erated files for MLIR dialects require that a macro be defined when
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index f7c4955d9ba53..4d62441f26d2c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -12,6 +12,7 @@
 
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 
+#include "clang/Basic/TargetInfo.h"
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
@@ -287,6 +288,31 @@ cir::CIRDialect::verifyOperationAttribute(mlir::Operation 
*op,
                                        /*trailingZerosNum=*/0);
   }
 
+  if (attrName == getTripleAttrName()) {
+    auto tripleStr = mlir::dyn_cast<mlir::StringAttr>(attr.getValue());
+    if (!tripleStr)
+      return op->emitOpError() << "expects '" << getTripleAttrName() << "' to "
+                               << " be a string";
+    llvm::Triple triple = llvm::Triple(tripleStr.getValue());
+    clang::TargetOptions targetOptions;
+    targetOptions.Triple = tripleStr.getValue();
+    // "Validate" our triple by checking if it can successfully initialize into
+    // a TargetInfo:
+    if (!clang::targets::AllocateTarget(triple, targetOptions)) {
+      return op->emitOpError() << "unknown triple '" << tripleStr.getValue()
+                               << "' in '" << getTripleAttrName()
+                               << "' attribute";
+    }
+  }
+
+  if (attrName == getOptInfoAttrName()) {
+    auto optInfo = mlir::dyn_cast<cir::OptInfoAttr>(attr.getValue());
+    if (!optInfo)
+      return op->emitOpError() << "malformed "
+                               << cir::CIRDialect::getOptInfoAttrName()
+                               << " attribute";
+  }
+
   return success();
 }
 
@@ -402,24 +428,17 @@ static LogicalResult verifyProducedBy(Operation *op, 
Value operand,
   return success();
 }
 
-std::optional<llvm::Triple> cir::getTripleFromModule(
-    mlir::ModuleOp mod,
-    llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag) {
-  if (!mod->hasAttr(cir::CIRDialect::getTripleAttrName())) {
-    if (emitDiag)
-      emitDiag() << "module is missing " << 
cir::CIRDialect::getTripleAttrName()
-                 << " attribute";
+std::optional<llvm::Triple> cir::getTripleFromModule(mlir::ModuleOp mod) {
+  // Verifying the validity of the triple attribute happens in
+  // cir::CIRDialect::verifyOperationAttribute; verifyOperationAttribute
+  // should error first if we have an invalid attribute. 
+  if (!mod->hasAttr(cir::CIRDialect::getTripleAttrName()))
     return std::nullopt;
-  }
 
   auto tripleAttr = mod->getAttrOfType<mlir::StringAttr>(
       cir::CIRDialect::getTripleAttrName());
-  if (!tripleAttr) {
-    if (emitDiag)
-      emitDiag() << "expected a string from module attribute "
-                 << cir::CIRDialect::getTripleAttrName();
+  if (!tripleAttr)
     return std::nullopt;
-  }
 
   return llvm::Triple{tripleAttr.getValue()};
 }
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index c7aa0dc68f686..6f4fa4176890c 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -900,15 +900,13 @@ void CXXABILoweringPass::runOnOperation() {
   auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
   mlir::MLIRContext *ctx = mod.getContext();
 
-  auto diag = [&] {
-    return mod.emitWarning("cannot create a CIR lower module, skipping the ")
-           << getName() << " pass: ";
-  };
-  std::unique_ptr<cir::LowerModule> lowerModule =
-      cir::createLowerModule(mod, diag);
+  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(mod);
   // If lower module is not available, skip the ABI lowering pass.
-  if (!lowerModule)
+  if (!lowerModule) {
+    mod.emitWarning("cannot create a CIR lower module, skipping the ")
+           << getName() << " pass: ";
     return;
+  }
 
   mlir::DataLayout dataLayout(mod);
   CIRABITypeConverter typeConverter(*ctx, dataLayout, *lowerModule);
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 5d846af5b64dc..13d12012423c6 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -3181,13 +3181,12 @@ void 
LoweringPreparePass::buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder,
 void LoweringPreparePass::runOnOperation() {
   mlirModule = getOperation();
 
-  auto diag = [&] {
-    return mlirModule.emitError("cannot create a CIR lower module for ")
+  lowerModule = cir::createLowerModule(mlirModule);
+  if (!lowerModule) {
+    mlirModule.emitError("cannot create a CIR lower module for ")
            << getName() << " pass: ";
-  };
-  lowerModule = cir::createLowerModule(mlirModule, diag);
-  if (!lowerModule)
     return signalPassFailure();
+  }
 
   llvm::SmallVector<mlir::Operation *> opsToTransform;
 
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
index f545fbb6bbecf..40e956c540471 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
@@ -296,15 +296,13 @@ 
populateTargetLoweringConversionTarget(mlir::ConversionTarget &target,
 
 void TargetLoweringPass::runOnOperation() {
   auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
-  auto diag = [&] {
-    return mod.emitWarning("cannot create a CIR lower module, skipping the ")
-           << getName() << " pass: ";
-  };
-  std::unique_ptr<cir::LowerModule> lowerModule =
-      cir::createLowerModule(mod, diag);
+  std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(mod);
   // If lower module is not available, skip the target lowering pass.
-  if (!lowerModule)
+  if (!lowerModule) {
+    mod.emitWarning("cannot create a CIR lower module, skipping the ")
+           << getName() << " pass: ";
     return;
+  }
 
   const auto &targetInfo = lowerModule->getTargetLoweringInfo();
 
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
index a5ee43c544344..f05fe7a1645c0 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp
@@ -80,26 +80,20 @@ const TargetLoweringInfo 
&LowerModule::getTargetLoweringInfo() {
 
 // TODO: not to create it every time
 std::unique_ptr<LowerModule>
-createLowerModule(mlir::ModuleOp module,
-                  llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag) {
+createLowerModule(mlir::ModuleOp module) {
   // If the triple is not present, e.g. CIR modules parsed from text, we
   // cannot init LowerModule properly.
   assert(!cir::MissingFeatures::makeTripleAlwaysPresent());
 
   // Fetch target information.
-  std::optional<llvm::Triple> triple =
-      cir::getTripleFromModule(module, emitDiag);
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(module);
   if (!triple)
     return nullptr;
   clang::TargetOptions targetOptions;
   targetOptions.Triple = triple->str();
   auto targetInfo = clang::targets::AllocateTarget(*triple, targetOptions);
-  if (!targetInfo) {
-    if (emitDiag)
-      emitDiag() << "unknown triple '" << triple->str() << "' in "
-                 << cir::CIRDialect::getTripleAttrName() << " attribute";
+  if (!targetInfo)
     return nullptr;
-  }
 
   // Populate the lowering-relevant LangOptions from the module's
   // #cir.lowering_lang_options attribute so a reloaded .cir lowers the same
@@ -129,12 +123,8 @@ createLowerModule(mlir::ModuleOp module,
 
   if (auto optAttr = module->getAttr(cir::CIRDialect::getOptInfoAttrName())) {
     auto optInfo = mlir::dyn_cast<cir::OptInfoAttr>(optAttr);
-    if (!optInfo) {
-      if (emitDiag)
-        emitDiag() << "malformed " << cir::CIRDialect::getOptInfoAttrName()
-                   << " attribute";
+    if (!optInfo)
       return nullptr;
-    }
     codeGenOpts.OptimizationLevel = optInfo.getLevel();
     codeGenOpts.OptimizeSize = optInfo.getSize();
   }
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
index dbd28430c6df3..56fcd0a9b58cd 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h
@@ -57,9 +57,7 @@ class LowerModule {
   const TargetLoweringInfo &getTargetLoweringInfo();
 };
 
-std::unique_ptr<LowerModule> createLowerModule(
-    mlir::ModuleOp module,
-    llvm::function_ref<mlir::InFlightDiagnostic()> emitDiag = nullptr);
+std::unique_ptr<LowerModule> createLowerModule(mlir::ModuleOp module);
 
 } // namespace cir
 

>From 7cac1228b6ec312044ba83075e68ff5ea33c94a4 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 13 Oct 2026 21:16:31 -0700
Subject: [PATCH 12/16] complete removing diags and moving validation to
 verifyOperationAttrs

---
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp             | 2 +-
 clang/lib/CIR/Lowering/CIRPasses.cpp                | 3 +--
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 6 +-----
 clang/test/CIR/Input/cir-input-invalid.cir          | 5 +++--
 4 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 4d62441f26d2c..06c88dfb78d48 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -292,7 +292,7 @@ cir::CIRDialect::verifyOperationAttribute(mlir::Operation 
*op,
     auto tripleStr = mlir::dyn_cast<mlir::StringAttr>(attr.getValue());
     if (!tripleStr)
       return op->emitOpError() << "expects '" << getTripleAttrName() << "' to "
-                               << " be a string";
+                               << "be a string";
     llvm::Triple triple = llvm::Triple(tripleStr.getValue());
     clang::TargetOptions targetOptions;
     targetOptions.Triple = tripleStr.getValue();
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp 
b/clang/lib/CIR/Lowering/CIRPasses.cpp
index cbc0c515bf275..11e8a3ee341f7 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -78,8 +78,7 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext 
&mlirContext,
 
   llvm::TimeTraceScope scope("CIR To CIR Passes");
 
-  std::optional<llvm::Triple> triple = cir::getTripleFromModule(
-      theModule, [&] { return theModule.emitError(); });
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(theModule);
   if (!triple)
     return mlir::LogicalResult::failure();
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 8a49790120c5f..0c77affa835ad 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -5830,11 +5830,7 @@ mlir::LogicalResult 
CIRToLLVMCpuIdOpLowering::matchAndRewrite(
 
   StringRef asmString, constraints;
   mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>();
-  auto diag = [&] {
-    return moduleOp.emitError("cannot lower ")
-           << op.getOperationName() << " op: ";
-  };
-  std::optional<llvm::Triple> triple = cir::getTripleFromModule(moduleOp, 
diag);
+  std::optional<llvm::Triple> triple = cir::getTripleFromModule(moduleOp);
   if (!triple)
     return mlir::failure();
   if (triple->getArch() == llvm::Triple::x86) {
diff --git a/clang/test/CIR/Input/cir-input-invalid.cir 
b/clang/test/CIR/Input/cir-input-invalid.cir
index 1a791d843bb0a..7b41ca296fefc 100644
--- a/clang/test/CIR/Input/cir-input-invalid.cir
+++ b/clang/test/CIR/Input/cir-input-invalid.cir
@@ -25,11 +25,12 @@
 
 // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir 
%t/no-triple.cir -o - 2>&1 \
 // RUN:   | FileCheck %s --check-prefix=NO-TRIPLE --implicit-check-not=error:
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir 
%t/int-triple.cir -o - 2>&1 \
-// RUN:   | FileCheck %s --check-prefix=NO-TRIPLE --implicit-check-not=error:
 // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-obj 
%t/no-triple.cir -o /dev/null 2>&1 \
 // RUN:   | FileCheck %s --check-prefix=NO-TRIPLE --implicit-check-not=error:
 // NO-TRIPLE: error: missing target triple in ClangIR input
+// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir 
%t/int-triple.cir -o - 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=BAD-TRIPLE --implicit-check-not=error:
+// BAD-TRIPLE: error: 'builtin.module' op expects 'cir.triple' to be a string
 
 // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir 
%t/mismatch.cir -o - 2>&1 \
 // RUN:   | FileCheck %s --check-prefix=MISMATCH --implicit-check-not=error:

>From 66d12d03046af3dfb3909ee672afb4dcf116262a Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 13 Oct 2026 21:17:13 -0700
Subject: [PATCH 13/16] Delete changes to EHABILowering; should be another PR

---
 .../CIR/Dialect/Transforms/EHABILowering.cpp  | 11 +++--
 .../Transforms/eh-abi-lowering-bad-attrs.cir  | 41 -------------------
 2 files changed, 7 insertions(+), 45 deletions(-)
 delete mode 100644 clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir

diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index ed93a41978811..72a8cffc3b060 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -1113,16 +1113,19 @@ void CIREHABILoweringPass::runOnOperation() {
   // The target triple is attached to the module as the "cir.triple"
   // attribute. If it is absent (e.g. a CIR module parsed from text without a
   // triple) we cannot determine the ABI and must skip the pass.
-  std::optional<llvm::Triple> triple =
-      cir::getTripleFromModule(mod, [&] { return mod.emitWarning(); });
-  if (!triple)
+  auto tripleAttr = mlir::dyn_cast_if_present<mlir::StringAttr>(
+      mod->getAttr(cir::CIRDialect::getTripleAttrName()));
+  if (!tripleAttr) {
+    mod.emitError("Module has no target triple");
     return;
+  }
 
   // Select the ABI-specific lowering handler from the triple. The Microsoft
   // C++ ABI targets a Windows MSVC environment; everything else uses Itanium.
   // Extend this when Microsoft ABI lowering is added.
+  llvm::Triple triple(tripleAttr.getValue());
   std::unique_ptr<EHABILowering> lowering;
-  if (triple->isWindowsMSVCEnvironment()) {
+  if (triple.isWindowsMSVCEnvironment()) {
     mod.emitError(
         "EH ABI lowering is not yet implemented for the Microsoft ABI");
     return signalPassFailure();
diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir 
b/clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir
deleted file mode 100644
index fc4be2550cb3b..0000000000000
--- a/clang/test/CIR/Transforms/eh-abi-lowering-bad-attrs.cir
+++ /dev/null
@@ -1,41 +0,0 @@
-// RUN: cir-opt %s -cir-eh-abi-lowering -verify-diagnostics -split-input-file
-// RUN: cir-opt %s -cir-eh-abi-lowering -split-input-file 2>/dev/null | 
FileCheck %s
-
-// Check that missing or malformed cir.triple attributes required by
-// -cir-eh-abi-lowering do not cause asserts or compiler crashes, and are
-// diagnosed properly. The pass should warn and skip instead of failing, so
-// every module is still printed.
-
-
-// Missing cir.triple.
-
-// expected-warning @below {{module is missing cir.triple attribute}}
-module {
-  // CHECK-LABEL: cir.func @missing_triple(
-  cir.func @missing_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Non-string cir.triple.
-
-// expected-warning @below {{expected a string from module attribute 
cir.triple}}
-module attributes {cir.triple = 42 : i32} {
-  // CHECK-LABEL: cir.func @non_string_triple(
-  cir.func @non_string_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Valid cir.triple.
-
-module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
-  // CHECK-LABEL: cir.func @valid_triple(
-  cir.func @valid_triple() {
-    cir.return
-  }
-}

>From b273d9ffd00b492b517e330c96e5abb6b0625b84 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 13 Oct 2026 21:30:52 -0700
Subject: [PATCH 14/16] add tests for new CIR dialect verifier behavior

---
 clang/test/CIR/IR/invalid-opt-info.cir        |  21 ++++
 clang/test/CIR/IR/invalid-triple.cir          |  27 +++++
 .../Transforms/cxx-abi-lowering-bad-attrs.cir | 104 ++----------------
 3 files changed, 59 insertions(+), 93 deletions(-)
 create mode 100644 clang/test/CIR/IR/invalid-triple.cir

diff --git a/clang/test/CIR/IR/invalid-opt-info.cir 
b/clang/test/CIR/IR/invalid-opt-info.cir
index 52d6afd2c6974..20ccb83694db5 100644
--- a/clang/test/CIR/IR/invalid-opt-info.cir
+++ b/clang/test/CIR/IR/invalid-opt-info.cir
@@ -11,3 +11,24 @@ module attributes {
   // expected-error @below {{size optimization level must be between 0 and 2 
inclusive}}
   cir.opt_info = #cir.opt_info<level = 0, size = 3>
 } {}
+
+// -----
+
+// cir.opt_info that is not an OptInfoAttr.
+
+// expected-error @below {{'builtin.module' op malformed cir.opt_info 
attribute}}
+module attributes {cir.opt_info = 1 : i32} {}
+
+// -----
+
+// String cir.opt_info.
+
+// expected-error @below {{'builtin.module' op malformed cir.opt_info 
attribute}}
+module attributes {cir.opt_info = "O2"} {}
+
+// -----
+
+// Dictionary cir.opt_info that mimics OptInfoAttr's fields.
+
+// expected-error @below {{'builtin.module' op malformed cir.opt_info 
attribute}}
+module attributes {cir.opt_info = {level = 2 : i32, size = 1 : i32}} {}
diff --git a/clang/test/CIR/IR/invalid-triple.cir 
b/clang/test/CIR/IR/invalid-triple.cir
new file mode 100644
index 0000000000000..a52ae9768689e
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-triple.cir
@@ -0,0 +1,27 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+// Non-string cir.triple.
+
+// expected-error @below {{'builtin.module' op expects 'cir.triple' to be a 
string}}
+module attributes {cir.triple = 42 : i32} {}
+
+// -----
+
+// Empty cir.triple.
+
+// expected-error @below {{'builtin.module' op unknown triple '' in 
'cir.triple' attribute}}
+module attributes {cir.triple = ""} {}
+
+// -----
+
+// Malformed cir.triple.
+
+// expected-error @below {{'builtin.module' op unknown triple 'garbage' in 
'cir.triple' attribute}}
+module attributes {cir.triple = "garbage"} {}
+
+// -----
+
+// Well-formed cir.triple with an unknown target.
+
+// expected-error @below {{'builtin.module' op unknown triple 
'foobar-unknown-unknown' in 'cir.triple' attribute}}
+module attributes {cir.triple = "foobar-unknown-unknown"} {}
diff --git a/clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir 
b/clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir
index 5d13956c63af4..b6ce3bbf0e6c2 100644
--- a/clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir
+++ b/clang/test/CIR/Transforms/cxx-abi-lowering-bad-attrs.cir
@@ -1,15 +1,17 @@
 // RUN: cir-opt %s -cir-cxxabi-lowering -verify-diagnostics -split-input-file
 // RUN: cir-opt %s -cir-cxxabi-lowering -split-input-file 2>/dev/null | 
FileCheck %s
 
-// Check that missing or malformed module attributes required/used by
-// -cir-cxxabi-lowering do not cause asserts or compiler crashes, and are
-// diagnosed properly. The pass should warn and skip instead of failing, so
-// every module is still printed.
+// Check that missing cir.triple module attribute does not cause asserts or
+// compiler crashes in -cir-cxxabi-lowering, and is diagnosed properly. The 
pass
+// should warn and skip instead of failing. so every module is still printed.
+//
+// Malformed cir.triple and cir.opt_info attributes are rejected by the CIR
+// dialect verifier; see IR/invalid-triple.cir and IR/invalid-opt-info.cir.
 
 
 // Missing cir.triple.
 
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: module is missing cir.triple attribute}}
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass}}
 module {
   // CHECK-LABEL: cir.func @missing_triple(
   cir.func @missing_triple() {
@@ -19,48 +21,10 @@ module {
 
 // -----
 
-// Non-string cir.triple.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: expected a string from module attribute cir.triple}}
-module attributes {cir.triple = 42 : i32} {
-  // CHECK-LABEL: cir.func @non_string_triple(
-  cir.func @non_string_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Empty cir.triple.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: unknown triple '' in cir.triple attribute}}
-module attributes {cir.triple = ""} {
-  // CHECK-LABEL: cir.func @empty_triple(
-  cir.func @empty_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Malformed cir.triple.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: unknown triple 'garbage' in cir.triple attribute}}
-module attributes {cir.triple = "garbage"} {
-  // CHECK-LABEL: cir.func @malformed_triple(
-  cir.func @malformed_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Well-formed cir.triple with an unknown target.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: unknown triple 'foobar-unknown-unknown' in cir.triple 
attribute}}
-module attributes {cir.triple = "foobar-unknown-unknown"} {
-  // CHECK-LABEL: cir.func @unknown_triple(
-  cir.func @unknown_triple() {
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass}}
+module attributes {cir.opt_info = #cir.opt_info<level = 0, size = 1>} {
+  // CHECK-LABEL: cir.func @missing_triple(
+  cir.func @missing_triple() {
     cir.return
   }
 }
@@ -89,49 +53,3 @@ module attributes {
     cir.return
   }
 }
-
-// -----
-
-// Valid cir.triple with a cir.opt_info that is not an OptInfoAttr.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = 1 : i32
-} {
-  // CHECK-LABEL: cir.func @malformed_opt_info(
-  cir.func @malformed_opt_info() {
-    cir.return
-  }
-}
-
-// -----
-
-// Valid cir.triple with a string cir.opt_info.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = "O2"
-} {
-  // CHECK-LABEL: cir.func @string_opt_info(
-  cir.func @string_opt_info() {
-    cir.return
-  }
-}
-
-// -----
-
-// Valid cir.triple with a dictionary cir.opt_info that mimics OptInfoAttr's
-// fields.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
CXXABILowering pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = {level = 2 : i32, size = 1 : i32}
-} {
-  // CHECK-LABEL: cir.func @dict_opt_info(
-  cir.func @dict_opt_info() {
-    cir.return
-  }
-}

>From 58a6435d2db545602ec6dc9ef5fb2a3508d3403e Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 13 Oct 2026 21:33:20 -0700
Subject: [PATCH 15/16] add comment

---
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 06c88dfb78d48..a80c311d42a93 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -307,6 +307,8 @@ cir::CIRDialect::verifyOperationAttribute(mlir::Operation 
*op,
 
   if (attrName == getOptInfoAttrName()) {
     auto optInfo = mlir::dyn_cast<cir::OptInfoAttr>(attr.getValue());
+    // Checks whether or not OptInfoAttr is even parseable; opt info range
+    // sanity checks are done in OptInfoAttr::verify.
     if (!optInfo)
       return op->emitOpError() << "malformed "
                                << cir::CIRDialect::getOptInfoAttrName()

>From 6928e7efbe589945a0bb85052e4658a89cb28463 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 13 Oct 2026 21:52:44 -0700
Subject: [PATCH 16/16] delete a crap ton of test code; this feels good but
 I'll get rid of the rest later

---
 .../CIR/Lowering/cir-to-llvm-module-attrs.cir | 21 +---
 .../lowering-prepare-module-attrs.cir         | 92 +----------------
 .../target-lowering-module-attrs.cir          | 99 +------------------
 3 files changed, 12 insertions(+), 200 deletions(-)

diff --git a/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir 
b/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
index 0cf5c4a3327c3..6c208074c1b9f 100644
--- a/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
+++ b/clang/test/CIR/Lowering/cir-to-llvm-module-attrs.cir
@@ -5,13 +5,15 @@
 // -cir-to-llvm relies on cir.triple module attributes to handle cir.cpuid ops:
 // Check that missing or malformed cir.triple attributes read by -cir-to-llvm 
do
 // not cause asserts or compiler crashes, and are diagnosed properly.
+//
+// Malformed cir.triple attributes are rejected by the CIR dialect verifier; 
see
+// IR/invalid-triple.cir.
 
 
 // Missing cir.triple.
 
 !s32i = !cir.int<s, 32>
-// expected-warning @below {{module is missing cir.triple attribute}}
-// expected-error @below {{cannot lower cir.cpuid op: module is missing 
cir.triple attribute}}
+// expected-error @below {{Module has no target triple}}
 module {
   cir.func @missing_triple(%p: !cir.ptr<!s32i>, %a: !s32i, %b: !s32i) {
     // expected-error @below {{failed to legalize operation 'cir.cpuid'}}
@@ -22,21 +24,6 @@ module {
 
 // -----
 
-// Non-string cir.triple.
-
-!s32i = !cir.int<s, 32>
-// expected-warning @below {{expected a string from module attribute 
cir.triple}}
-// expected-error @below {{cannot lower cir.cpuid op: expected a string from 
module attribute cir.triple}}
-module attributes {cir.triple = 42 : i32} {
-  cir.func @non_string_triple(%p: !cir.ptr<!s32i>, %a: !s32i, %b: !s32i) {
-    // expected-error @below {{failed to legalize operation 'cir.cpuid'}}
-    cir.cpuid %p, %a, %b : !cir.ptr<!s32i>, !s32i, !s32i
-    cir.return
-  }
-}
-
-// -----
-
 // Valid cir.triple.
 
 !s32i = !cir.int<s, 32>
diff --git a/clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir 
b/clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir
index f42bad16d7bc3..8ff76ba35e370 100644
--- a/clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir
+++ b/clang/test/CIR/Transforms/lowering-prepare-module-attrs.cir
@@ -6,11 +6,14 @@
 // -cir-lowering-prepare do not cause asserts or compiler crashes, and are
 // diagnosed properly. The pass should fail on bad attributes, so only modules
 // with valid attributes are printed.
+//
+// Malformed cir.triple and cir.opt_info attributes are rejected by the CIR
+// dialect verifier; see IR/invalid-triple.cir and IR/invalid-opt-info.cir.
 
 
 // Missing cir.triple.
 
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: module is missing cir.triple attribute}}
+// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass}}
 module {
   cir.func @missing_triple() {
     cir.return
@@ -19,50 +22,6 @@ module {
 
 // -----
 
-// Non-string cir.triple.
-
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: expected a string from module attribute cir.triple}}
-module attributes {cir.triple = 42 : i32} {
-  cir.func @non_string_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Empty cir.triple.
-
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: unknown triple '' in cir.triple attribute}}
-module attributes {cir.triple = ""} {
-  cir.func @empty_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Malformed cir.triple.
-
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: unknown triple 'garbage' in cir.triple attribute}}
-module attributes {cir.triple = "garbage"} {
-  cir.func @malformed_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Well-formed cir.triple with an unknown target.
-
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: unknown triple 'foobar-unknown-unknown' in cir.triple 
attribute}}
-module attributes {cir.triple = "foobar-unknown-unknown"} {
-  cir.func @unknown_triple() {
-    cir.return
-  }
-}
-
-// -----
-
 // Valid cir.triple without cir.opt_info.
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
@@ -85,46 +44,3 @@ module attributes {
     cir.return
   }
 }
-
-// -----
-
-// Valid cir.triple with a cir.opt_info that is not an OptInfoAttr.
-
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = 1 : i32
-} {
-  cir.func @malformed_opt_info() {
-    cir.return
-  }
-}
-
-// -----
-
-// Valid cir.triple with a string cir.opt_info.
-
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = "O2"
-} {
-  cir.func @string_opt_info() {
-    cir.return
-  }
-}
-
-// -----
-
-// Valid cir.triple with a dictionary cir.opt_info that mimics OptInfoAttr's
-// fields.
-
-// expected-error @below {{cannot create a CIR lower module for 
LoweringPrepare pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = {level = 2 : i32, size = 1 : i32}
-} {
-  cir.func @dict_opt_info() {
-    cir.return
-  }
-}
diff --git a/clang/test/CIR/Transforms/target-lowering-module-attrs.cir 
b/clang/test/CIR/Transforms/target-lowering-module-attrs.cir
index 36813d4d707a4..6c507cd2d5597 100644
--- a/clang/test/CIR/Transforms/target-lowering-module-attrs.cir
+++ b/clang/test/CIR/Transforms/target-lowering-module-attrs.cir
@@ -5,11 +5,14 @@
 // -cir-target-lowering do not cause asserts or compiler crashes, and are
 // diagnosed properly. The pass should warn and skip instead of failing, so
 // every module is still printed.
+//
+// Malformed cir.triple and cir.opt_info attributes are rejected by the CIR
+// dialect verifier; see IR/invalid-triple.cir and IR/invalid-opt-info.cir.
 
 
 // Missing cir.triple.
 
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: module is missing cir.triple attribute}}
+// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass}}
 module {
   // CHECK-LABEL: cir.func @missing_triple(
   cir.func @missing_triple() {
@@ -19,54 +22,6 @@ module {
 
 // -----
 
-// Non-string cir.triple.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: expected a string from module attribute cir.triple}}
-module attributes {cir.triple = 42 : i32} {
-  // CHECK-LABEL: cir.func @non_string_triple(
-  cir.func @non_string_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Empty cir.triple.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: unknown triple '' in cir.triple attribute}}
-module attributes {cir.triple = ""} {
-  // CHECK-LABEL: cir.func @empty_triple(
-  cir.func @empty_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Malformed cir.triple.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: unknown triple 'garbage' in cir.triple attribute}}
-module attributes {cir.triple = "garbage"} {
-  // CHECK-LABEL: cir.func @malformed_triple(
-  cir.func @malformed_triple() {
-    cir.return
-  }
-}
-
-// -----
-
-// Well-formed cir.triple with an unknown target.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: unknown triple 'foobar-unknown-unknown' in cir.triple 
attribute}}
-module attributes {cir.triple = "foobar-unknown-unknown"} {
-  // CHECK-LABEL: cir.func @unknown_triple(
-  cir.func @unknown_triple() {
-    cir.return
-  }
-}
-
-// -----
-
 // Valid cir.triple without cir.opt_info.
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
@@ -89,49 +44,3 @@ module attributes {
     cir.return
   }
 }
-
-// -----
-
-// Valid cir.triple with a cir.opt_info that is not an OptInfoAttr.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = 1 : i32
-} {
-  // CHECK-LABEL: cir.func @malformed_opt_info(
-  cir.func @malformed_opt_info() {
-    cir.return
-  }
-}
-
-// -----
-
-// Valid cir.triple with a string cir.opt_info.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = "O2"
-} {
-  // CHECK-LABEL: cir.func @string_opt_info(
-  cir.func @string_opt_info() {
-    cir.return
-  }
-}
-
-// -----
-
-// Valid cir.triple with a dictionary cir.opt_info that mimics OptInfoAttr's
-// fields.
-
-// expected-warning @below {{cannot create a CIR lower module, skipping the 
TargetLowering pass: malformed cir.opt_info attribute}}
-module attributes {
-  cir.triple = "x86_64-unknown-linux-gnu",
-  cir.opt_info = {level = 2 : i32, size = 1 : i32}
-} {
-  // CHECK-LABEL: cir.func @dict_opt_info(
-  cir.func @dict_opt_info() {
-    cir.return
-  }
-}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to