llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Sirui Mu (Lancern)

<details>
<summary>Changes</summary>

Introduce the `cir.sanitize` attribute for modules and functions, which gives a 
list of sanitizers enabled for the attached modules and functions. Added 
support for address sanitizer as the only supported sanitizer kind yet.

Specifically, this patch contains the following changes:

- It introduces a new attribute `cir.sanitize` which is essentially a list of 
non-duplicating `SanitizeKind`. This attribute could be attached either to the 
module op or to a function op to indicate the set of sanitizers enabled for the 
module or the function. For now, only address sanitizer is defined as a 
sanitizer kind; other sanitizers will be added in future patches.
- It updates CIRGen to start emitting the `cir.sanitize` attribute in 
CIRGenModule and CIRGenFunction.
- It updates LowerToLLVM pass to lower the `cir.sanitize` attribute on a 
function to corresponding LLVM function attributes, such as `sanitize_address`.

Assisted-by: Codex / gpt-5.6-sol medium

---
Full diff: https://github.com/llvm/llvm-project/pull/220625.diff


10 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+29) 
- (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.td (+1) 
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+2-1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+18-1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+9) 
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+34) 
- (modified) clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp (+1-1) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+23-7) 
- (added) clang/test/CIR/CodeGen/sanitize.c (+27) 
- (added) clang/test/CIR/IR/sanitize.cir (+4) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 126f6a37a739c..d68b1fe01106f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -2136,6 +2136,35 @@ def CIR_AnnotationArrayAttr
     : CIR_TypedArrayAttrBase<CIR_AnnotationAttr,
                              "array of cir.annotation attributes">;
 
+//===----------------------------------------------------------------------===//
+// SanitizeAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_SanitizeKind : CIR_I32EnumAttr<"SanitizeKind", "sanitize kind", [
+  I32EnumAttrCase<"Address", 0, "address">,
+]> {
+  let genSpecializedAttr = 0;
+}
+
+def CIR_SanitizeAttr : CIR_Attr<"Sanitize", "sanitize"> {
+  let summary = "A list of sanitizers enabled for the module or function";
+  let description = [{
+    The `cir.sanitize` attribute is essentially a list of `SanitizeKind` values
+    attached to the module or a function. It represents the list of sanitizers
+    that should be enabled for the attached module or function.
+
+    Each element in the `kinds` parameter is a `SanitizeKind` value. No
+    duplicates are allowed in the list.
+  }];
+
+  let parameters = (ins
+    OptionalArrayRefParameter<"cir::SanitizeKind">:$kinds
+  );
+  let assemblyFormat = "`<` `[` (`]` `>`) : ($kinds^ `]` `>`)?";
+
+  let genVerifyDecl = 1;
+}
+
 include "clang/CIR/Dialect/IR/CIROpenCLAttrs.td"
 include "clang/CIR/Dialect/IR/CIRCUDAAttrs.td"
 
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 135cbdcc7d7be..58718502ee77f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -39,6 +39,7 @@ def CIR_Dialect : Dialect {
     static llvm::StringRef getSizeTypeWidthAttrName() { return 
"cir.size_type_width"; }
     static llvm::StringRef getIntTypeWidthAttrName() { return 
"cir.int_type_width"; }
     static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
+    static llvm::StringRef getSanitizeAttrName() { return "cir.sanitize"; }
     static llvm::StringRef getCalleeAttrName() { return "callee"; }
     static llvm::StringRef getNoThrowAttrName() { return "nothrow"; }
     static llvm::StringRef getNoReturnAttrName() { return "noreturn"; }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 70d34884c70a4..8e4b4557b73fe 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4280,7 +4280,8 @@ def CIR_FuncOp : CIR_Op<"func", [
     CIR_OptionalPriorityAttr:$global_ctor_priority,
     CIR_OptionalPriorityAttr:$global_dtor_priority,
     OptionalAttr<CIR_FuncInfoAttr>:$func_info,
-    OptionalAttr<CIR_AnnotationArrayAttr>:$annotations
+    OptionalAttr<CIR_AnnotationArrayAttr>:$annotations,
+    OptionalAttr<CIR_SanitizeAttr>:$sanitize
   );
 
   let regions = (region AnyRegion:$body);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 8301627ad8123..c3d5f9b66e206 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -63,7 +63,7 @@ static bool functionMightHaveBypass(const Stmt *s) {
 CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,
                                bool suppressNewContext)
     : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder),
