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/10] 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 735146b04c64f6..b57b994bea88c9 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 23fb81e2f706d4..106298629c65e7 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 76ca7114ee5cea..e978acda6cca9f 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 03044286e8cf71..313661ba959f46 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 56fcd0a9b58cda..588bc496bdabaa 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/10] 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 313661ba959f46..afbacbd7987a68 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/10] 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 afbacbd7987a68..4190947e0cb4de 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 6426841e6237f3..d539ad50db866e 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/10] 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 d9018e93628b69..baece7ab02fc71 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 2a5cb9a908a1dc..caa3527a02f118 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 77ce7434c8ed31..e3306227aac5eb 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 4190947e0cb4de..91a6f27ea8b166 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 6e75ce03d14ffd..dc4e3128ca26d4 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 d539ad50db866e..628dc160e251da 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/10] 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 baece7ab02fc71..732d065f81cb3d 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 caa3527a02f118..0136ed1ccd0dc4 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 e3306227aac5eb..72f9c786db08e1 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 91a6f27ea8b166..b6f6031ddaf2da 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 dc4e3128ca26d4..0158c7fe373093 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 628dc160e251da..0903de9c77f202 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/10] 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 fdaf4054410033..0a0c791ae494e3 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/10] 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 732d065f81cb3d..662942fdeda04a 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 0136ed1ccd0dc4..7a208cf4f1b00a 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 b57b994bea88c9..7c7de931fdc70f 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 72f9c786db08e1..668016a432308d 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 106298629c65e7..e35eb52fabda2f 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 e978acda6cca9f..f545fbb6bbecf0 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 b6f6031ddaf2da..a5ee43c544344c 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 588bc496bdabaa..dbd28430c6df34 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 0158c7fe373093..cbc0c515bf2755 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 0903de9c77f202..dc99dd0b439b03 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/10] 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 00000000000000..ed861075a5c36a
--- /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 00000000000000..5d13956c63af4a
--- /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 00000000000000..fc4be2550cb3b0
--- /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 00000000000000..f42bad16d7bc3f
--- /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 00000000000000..36813d4d707a4a
--- /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/10] 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 bebdf3dd57f737..00000000000000
--- 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/10] 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 a74cdbff3d3bdf..8a49790120c5f1 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 ed861075a5c36a..0cf5c4a3327c3f 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'}}

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

Reply via email to