https://github.com/adams381 updated 
https://github.com/llvm/llvm-project/pull/175234

>From 2866f4c2ba59fcc470e9e7273ade35eb5ab03212 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Fri, 9 Jan 2026 11:54:53 -0800
Subject: [PATCH] [CIR] Add MemChrOp for __builtin_char_memchr and
 __builtin_memchr

Add support for the memchr builtin functions:
- Define CIR_MemChrOp (cir.libc.memchr) in CIROps.td
- Add builtin handling in CIRGenBuiltin.cpp
- Add LLVM lowering in LowerToLLVM.cpp
- Add CodeGen and IR tests
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 31 +++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       | 12 ++++++-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 20 ++++++++++++
 clang/test/CIR/CodeGen/builtin-memchr.c       | 23 ++++++++++++++
 clang/test/CIR/IR/libc-memchr.cir             | 12 +++++++
 5 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CIR/CodeGen/builtin-memchr.c
 create mode 100644 clang/test/CIR/IR/libc-memchr.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index e2b582c5c55df..4c9c656eb254b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5906,4 +5906,35 @@ def CIR_BlockAddressOp : CIR_Op<"block_address", [Pure]> 
{
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// MemChrOp
+//===----------------------------------------------------------------------===//
+
+def CIR_MemChrOp : CIR_Op<"libc.memchr"> {
+  let summary = "libc's `memchr`";
+  let description = [{
+    Search for `pattern` in data range from `src` to `src` + `len`.
+    `len` provides a bound to the search in `src`. `result` is a pointer to
+    found `pattern` or a null pointer.
+
+    Examples:
+
+    ```mlir
+    %p = cir.libc.memchr(%src, %pattern, %len)
+    ```
+  }];
+
+  let arguments = (ins
+    Arg<CIR_VoidPtrType, "", [MemRead]>:$src,
+    CIR_SInt32:$pattern,
+    CIR_UInt64:$len
+  );
+
+  let results = (outs CIR_VoidPtrType:$result);
+
+  let assemblyFormat = [{
+    `(` $src `,` $pattern `,` $len `)` attr-dict
+  }];
+}
+
 #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 85406e9f6488a..a9929723d831e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1165,12 +1165,22 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   case Builtin::BIbcopy:
   case Builtin::BI__builtin_bcopy:
     return errorBuiltinNYI(*this, e, builtinID);
+  case Builtin::BI__builtin_char_memchr:
+  case Builtin::BI__builtin_memchr: {
+    Address srcPtr = emitPointerWithAlignment(e->getArg(0));
+    mlir::Value src =
+        builder.createBitcast(srcPtr.getPointer(), builder.getVoidPtrTy());
+    mlir::Value pattern = emitScalarExpr(e->getArg(1));
+    mlir::Value len = emitScalarExpr(e->getArg(2));
+    mlir::Value res = cir::MemChrOp::create(builder, getLoc(e->getExprLoc()),
+                                            src, pattern, len);
+    return RValue::get(res);
+  }
   case Builtin::BImemcpy:
   case Builtin::BI__builtin_memcpy:
   case Builtin::BImempcpy:
   case Builtin::BI__builtin_mempcpy:
   case Builtin::BI__builtin_memcpy_inline:
-  case Builtin::BI__builtin_char_memchr:
   case Builtin::BI__builtin___memcpy_chk:
   case Builtin::BI__builtin_objc_memmove_collectable:
   case Builtin::BI__builtin___memmove_chk:
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index d0fa8bae545be..ab254dc997cb4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4284,6 +4284,26 @@ mlir::LogicalResult 
CIRToLLVMAwaitOpLowering::matchAndRewrite(
   return mlir::failure();
 }
 
+mlir::LogicalResult CIRToLLVMMemChrOpLowering::matchAndRewrite(
+    cir::MemChrOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
+  mlir::Type srcTy = getTypeConverter()->convertType(op.getSrc().getType());
+  mlir::Type patternTy =
+      getTypeConverter()->convertType(op.getPattern().getType());
+  mlir::Type lenTy = getTypeConverter()->convertType(op.getLen().getType());
+  auto fnTy =
+      mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {srcTy, patternTy, lenTy},
+                                        /*isVarArg=*/false);
+  llvm::StringRef fnName = "memchr";
+  createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy);
+  rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
+      op, mlir::TypeRange{llvmPtrTy}, fnName,
+      mlir::ValueRange{adaptor.getSrc(), adaptor.getPattern(),
+                       adaptor.getLen()});
+  return mlir::success();
+}
+
 std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
   return std::make_unique<ConvertCIRToLLVMPass>();
 }
diff --git a/clang/test/CIR/CodeGen/builtin-memchr.c 
b/clang/test/CIR/CodeGen/builtin-memchr.c
new file mode 100644
index 0000000000000..e544422992a05
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin-memchr.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+void *test_memchr(const char arg[32]) {
+  return __builtin_char_memchr(arg, 123, 32);
+}
+
+// CIR-LABEL: @test_memchr
+// CIR: %[[PATTERN:.*]] = cir.const #cir.int<123> : !s32i
+// CIR: %[[LEN:.*]] = cir.const #cir.int<32> : !u64i
+// CIR: {{%.*}} = cir.libc.memchr({{%.*}}, %[[PATTERN]], %[[LEN]])
+
+// LLVM-LABEL: @test_memchr
+// LLVM: call ptr @memchr(ptr %{{.*}}, i32 123, i64 32)
+// LLVM: ret ptr
+
+// OGCG-LABEL: @test_memchr
+// OGCG: call ptr @memchr(ptr noundef %{{.*}}, i32 noundef 123, i64 noundef 32)
+// OGCG: ret ptr
diff --git a/clang/test/CIR/IR/libc-memchr.cir 
b/clang/test/CIR/IR/libc-memchr.cir
new file mode 100644
index 0000000000000..bbddb15b187a5
--- /dev/null
+++ b/clang/test/CIR/IR/libc-memchr.cir
@@ -0,0 +1,12 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!voidptr = !cir.ptr<!cir.void>
+!s32i = !cir.int<s, 32>
+!u64i = !cir.int<u, 64>
+module {
+  cir.func @f(%src : !voidptr, %pattern : !s32i, %len : !u64i) -> !voidptr {
+    // CHECK: cir.libc.memchr
+    %ptr = cir.libc.memchr(%src, %pattern, %len)
+    cir.return %ptr : !voidptr
+  }
+}

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

Reply via email to