-      curFPFeatures(cgm.getLangOpts()) {
+      sanOpts(cgm.getLangOpts().Sanitize), curFPFeatures(cgm.getLangOpts()) {
   ehStack.setCGF(this);
   shouldEmitLifetimeMarkers = CIRGen::shouldEmitLifetimeMarkers(
       cgm.getCodeGenOpts(), getContext().getLangOpts());
@@ -522,6 +522,23 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType 
returnType,
   const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
   curFuncDecl = (d ? d->getNonClosureContext() : nullptr);
 
+  if (d) {
+    SanitizerMask noSanitizeMask;
+    for (const auto *attr : d->specific_attrs<NoSanitizeAttr>())
+      noSanitizeMask |= attr->getMask();
+    sanOpts.Mask &= ~noSanitizeMask;
+
+    assert(!cir::MissingFeatures::sanitizers());
+  }
+
+  llvm::SmallVector<cir::SanitizeKind> sanitizerKinds;
+  if (sanOpts.has(SanitizerKind::Address))
+    sanitizerKinds.push_back(cir::SanitizeKind::Address);
+  assert(!cir::MissingFeatures::sanitizers());
+  if (!sanitizerKinds.empty())
+    fn.setSanitizeAttr(
+        cir::SanitizeAttr::get(&getMLIRContext(), sanitizerKinds));
+
   // This is an artifact of the legacy handling of constrained floating-point
   // modes. The rounding mode and exception behavior tracked in
   // clang::LangOptions don't correspond directly to the representation we
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 0cb2164f4c0ef..57ea1e61196ee 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -144,6 +144,15 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
   theModule->setAttr(cir::CIRDialect::getIntTypeWidthAttrName(),
                      builder.getI32IntegerAttr(target.getIntWidth()));
 
+  llvm::SmallVector<cir::SanitizeKind> sanitizerKinds;
+  if (getLangOpts().Sanitize.has(SanitizerKind::Address))
+    sanitizerKinds.push_back(cir::SanitizeKind::Address);
+  // TODO(CIR): Register more enabled sanitizers into the sanitize attribute
+  assert(!cir::MissingFeatures::sanitizers());
+  if (!sanitizerKinds.empty())
+    theModule->setAttr(cir::CIRDialect::getSanitizeAttrName(),
+                       cir::SanitizeAttr::get(&mlirContext, sanitizerKinds));
+
   if (cgo.OptimizationLevel > 0 || cgo.OptimizeSize > 0)
     theModule->setAttr(cir::CIRDialect::getOptInfoAttrName(),
                        cir::OptInfoAttr::get(&mlirContext,
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 4b1909c6f3fad..a4ee4a3d86721 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2444,6 +2444,22 @@ 
cir::AnnotationAttr::verify(function_ref<InFlightDiagnostic()> emitError,
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// SanitizeAttr
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+cir::SanitizeAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+                          llvm::ArrayRef<cir::SanitizeKind> kinds) {
+  llvm::DenseSet<cir::SanitizeKind> uniqueKinds;
+  for (cir::SanitizeKind kind : kinds) {
+    if (uniqueKinds.contains(kind))
+      return emitError() << "duplicate sanitize kind " << kind;
+    uniqueKinds.insert(kind);
+  }
+  return success();
+}
+
 ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
   llvm::SMLoc loc = parser.getCurrentLocation();
   mlir::Builder &builder = parser.getBuilder();
@@ -2457,6 +2473,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, 
OperationState &state) {
   mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);
   mlir::StringAttr dsoLocalNameAttr = getDsoLocalAttrName(state.name);
   mlir::StringAttr funcInfoNameAttr = getFuncInfoAttrName(state.name);
+  mlir::StringAttr sanitizeNameAttr = getSanitizeAttrName(state.name);
 
   if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref())))
     state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr());
@@ -2661,6 +2678,17 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, 
OperationState &state) {
     state.addAttribute(CIRDialect::getSideEffectAttrName(), attr);
   }
 
+  if (parser.parseOptionalKeyword("sanitize").succeeded()) {
+    if (parser.parseLParen().failed())
+      return failure();
+
+    cir::SanitizeAttr sanitizeAttr;
+    if (parser.parseAttribute(sanitizeAttr).failed() ||
+        parser.parseRParen().failed())
+      return failure();
+    state.addAttribute(sanitizeNameAttr, sanitizeAttr);
+  }
+
   // Parse optional annotations attribute (an ArrayAttr of AnnotationAttr).
   mlir::StringAttr annotationsNameAttr = getAnnotationsAttrName(state.name);
   mlir::ArrayAttr annotationsAttr;
@@ -2852,6 +2880,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
     p << ")";
   }
 
