[clang] [CIR] Add MemChrOp for __builtin_char_memchr and __builtin_memchr (PR #175234)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 9 13:23:46 PST 2026
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 <adams at nvidia.com>
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
+ }
+}
More information about the cfe-commits
mailing list