Skip to content

Conversation

kimsh02
Copy link
Contributor

@kimsh02 kimsh02 commented Oct 21, 2025

Fix #163886

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Oct 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2025

@llvm/pr-subscribers-clangir

Author: Shawn K (kimsh02)

Changes

Fix #163886


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

4 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+33)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+21)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+9)
  • (added) clang/test/CIR/CodeGen/builtin_prefetech.c (+20)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index e0163a4fecd5f..43abdc8f7bc0b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4049,6 +4049,39 @@ def CIR_ExpectOp : CIR_Op<"expect", [
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// PrefetchOp
+//===----------------------------------------------------------------------===//
+
+def CIR_PrefetchOp : CIR_Op<"prefetch"> {
+  let summary = "prefetch operation";
+  let description = [{
+    The `cir.prefetch` op prefetches data from the memmory address.
+
+    ```mlir
+    cir.prefetch(%0 : !cir.ptr<!void>) locality(1) write
+    ```
+
+    This opcode has the three attributes:
+    1. The $locality is a temporal locality specifier
+    ranging from (0) - no locality, to (3) - extremely local keep in cache.
+    2. The $isWrite is the specifier determining if the prefetch is prepaired
+    for a 'read' or 'write'.
+    If $isWrite doesn't specified it means that prefetch is prepared for 'read'.
+  }];
+
+  let arguments = (ins CIR_VoidPtrType:$addr,
+      ConfinedAttr<I32Attr, [IntMinValue<0>, IntMaxValue<3>]>:$locality,
+      UnitAttr:$isWrite);
+
+  let assemblyFormat = [{
+    `(` $addr `:` qualified(type($addr)) `)`
+        `locality``(` $locality `)`
+        (`write` $isWrite^) : (`read`)?
+        attr-dict
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // PtrDiffOp
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index ea31871806bd7..2571a402f9676 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -454,6 +454,27 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
     assert(!cir::MissingFeatures::coroSizeBuiltinCall());
     return getUndefRValue(e->getType());
   }
+  case Builtin::BI__builtin_prefetch: {
+    auto evaluateOperandAsInt = [&](const Expr *arg) {
+      Expr::EvalResult res;
+      [[maybe_unused]] bool evalSucceed =
+          arg->EvaluateAsInt(res, cgm.getASTContext());
+      assert(evalSucceed && "expression should be able to evaluate as int");
+      return res.Val.getInt().getZExtValue();
+    };
+
+    bool isWrite = false;
+    if (e->getNumArgs() > 1)
+      isWrite = evaluateOperandAsInt(e->getArg(1));
+
+    int locality = 0;
+    if (e->getNumArgs() > 2)
+      locality = evaluateOperandAsInt(e->getArg(2));
+
+    mlir::Value address = emitScalarExpr(e->getArg(0));
+    cir::PrefetchOp::create(builder, loc, address, locality, isWrite);
+    return RValue::get(nullptr);
+  }
   }
 
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0243bf120f396..47f9d79b30655 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1507,6 +1507,15 @@ static uint64_t getTypeSize(mlir::Type type, mlir::Operation &op) {
   return llvm::divideCeil(layout.getTypeSizeInBits(type), 8);
 }
 
+mlir::LogicalResult CIRToLLVMPrefetchOpLowering::matchAndRewrite(
+    cir::PrefetchOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  rewriter.replaceOpWithNewOp<mlir::LLVM::Prefetch>(
+      op, adaptor.getAddr(), adaptor.getIsWrite(), adaptor.getLocality(),
+      /*DataCache*/ 1);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite(
     cir::PtrDiffOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/builtin_prefetech.c b/clang/test/CIR/CodeGen/builtin_prefetech.c
new file mode 100644
index 0000000000000..343d9a808ad68
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin_prefetech.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s -check-prefix=LLVM
+
+void foo(void *a) {
+  __builtin_prefetch(a, 1, 1);
+}
+
+// CIR:  cir.func dso_local @foo(%arg0: !cir.ptr<!void> loc({{.*}}))
+// CIR:    [[PTR_ALLOC:%.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["a", init] {alignment = 8 : i64}
+// CIR:    cir.store %arg0, [[PTR_ALLOC]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+// CIR:    [[PTR:%.*]] = cir.load{{.*}} [[PTR_ALLOC]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR:    cir.prefetch([[PTR]] : !cir.ptr<!void>) locality(1) write
+// CIR:    cir.return
+
+// LLVM:  define dso_local void @foo(ptr [[ARG0:%.*]])
+// LLVM:    [[PTR_ALLOC:%.*]] = alloca ptr, i64 1
+// LLVM:    store ptr [[ARG0]], ptr [[PTR_ALLOC]]
+// LLVM:    [[PTR:%.*]] = load ptr, ptr [[PTR_ALLOC]]
+// LLVM:    call void @llvm.prefetch.p0(ptr [[PTR]], i32 1, i32 1, i32 1)
+// LLVM:    ret void

@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2025

@llvm/pr-subscribers-clang

Author: Shawn K (kimsh02)

Changes

Fix #163886


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

4 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+33)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+21)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+9)
  • (added) clang/test/CIR/CodeGen/builtin_prefetech.c (+20)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index e0163a4fecd5f..43abdc8f7bc0b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4049,6 +4049,39 @@ def CIR_ExpectOp : CIR_Op<"expect", [
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// PrefetchOp
+//===----------------------------------------------------------------------===//
+
+def CIR_PrefetchOp : CIR_Op<"prefetch"> {
+  let summary = "prefetch operation";
+  let description = [{
+    The `cir.prefetch` op prefetches data from the memmory address.
+
+    ```mlir
+    cir.prefetch(%0 : !cir.ptr<!void>) locality(1) write
+    ```
+
+    This opcode has the three attributes:
+    1. The $locality is a temporal locality specifier
+    ranging from (0) - no locality, to (3) - extremely local keep in cache.
+    2. The $isWrite is the specifier determining if the prefetch is prepaired
+    for a 'read' or 'write'.
+    If $isWrite doesn't specified it means that prefetch is prepared for 'read'.
+  }];
+
+  let arguments = (ins CIR_VoidPtrType:$addr,
+      ConfinedAttr<I32Attr, [IntMinValue<0>, IntMaxValue<3>]>:$locality,
+      UnitAttr:$isWrite);
+
+  let assemblyFormat = [{
+    `(` $addr `:` qualified(type($addr)) `)`
+        `locality``(` $locality `)`
+        (`write` $isWrite^) : (`read`)?
+        attr-dict
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // PtrDiffOp
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index ea31871806bd7..2571a402f9676 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -454,6 +454,27 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
     assert(!cir::MissingFeatures::coroSizeBuiltinCall());
     return getUndefRValue(e->getType());
   }
+  case Builtin::BI__builtin_prefetch: {
+    auto evaluateOperandAsInt = [&](const Expr *arg) {
+      Expr::EvalResult res;
+      [[maybe_unused]] bool evalSucceed =
+          arg->EvaluateAsInt(res, cgm.getASTContext());
+      assert(evalSucceed && "expression should be able to evaluate as int");
+      return res.Val.getInt().getZExtValue();
+    };
+
+    bool isWrite = false;
+    if (e->getNumArgs() > 1)
+      isWrite = evaluateOperandAsInt(e->getArg(1));
+
+    int locality = 0;
+    if (e->getNumArgs() > 2)
+      locality = evaluateOperandAsInt(e->getArg(2));
+
+    mlir::Value address = emitScalarExpr(e->getArg(0));
+    cir::PrefetchOp::create(builder, loc, address, locality, isWrite);
+    return RValue::get(nullptr);
+  }
   }
 
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0243bf120f396..47f9d79b30655 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1507,6 +1507,15 @@ static uint64_t getTypeSize(mlir::Type type, mlir::Operation &op) {
   return llvm::divideCeil(layout.getTypeSizeInBits(type), 8);
 }
 
+mlir::LogicalResult CIRToLLVMPrefetchOpLowering::matchAndRewrite(
+    cir::PrefetchOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  rewriter.replaceOpWithNewOp<mlir::LLVM::Prefetch>(
+      op, adaptor.getAddr(), adaptor.getIsWrite(), adaptor.getLocality(),
+      /*DataCache*/ 1);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite(
     cir::PtrDiffOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/builtin_prefetech.c b/clang/test/CIR/CodeGen/builtin_prefetech.c
new file mode 100644
index 0000000000000..343d9a808ad68
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin_prefetech.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s -check-prefix=LLVM
+
+void foo(void *a) {
+  __builtin_prefetch(a, 1, 1);
+}
+
+// CIR:  cir.func dso_local @foo(%arg0: !cir.ptr<!void> loc({{.*}}))
+// CIR:    [[PTR_ALLOC:%.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["a", init] {alignment = 8 : i64}
+// CIR:    cir.store %arg0, [[PTR_ALLOC]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+// CIR:    [[PTR:%.*]] = cir.load{{.*}} [[PTR_ALLOC]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR:    cir.prefetch([[PTR]] : !cir.ptr<!void>) locality(1) write
+// CIR:    cir.return
+
+// LLVM:  define dso_local void @foo(ptr [[ARG0:%.*]])
+// LLVM:    [[PTR_ALLOC:%.*]] = alloca ptr, i64 1
+// LLVM:    store ptr [[ARG0]], ptr [[PTR_ALLOC]]
+// LLVM:    [[PTR:%.*]] = load ptr, ptr [[PTR_ALLOC]]
+// LLVM:    call void @llvm.prefetch.p0(ptr [[PTR]], i32 1, i32 1, i32 1)
+// LLVM:    ret void

Copy link
Member

@Lancern Lancern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for authoring this, some comments inline.

@kimsh02
Copy link
Contributor Author

kimsh02 commented Oct 22, 2025

I'm still new to upstreaming, so thanks for your patience and all the feedback

@kimsh02 kimsh02 force-pushed the cir-builtin-prefetch branch from 760e039 to 645ffaa Compare October 22, 2025 01:45
@kimsh02 kimsh02 requested a review from andykaylor October 22, 2025 01:46
@kimsh02
Copy link
Contributor Author

kimsh02 commented Oct 22, 2025

Getting this failed test case, not sure if I broke something.

Command Output (stdout):
--
# RUN: at line 1
/Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/bin/clang -cc1 -internal-isystem /Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/lib/clang/22/include -nostdsysteminc -triple aarch64-unknown-linux-gnu -fclangir -emit-cir -fdump-record-layouts /Users/kimsh/Downloads/forked/llvm-project/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c -o /Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/tools/clang/test/CIR/CodeGen/Output/aapcs-volatile-bitfields.c.tmp.cir 1> /Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/tools/clang/test/CIR/CodeGen/Output/aapcs-volatile-bitfields.c.tmp.cirlayout
# executed command: /Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/bin/clang -cc1 -internal-isystem /Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/lib/clang/22/include -nostdsysteminc -triple aarch64-unknown-linux-gnu -fclangir -emit-cir -fdump-record-layouts /Users/kimsh/Downloads/forked/llvm-project/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c -o /Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/tools/clang/test/CIR/CodeGen/Output/aapcs-volatile-bitfields.c.tmp.cir
# .---command stderr------------
# | Unsupported redirect: (('>', 1), '/Users/kimsh/Downloads/forked/llvm-project/build-clang-cir/tools/clang/test/CIR/CodeGen/Output/aapcs-volatile-bitfields.c.tmp.cirlayout')
# `-----------------------------
# error: command failed with exit status: 127

--

********************
********************
Failed Tests (1):
  Clang :: CIR/CodeGen/aapcs-volatile-bitfields.c

@andykaylor
Copy link
Contributor

I'm still new to upstreaming, so thanks for your patience and all the feedback

That's totally expected. I appreciate your willingness to help.

BTW, the CI failure was unrelated to your change and is fixed now.

@kimsh02
Copy link
Contributor Author

kimsh02 commented Oct 22, 2025

@andykaylor I merged again and looking at the build artifact for the build/test on Linux, and I think the failure is unrelated to my PR again?

@andykaylor
Copy link
Contributor

@andykaylor I merged again and looking at the build artifact for the build/test on Linux, and I think the failure is unrelated to my PR again?

Yes. This one is because of an MLIR function that has been deprecated. That's fixed by this commit: #164656

I guess the CI runs using the commit that your PR is based on rather than trying to merge your PR onto the top of trunk. I'm rebasing a couple of other commits for this same reason. Normally I wouldn't worry about unrelated failures, but this one stops the build so none of the usual CI testing was done in this case.

@andykaylor
Copy link
Contributor

@andykaylor I merged again and looking at the build artifact for the build/test on Linux, and I think the failure is unrelated to my PR again?

Yes. This one is because of an MLIR function that has been deprecated. That's fixed by this commit: #164656

I guess the CI runs using the commit that your PR is based on rather than trying to merge your PR onto the top of trunk. I'm rebasing a couple of other commits for this same reason. Normally I wouldn't worry about unrelated failures, but this one stops the build so none of the usual CI testing was done in this case.

Actually, it looks like we missed some. I'll put up another PR to fix it.

@andykaylor
Copy link
Contributor

#164719 should fix the CI issues. And I think I was wrong about CI not merging with top of trunk. The problem was just that we still had deprecated calls in top of trunk.

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@kimsh02 kimsh02 requested a review from andykaylor October 23, 2025 02:30
Copy link
Member

@Lancern Lancern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Lancern Lancern merged commit 3107c2f into llvm:main Oct 23, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CIR] Upstream handling for __builtin_prefetch

4 participants