+  if (cir::SanitizeAttr sanitizeAttr = getSanitizeAttr()) {
+    p << " sanitize(";
+    p.printAttribute(sanitizeAttr);
+    p << ")";
+  }
+
   if (mlir::ArrayAttr annotations = getAnnotationsAttr()) {
     p << ' ';
     p.printAttribute(annotations);
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index 67aa242c6018b..465b886b2bc87 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -55,7 +55,7 @@ bool isCXXABIAttributeLegal(const mlir::TypeConverter &tc,
   // can have a data member/method.
   if (isa<mlir::DenseArrayAttr, mlir::FloatAttr, mlir::UnitAttr,
           mlir::StringAttr, mlir::IntegerAttr, mlir::SymbolRefAttr,
-          cir::AnnotationAttr>(attr))
+          cir::AnnotationAttr, cir::SanitizeAttr>(attr))
     return true;
 
   // Tablegen'ed always-legal attributes:
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 233e6aaa15adb..2d98dbffc8c39 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2647,7 +2647,15 @@ static bool shouldDropFuncAttribute(cir::FuncOp func, 
mlir::NamedAttribute attr,
          attr.getName() == func.getSideEffectAttrName() ||
          attr.getName() == CIRDialect::getNoReturnAttrName() ||
          attr.getName() == CIRDialect::getStrictFPAttrName() ||
-         attr.getName() == func.getAnnotationsAttrName();
+         attr.getName() == func.getAnnotationsAttrName() ||
+         attr.getName() == func.getSanitizeAttrName();
+}
+
+static llvm::StringRef getLLVMSanitizeAttrName(cir::SanitizeKind kind) {
+  switch (kind) {
+  case cir::SanitizeKind::Address:
+    return "sanitize_address";
+  }
 }
 
 /// Lower `cir.func` attributes for an `LLVMFuncOp` or `LLVM::AliasOp`.
@@ -2786,13 +2794,21 @@ mlir::LogicalResult 
CIRToLLVMFuncOpLowering::matchAndRewrite(
   if (op->hasAttr(CIRDialect::getNoReturnAttrName()))
     fn.setNoreturn(true);
 
-  // The LLVM dialect's LLVMFuncOp has no dedicated field for the `strictfp`
-  // function attribute, so route it through the `passthrough` array. The MLIR
-  // LLVM IR translator forwards `passthrough` entries to LLVM IR as function
-  // attributes.
+  // The LLVM dialect's LLVMFuncOp has no dedicated fields for sanitizer or
+  // `strictfp` function attributes, so route them through the `passthrough`
+  // array. The MLIR LLVM IR translator forwards `passthrough` entries to LLVM
+  // IR as function attributes.
+  SmallVector<mlir::Attribute> passthroughAttrs;
+  if (cir::SanitizeAttr sanitizeAttr = op.getSanitizeAttr()) {
+    for (cir::SanitizeKind kind : sanitizeAttr.getKinds())
+      passthroughAttrs.push_back(
+          rewriter.getStringAttr(getLLVMSanitizeAttrName(kind)));
+  }
   if (op->hasAttr(CIRDialect::getStrictFPAttrName()))
-    fn.setPassthroughAttr(rewriter.getArrayAttr(
-        {rewriter.getStringAttr(CIRDialect::getStrictFPAttrName())}));
+    passthroughAttrs.push_back(
+        rewriter.getStringAttr(CIRDialect::getStrictFPAttrName()));
+  if (!passthroughAttrs.empty())
+    fn.setPassthroughAttr(rewriter.getArrayAttr(passthroughAttrs));
 
   if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) {
     fn.setNoInline(*inlineKind == cir::InlineKind::NoInline);
diff --git a/clang/test/CIR/CodeGen/sanitize.c 
b/clang/test/CIR/CodeGen/sanitize.c
new file mode 100644
index 0000000000000..1c7e1a51366d7
--- /dev/null
+++ b/clang/test/CIR/CodeGen/sanitize.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir \
+// RUN:   -fsanitize=address %s -o - | FileCheck %s --check-prefix=ASAN
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir \
+// RUN:   %s -o - | FileCheck %s --check-prefix=NO-ASAN
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm \
+// RUN:   -fsanitize=address %s -o - | FileCheck %s --check-prefix=LLVM-ASAN
+
+// ASAN: cir.sanitize = #cir.sanitize<[address]>
+
+// NO-ASAN: module
+// NO-ASAN-NOT: cir.sanitize
+
+void foo(void) {}
+// ASAN-LABEL: cir.func{{.*}}@foo
+// ASAN-SAME: sanitize(#cir.sanitize<[address]>)
+
+// LLVM-ASAN: define {{.*}}void @foo() #[[SANITIZE_ATTR:[0-9]+]]
+
+__attribute__((no_sanitize("address")))
+void no_sanitize_address(void) {}
+// ASAN-LABEL: cir.func{{.*}}@no_sanitize_address
+// ASAN-NOT: sanitize(#cir.sanitize
+
+// LLVM-ASAN: define {{.*}}void @no_sanitize_address()
+// LLVM-ASAN-NOT: #[[SANITIZE_ATTR]]
+
+// LLVM-ASAN: attributes #[[SANITIZE_ATTR]] = {{.*}}sanitize_address
diff --git a/clang/test/CIR/IR/sanitize.cir b/clang/test/CIR/IR/sanitize.cir
new file mode 100644
index 0000000000000..0eae2e45baf75
--- /dev/null
+++ b/clang/test/CIR/IR/sanitize.cir
@@ -0,0 +1,4 @@
+// RUN: cir-opt %s -verify-diagnostics
+
+// expected-error @below {{duplicate sanitize kind address}}
+module attributes {cir.sanitize = #cir.sanitize<[address, address]>} {}

``````````

</details>


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

Reply via email to