[clang] [CIR] Add X86 prefetch builtins (PR #168051)
Hendrik Hübner via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 18 16:56:11 PST 2025
https://github.com/HendrikHuebner updated https://github.com/llvm/llvm-project/pull/168051
>From 02cf87cd1dd27732414b68f3715ce722b00b92cc Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Fri, 14 Nov 2025 13:29:41 +0100
Subject: [PATCH 1/8] Add prefetch builtins
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 +--
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 30 ++++++++++++++++
.../test/CIR/CodeGen/X86/prefetchw-builtin.c | 36 +++++++++++++++++++
clang/test/CIR/CodeGen/X86/sse-builtins.c | 18 ++++++++++
4 files changed, 86 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2124b1dc62a81..219846ec7a884 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4116,7 +4116,7 @@ def CIR_PrefetchOp : CIR_Op<"prefetch"> {
$locality is a temporal locality specifier ranging from (0) - no locality,
to (3) - extremely local, keep in cache. If $locality is not present, the
default value is 3.
-
+
$isWrite specifies whether the prefetch is for a 'read' or 'write'. If
$isWrite is not specified, it means that prefetch is prepared for 'read'.
}];
@@ -4150,7 +4150,7 @@ def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> {
When the `min` attribute is present, the operation returns the minimum
guaranteed accessible size. When absent (max mode), it returns the maximum
possible object size. Corresponds to `llvm.objectsize`'s `min` argument.
-
+
The `dynamic` attribute determines if the value should be evaluated at
runtime. Corresponds to `llvm.objectsize`'s `dynamic` argument.
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index ba160373ec77e..580d8b890b5c7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -20,6 +20,11 @@
using namespace clang;
using namespace clang::CIRGen;
+/// Get integer from a mlir::Value that is an int constant or a constant op.
+static int64_t getIntValueFromConstOp(mlir::Value val) {
+ return val.getDefiningOp<cir::ConstantOp>().getIntValue().getSExtValue();
+}
+
template <typename... Operands>
static mlir::Value emitIntrinsicCallOp(CIRGenFunction &cgf, const CallExpr *e,
const std::string &str,
@@ -33,6 +38,28 @@ static mlir::Value emitIntrinsicCallOp(CIRGenFunction &cgf, const CallExpr *e,
.getResult();
}
+static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
+ const CallExpr *e,
+ mlir::Value &addr, int64_t hint) {
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+ mlir::Location location = cgf.getLoc(e->getExprLoc());
+ mlir::Type voidTy = builder.getVoidTy();
+ mlir::Value address = builder.createPtrBitcast(addr, voidTy);
+ bool isWrite{};
+ int locality{};
+
+ if (builtinID == X86::BI_mm_prefetch) {
+ isWrite = (hint >> 2) & 0x1;
+ locality = hint & 0x3;
+ } else {
+ isWrite = (builtinID == X86::BI_m_prefetchw);
+ locality = 0x3;
+ }
+
+ cir::PrefetchOp::create(builder, location, address, locality, isWrite);
+ return {};
+}
+
mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
const CallExpr *e) {
if (builtinID == Builtin::BI__builtin_cpu_is) {
@@ -85,6 +112,9 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
case X86::BI_mm_sfence:
return emitIntrinsicCallOp(*this, e, "x86.sse.sfence", voidTy);
case X86::BI_mm_prefetch:
+ case X86::BI_m_prefetch:
+ case X86::BI_m_prefetchw:
+ return emitPrefetch(*this, builtinID, e, ops[0], getIntValueFromConstOp(ops[1]));
case X86::BI__rdtsc:
case X86::BI__builtin_ia32_rdtscp:
case X86::BI__builtin_ia32_lzcnt_u16:
diff --git a/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c b/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
new file mode 100644
index 0000000000000..fbf7894ba69b2
--- /dev/null
+++ b/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
@@ -0,0 +1,36 @@
+
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-cir -o %t.cir -Wall -Werror
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-llvm -o %t.ll -Wall -Werror
+// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
+
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fno-signed-char -fclangir -emit-cir -o %t.cir -Wall -Werror
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-llvm -o %t.ll -Wall -Werror
+// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
+
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG
+
+
+#include <x86intrin.h>
+
+void test_m_prefetch(void *p) {
+ // CIR-LABEL: test_m_prefetch
+ // LLVM-LABEL: test_m_prefetch
+ // OGCG-LABEL: test_m_prefetch
+ return _m_prefetch(p);
+ // CIR: cir.prefetch read locality(0) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+}
+
+void test_m_prefetch_w(void *p) {
+ // CIR-LABEL: test_m_prefetch_w
+ // LLVM-LABEL: test_m_prefetch_w
+ // OGCG-LABEL: test_m_prefetch_w
+ return _m_prefetchw(p);
+ // CIR: cir.prefetch write locality(0) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+}
diff --git a/clang/test/CIR/CodeGen/X86/sse-builtins.c b/clang/test/CIR/CodeGen/X86/sse-builtins.c
index 3a61018741958..07c586d7c0b8c 100644
--- a/clang/test/CIR/CodeGen/X86/sse-builtins.c
+++ b/clang/test/CIR/CodeGen/X86/sse-builtins.c
@@ -26,3 +26,21 @@ void test_mm_sfence(void) {
// LLVM: call void @llvm.x86.sse.sfence()
// OGCG: call void @llvm.x86.sse.sfence()
}
+
+void test_mm_prefetch(char const* p) {
+ // CIR-LABEL: test_mm_prefetch
+ // LLVM-LABEL: test_mm_prefetch
+ _mm_prefetch(p, 0);
+ // CIR: cir.prefetch read locality(0) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+}
+
+void test_mm_prefetch_local(char const* p) {
+ // CIR-LABEL: test_mm_prefetch_local
+ // LLVM-LABEL: test_mm_prefetch_local
+ _mm_prefetch(p, 3);
+ // CIR: cir.prefetch read locality(3) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
+}
>From 84f845d4c24a27cfc9a818af913c539a62462a3e Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Fri, 14 Nov 2025 15:38:58 +0100
Subject: [PATCH 2/8] Format
---
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 7 ++++---
.../test/CIR/CodeGen/X86/prefetchw-builtin.c | 20 +++++++++----------
2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 580d8b890b5c7..3d0dfef12a6c3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -40,15 +40,16 @@ static mlir::Value emitIntrinsicCallOp(CIRGenFunction &cgf, const CallExpr *e,
static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
const CallExpr *e,
- mlir::Value &addr, int64_t hint) {
+ const SmallVector<mlir::Value> &ops) {
CIRGenBuilderTy &builder = cgf.getBuilder();
mlir::Location location = cgf.getLoc(e->getExprLoc());
mlir::Type voidTy = builder.getVoidTy();
- mlir::Value address = builder.createPtrBitcast(addr, voidTy);
+ mlir::Value address = builder.createPtrBitcast(ops[0], voidTy);
bool isWrite{};
int locality{};
if (builtinID == X86::BI_mm_prefetch) {
+ int hint = getIntValueFromConstOp(ops[1]);
isWrite = (hint >> 2) & 0x1;
locality = hint & 0x3;
} else {
@@ -114,7 +115,7 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
case X86::BI_mm_prefetch:
case X86::BI_m_prefetch:
case X86::BI_m_prefetchw:
- return emitPrefetch(*this, builtinID, e, ops[0], getIntValueFromConstOp(ops[1]));
+ return emitPrefetch(*this, builtinID, e, ops);
case X86::BI__rdtsc:
case X86::BI__builtin_ia32_rdtscp:
case X86::BI__builtin_ia32_lzcnt_u16:
diff --git a/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c b/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
index fbf7894ba69b2..3b04b789b3322 100644
--- a/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
+++ b/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
@@ -15,16 +15,6 @@
#include <x86intrin.h>
-void test_m_prefetch(void *p) {
- // CIR-LABEL: test_m_prefetch
- // LLVM-LABEL: test_m_prefetch
- // OGCG-LABEL: test_m_prefetch
- return _m_prefetch(p);
- // CIR: cir.prefetch read locality(0) %{{.*}} : !cir.ptr<!void>
- // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
- // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
-}
-
void test_m_prefetch_w(void *p) {
// CIR-LABEL: test_m_prefetch_w
// LLVM-LABEL: test_m_prefetch_w
@@ -34,3 +24,13 @@ void test_m_prefetch_w(void *p) {
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
}
+
+void test_m_prefetch(void *p) {
+ // CIR-LABEL: test_m_prefetch
+ // LLVM-LABEL: test_m_prefetch
+ // OGCG-LABEL: test_m_prefetch
+ return _m_prefetch(p);
+ // CIR: cir.prefetch read locality(0) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+}
>From fd266d4bd99cfffb88c85d58958444df063ffc42 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sat, 15 Nov 2025 17:15:56 +0100
Subject: [PATCH 3/8] Feedback
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 18 +++++++++++++-----
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 6 +++++-
clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 ++--
clang/test/CIR/CodeGen/X86/prefetchw-builtin.c | 12 ++++++------
clang/test/CIR/CodeGen/X86/sse-builtins.c | 9 +++++++++
5 files changed, 35 insertions(+), 14 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 77f19343653db..201759fba0aba 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -540,12 +540,20 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
}
// Now see if we can emit a target-specific builtin.
- if (mlir::Value v = emitTargetBuiltinExpr(builtinID, e, returnValue)) {
+ std::optional<mlir::Value> valueOpt =
+ emitTargetBuiltinExpr(builtinID, e, returnValue);
+ if (valueOpt) {
+ // A builtin was emitted but had no return value.
+ if (*valueOpt == nullptr) {
+ return RValue::get(nullptr);
+ }
+
switch (evalKind) {
case cir::TEK_Scalar:
- if (mlir::isa<cir::VoidType>(v.getType()))
+ if (mlir::isa<cir::VoidType>(valueOpt->getType())) {
return RValue::get(nullptr);
- return RValue::get(v);
+ }
+ return RValue::get(*valueOpt);
case cir::TEK_Aggregate:
cgm.errorNYI(e->getSourceRange(), "aggregate return value from builtin");
return getUndefRValue(e->getType());
@@ -561,7 +569,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
return getUndefRValue(e->getType());
}
-static mlir::Value emitTargetArchBuiltinExpr(CIRGenFunction *cgf,
+static std::optional<mlir::Value> emitTargetArchBuiltinExpr(CIRGenFunction *cgf,
unsigned builtinID,
const CallExpr *e,
ReturnValueSlot &returnValue,
@@ -616,7 +624,7 @@ static mlir::Value emitTargetArchBuiltinExpr(CIRGenFunction *cgf,
}
}
-mlir::Value
+std::optional<mlir::Value>
CIRGenFunction::emitTargetBuiltinExpr(unsigned builtinID, const CallExpr *e,
ReturnValueSlot &returnValue) {
if (getContext().BuiltinInfo.isAuxBuiltinID(builtinID)) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 3d0dfef12a6c3..503ff1b93bc29 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -48,6 +48,10 @@ static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
bool isWrite{};
int locality{};
+ assert(builtinID == X86::BI_mm_prefetch ||
+ builtinID == X86::BI_m_prefetchw ||
+ builtinID == X86::BI_m_prefetch && "Expected prefetch builtin");
+
if (builtinID == X86::BI_mm_prefetch) {
int hint = getIntValueFromConstOp(ops[1]);
isWrite = (hint >> 2) & 0x1;
@@ -61,7 +65,7 @@ static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
return {};
}
-mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
+std::optional<mlir::Value> CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
const CallExpr *e) {
if (builtinID == Builtin::BI__builtin_cpu_is) {
cgm.errorNYI(e->getSourceRange(), "__builtin_cpu_is");
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 00f289bcd1bb2..52d278f5264cf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1746,7 +1746,7 @@ class CIRGenFunction : public CIRGenTypeCache {
bool buildingTopLevelCase);
mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s);
- mlir::Value emitTargetBuiltinExpr(unsigned builtinID,
+ std::optional<mlir::Value> emitTargetBuiltinExpr(unsigned builtinID,
const clang::CallExpr *e,
ReturnValueSlot &returnValue);
@@ -1788,7 +1788,7 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s);
- mlir::Value emitX86BuiltinExpr(unsigned builtinID, const CallExpr *e);
+ std::optional<mlir::Value> emitX86BuiltinExpr(unsigned builtinID, const CallExpr *e);
/// Given an assignment `*lhs = rhs`, emit a test that checks if \p rhs is
/// nonnull, if 1\p LHS is marked _Nonnull.
diff --git a/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c b/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
index 3b04b789b3322..7d7ce348b8d88 100644
--- a/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
+++ b/clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
@@ -20,9 +20,9 @@ void test_m_prefetch_w(void *p) {
// LLVM-LABEL: test_m_prefetch_w
// OGCG-LABEL: test_m_prefetch_w
return _m_prefetchw(p);
- // CIR: cir.prefetch write locality(0) %{{.*}} : !cir.ptr<!void>
- // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
- // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+ // CIR: cir.prefetch write locality(3) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
}
void test_m_prefetch(void *p) {
@@ -30,7 +30,7 @@ void test_m_prefetch(void *p) {
// LLVM-LABEL: test_m_prefetch
// OGCG-LABEL: test_m_prefetch
return _m_prefetch(p);
- // CIR: cir.prefetch read locality(0) %{{.*}} : !cir.ptr<!void>
- // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
- // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
+ // CIR: cir.prefetch read locality(3) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
}
diff --git a/clang/test/CIR/CodeGen/X86/sse-builtins.c b/clang/test/CIR/CodeGen/X86/sse-builtins.c
index 07c586d7c0b8c..c7e4db46fbfca 100644
--- a/clang/test/CIR/CodeGen/X86/sse-builtins.c
+++ b/clang/test/CIR/CodeGen/X86/sse-builtins.c
@@ -44,3 +44,12 @@ void test_mm_prefetch_local(char const* p) {
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
}
+
+void test_mm_prefetch_write(char const* p) {
+ // CIR-LABEL: test_mm_prefetch_write
+ // LLVM-LABEL: test_mm_prefetch_write
+ _mm_prefetch(p, 7);
+ // CIR: cir.prefetch write locality(3) %{{.*}} : !cir.ptr<!void>
+ // LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
+ // OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
+}
>From 30e68019c087569ee4f6c42a084b308db5acf728 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sat, 15 Nov 2025 17:16:07 +0100
Subject: [PATCH 4/8] Formatting
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 9 ++++-----
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 7 +++----
clang/lib/CIR/CodeGen/CIRGenFunction.h | 9 +++++----
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 201759fba0aba..302b8fc65515a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -569,11 +569,10 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
return getUndefRValue(e->getType());
}
-static std::optional<mlir::Value> emitTargetArchBuiltinExpr(CIRGenFunction *cgf,
- unsigned builtinID,
- const CallExpr *e,
- ReturnValueSlot &returnValue,
- llvm::Triple::ArchType arch) {
+static std::optional<mlir::Value>
+emitTargetArchBuiltinExpr(CIRGenFunction *cgf, unsigned builtinID,
+ const CallExpr *e, ReturnValueSlot &returnValue,
+ llvm::Triple::ArchType arch) {
// When compiling in HipStdPar mode we have to be conservative in rejecting
// target specific features in the FE, and defer the possible error to the
// AcceleratorCodeSelection pass, wherein iff an unsupported target builtin is
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 503ff1b93bc29..d28aa3567c999 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -48,8 +48,7 @@ static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
bool isWrite{};
int locality{};
- assert(builtinID == X86::BI_mm_prefetch ||
- builtinID == X86::BI_m_prefetchw ||
+ assert(builtinID == X86::BI_mm_prefetch || builtinID == X86::BI_m_prefetchw ||
builtinID == X86::BI_m_prefetch && "Expected prefetch builtin");
if (builtinID == X86::BI_mm_prefetch) {
@@ -65,8 +64,8 @@ static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
return {};
}
-std::optional<mlir::Value> CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
- const CallExpr *e) {
+std::optional<mlir::Value>
+CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *e) {
if (builtinID == Builtin::BI__builtin_cpu_is) {
cgm.errorNYI(e->getSourceRange(), "__builtin_cpu_is");
return {};
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 52d278f5264cf..b1403bd3780ab 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1746,9 +1746,9 @@ class CIRGenFunction : public CIRGenTypeCache {
bool buildingTopLevelCase);
mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s);
- std::optional<mlir::Value> emitTargetBuiltinExpr(unsigned builtinID,
- const clang::CallExpr *e,
- ReturnValueSlot &returnValue);
+ std::optional<mlir::Value>
+ emitTargetBuiltinExpr(unsigned builtinID, const clang::CallExpr *e,
+ ReturnValueSlot &returnValue);
/// Given a value and its clang type, returns the value casted to its memory
/// representation.
@@ -1788,7 +1788,8 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s);
- std::optional<mlir::Value> emitX86BuiltinExpr(unsigned builtinID, const CallExpr *e);
+ std::optional<mlir::Value> emitX86BuiltinExpr(unsigned builtinID,
+ const CallExpr *e);
/// Given an assignment `*lhs = rhs`, emit a test that checks if \p rhs is
/// nonnull, if 1\p LHS is marked _Nonnull.
>From e8d557fd45efd0d6782ded597f55b5039ae09ddf Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Mon, 17 Nov 2025 23:39:33 +0100
Subject: [PATCH 5/8] revert formatting changes
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 219846ec7a884..2b53fff4c9e19 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4150,7 +4150,7 @@ def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> {
When the `min` attribute is present, the operation returns the minimum
guaranteed accessible size. When absent (max mode), it returns the maximum
possible object size. Corresponds to `llvm.objectsize`'s `min` argument.
-
+
The `dynamic` attribute determines if the value should be evaluated at
runtime. Corresponds to `llvm.objectsize`'s `dynamic` argument.
>From fd000c83d08a6f1df3fad60dfad0d9c2f09deb0e Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Mon, 17 Nov 2025 23:45:38 +0100
Subject: [PATCH 6/8] revert formatting changes
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2b53fff4c9e19..2124b1dc62a81 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4116,7 +4116,7 @@ def CIR_PrefetchOp : CIR_Op<"prefetch"> {
$locality is a temporal locality specifier ranging from (0) - no locality,
to (3) - extremely local, keep in cache. If $locality is not present, the
default value is 3.
-
+
$isWrite specifies whether the prefetch is for a 'read' or 'write'. If
$isWrite is not specified, it means that prefetch is prepared for 'read'.
}];
>From 34a531d441eceb7992ae0c3f01c365d02a2cef5b Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Mon, 17 Nov 2025 23:46:59 +0100
Subject: [PATCH 7/8] add OGCG label
---
clang/test/CIR/CodeGen/X86/sse-builtins.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/test/CIR/CodeGen/X86/sse-builtins.c b/clang/test/CIR/CodeGen/X86/sse-builtins.c
index c7e4db46fbfca..e8203265f89f3 100644
--- a/clang/test/CIR/CodeGen/X86/sse-builtins.c
+++ b/clang/test/CIR/CodeGen/X86/sse-builtins.c
@@ -30,6 +30,7 @@ void test_mm_sfence(void) {
void test_mm_prefetch(char const* p) {
// CIR-LABEL: test_mm_prefetch
// LLVM-LABEL: test_mm_prefetch
+ // OGCG-LABEL: test_mm_prefetch
_mm_prefetch(p, 0);
// CIR: cir.prefetch read locality(0) %{{.*}} : !cir.ptr<!void>
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
@@ -39,6 +40,7 @@ void test_mm_prefetch(char const* p) {
void test_mm_prefetch_local(char const* p) {
// CIR-LABEL: test_mm_prefetch_local
// LLVM-LABEL: test_mm_prefetch_local
+ // OGCG-LABEL: test_mm_prefetch_local
_mm_prefetch(p, 3);
// CIR: cir.prefetch read locality(3) %{{.*}} : !cir.ptr<!void>
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
@@ -48,6 +50,7 @@ void test_mm_prefetch_local(char const* p) {
void test_mm_prefetch_write(char const* p) {
// CIR-LABEL: test_mm_prefetch_write
// LLVM-LABEL: test_mm_prefetch_write
+ // OGCG-LABEL: test_mm_prefetch_write
_mm_prefetch(p, 7);
// CIR: cir.prefetch write locality(3) %{{.*}} : !cir.ptr<!void>
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
>From 58af6247576f2c5c8d4bad046f4de69b90f11792 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Wed, 19 Nov 2025 01:55:56 +0100
Subject: [PATCH 8/8] feedback
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 63 +++++++++++++------------
clang/lib/CIR/CodeGen/CIRGenFunction.h | 5 +-
2 files changed, 35 insertions(+), 33 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 302b8fc65515a..c4408405002a0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -540,33 +540,26 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
}
// Now see if we can emit a target-specific builtin.
- std::optional<mlir::Value> valueOpt =
- emitTargetBuiltinExpr(builtinID, e, returnValue);
- if (valueOpt) {
- // A builtin was emitted but had no return value.
- if (*valueOpt == nullptr) {
- return RValue::get(nullptr);
- }
+ RValue value = emitTargetBuiltinExpr(builtinID, e, returnValue);
- switch (evalKind) {
- case cir::TEK_Scalar:
- if (mlir::isa<cir::VoidType>(valueOpt->getType())) {
- return RValue::get(nullptr);
- }
- return RValue::get(*valueOpt);
- case cir::TEK_Aggregate:
- cgm.errorNYI(e->getSourceRange(), "aggregate return value from builtin");
- return getUndefRValue(e->getType());
- case cir::TEK_Complex:
- llvm_unreachable("No current target builtin returns complex");
- }
- llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr");
+
+ if (value.isScalar()) {
+ if (!value.getValue() || mlir::isa<cir::VoidType>(value.getValue().getType()))
+ return RValue::getIgnored();
+
+ return value;
}
- cgm.errorNYI(e->getSourceRange(),
- std::string("unimplemented builtin call: ") +
- getContext().BuiltinInfo.getName(builtinID));
- return getUndefRValue(e->getType());
+ if (value.isAggregate()) {
+ cgm.errorNYI(e->getSourceRange(), "aggregate return value from builtin");
+ return getUndefRValue(e->getType());
+ }
+
+ if (value.isComplex()) {
+ llvm_unreachable("No current target builtin returns complex");
+ }
+
+ llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr");
}
static std::optional<mlir::Value>
@@ -623,18 +616,28 @@ emitTargetArchBuiltinExpr(CIRGenFunction *cgf, unsigned builtinID,
}
}
-std::optional<mlir::Value>
-CIRGenFunction::emitTargetBuiltinExpr(unsigned builtinID, const CallExpr *e,
- ReturnValueSlot &returnValue) {
+RValue CIRGenFunction::emitTargetBuiltinExpr(unsigned builtinID,
+ const CallExpr *e,
+ ReturnValueSlot &returnValue) {
+ std::optional<mlir::Value> valueOpt;
if (getContext().BuiltinInfo.isAuxBuiltinID(builtinID)) {
assert(getContext().getAuxTargetInfo() && "Missing aux target info");
- return emitTargetArchBuiltinExpr(
+ valueOpt = emitTargetArchBuiltinExpr(
this, getContext().BuiltinInfo.getAuxBuiltinID(builtinID), e,
returnValue, getContext().getAuxTargetInfo()->getTriple().getArch());
+ } else {
+ valueOpt = emitTargetArchBuiltinExpr(this, builtinID, e, returnValue,
+ getTarget().getTriple().getArch());
+ }
+
+ if (!valueOpt) {
+ cgm.errorNYI(e->getSourceRange(),
+ std::string("unimplemented builtin call: ") +
+ getContext().BuiltinInfo.getName(builtinID));
+ return getUndefRValue(e->getType());
}
- return emitTargetArchBuiltinExpr(this, builtinID, e, returnValue,
- getTarget().getTriple().getArch());
+ return RValue::get(*valueOpt);
}
mlir::Value CIRGenFunction::emitScalarOrConstFoldImmArg(
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index b1403bd3780ab..97be21317d3a6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1746,9 +1746,8 @@ class CIRGenFunction : public CIRGenTypeCache {
bool buildingTopLevelCase);
mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s);
- std::optional<mlir::Value>
- emitTargetBuiltinExpr(unsigned builtinID, const clang::CallExpr *e,
- ReturnValueSlot &returnValue);
+ RValue emitTargetBuiltinExpr(unsigned builtinID, const clang::CallExpr *e,
+ ReturnValueSlot &returnValue);
/// Given a value and its clang type, returns the value casted to its memory
/// representation.
More information about the cfe-commits
mailing list