llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Wenju He (wenju-he)
<details>
<summary>Changes</summary>
Per OpenCL spec:
The read_image{i|ui} calls support a nearest filter only. The filter_mode
specified in sampler must be set to CLK_FILTER_NEAREST; otherwise the values
returned are undefined.
Assisted-by: Claude Sonnet 4.6
---
Full diff: https://github.com/llvm/llvm-project/pull/204086.diff
5 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2)
- (modified) clang/include/clang/Sema/SemaOpenCL.h (+2)
- (modified) clang/lib/Sema/SemaExpr.cpp (+7)
- (modified) clang/lib/Sema/SemaOpenCL.cpp (+49)
- (added) clang/test/SemaOpenCL/read-image-integer-linear-filter.cl (+68)
``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f84cd8dca6d4c..57c32216a2f1e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11834,6 +11834,8 @@ def err_sampler_initializer_not_integer : Error<
"sampler_t initialization requires 32-bit integer, not %0">;
def warn_sampler_initializer_invalid_bits : Warning<
"sampler initializer has invalid %0 bits">, InGroup<SpirCompat>,
DefaultIgnore;
+def warn_sampler_argument_invalid_filter : Warning<
+ "'%0' sampler must use CLK_FILTER_NEAREST">, InGroup<SpirCompat>;
def err_sampler_argument_required : Error<
"sampler_t variable required - got %0">;
def err_wrong_sampler_addressspace: Error<
diff --git a/clang/include/clang/Sema/SemaOpenCL.h
b/clang/include/clang/Sema/SemaOpenCL.h
index 04b2b617fb12f..51c2e1703b504 100644
--- a/clang/include/clang/Sema/SemaOpenCL.h
+++ b/clang/include/clang/Sema/SemaOpenCL.h
@@ -100,6 +100,8 @@ class SemaOpenCL : public SemaBase {
bool checkBuiltinKernelWorkGroupSize(CallExpr *TheCall);
bool checkBuiltinNDRangeAndBlock(CallExpr *TheCall);
+
+ void checkBuiltinReadImage(FunctionDecl *FDecl, CallExpr *Call);
};
} // namespace clang
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index f2745425588f5..345d093aed88a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -59,6 +59,7 @@
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaObjC.h"
+#include "clang/Sema/SemaOpenCL.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaPseudoObject.h"
#include "clang/Sema/Template.h"
@@ -7283,6 +7284,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn,
NamedDecl *NDecl,
}
}
+ // Check read_image{i|ui} sampler argument before ConvertArgumentsForCall
+ // replaces sampler DeclRefExprs with their integer initializers.
+ if (getLangOpts().OpenCL && FDecl) {
+ OpenCL().checkBuiltinReadImage(FDecl, TheCall);
+ }
+
if (Proto) {
if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, RParenLoc,
IsExecConfig))
diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp
index f11a40e3964ff..d307858e1660f 100644
--- a/clang/lib/Sema/SemaOpenCL.cpp
+++ b/clang/lib/Sema/SemaOpenCL.cpp
@@ -12,7 +12,9 @@
#include "clang/Sema/SemaOpenCL.h"
#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/Expr.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
@@ -576,4 +578,51 @@ bool SemaOpenCL::checkBuiltinToAddr(unsigned BuiltinID,
CallExpr *Call) {
return false;
}
+void SemaOpenCL::checkBuiltinReadImage(FunctionDecl *FDecl, CallExpr *Call) {
+ IdentifierInfo *II = FDecl->getIdentifier();
+ if (!II)
+ return;
+ StringRef Name = II->getName();
+ if (Name != "read_imagei" && Name != "read_imageui")
+ return;
+
+ // read_image{i|ui} take (image, sampler, coord); sampler is arg[1].
+ if (Call->getNumArgs() < 2)
+ return;
+ Expr *SamplerArg = Call->getArg(1);
+ QualType ArgTy = SamplerArg->getType().getCanonicalType();
+ if (!ArgTy->isSamplerT() && !ArgTy->isIntegerType())
+ return;
+
+ Expr *IntExpr = nullptr;
+ Expr *Inner = SamplerArg->IgnoreParenCasts();
+
+ if (auto *DRE = dyn_cast<DeclRefExpr>(Inner)) {
+ if (auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (const Expr *Init = Var->getAnyInitializer()) {
+ Init = Init->IgnoreParenImpCasts();
+ if (Init->getType()->isIntegerType())
+ IntExpr = const_cast<Expr *>(Init);
+ }
+ }
+ } else if (Inner->getType()->isIntegerType()) {
+ IntExpr = Inner;
+ }
+
+ if (!IntExpr)
+ return;
+
+ Expr::EvalResult EVResult;
+ if (!IntExpr->EvaluateAsInt(EVResult, getASTContext()))
+ return;
+
+ uint64_t SamplerValue = EVResult.Val.getInt().getLimitedValue();
+ // Bit layout: |...|FilterMode[5:4]|AddressMode[3:1]|NormalizedCoords[0]|
+ // CLK_FILTER_LINEAR = 0x20 => FilterMode bits = 2
+ if (((SamplerValue & 0x30u) >> 4) == 2)
+ Diag(SamplerArg->getExprLoc(),
+ diag::warn_sampler_argument_invalid_filter)
+ << Name << SamplerArg->getSourceRange();
+}
+
} // namespace clang
diff --git a/clang/test/SemaOpenCL/read-image-integer-linear-filter.cl
b/clang/test/SemaOpenCL/read-image-integer-linear-filter.cl
new file mode 100644
index 0000000000000..2a7acff8a8298
--- /dev/null
+++ b/clang/test/SemaOpenCL/read-image-integer-linear-filter.cl
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL2.0
-finclude-default-header
+
+// OpenCL spec: read_imagei and read_imageui support nearest filter only.
+// CLK_FILTER_LINEAR in the sampler results in undefined behavior; warn.
+
+// Program scope samplers.
+__constant sampler_t glb_linear =
+ CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR |
CLK_ADDRESS_MIRRORED_REPEAT;
+__constant sampler_t glb_nearest =
+ CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST |
CLK_ADDRESS_CLAMP_TO_EDGE;
+
+kernel void test_read_imageui_global_sampler(read_only image2d_t img, global
uint *out) {
+ int2 coord = (int2)(0, 0);
+ *out = read_imageui(img, glb_linear, coord).s0; //
expected-warning{{'read_imageui' sampler must use CLK_FILTER_NEAREST}}
+ *out = read_imageui(img, glb_nearest, coord).s0; // no warning
+}
+
+kernel void test_read_imagei_global_sampler(read_only image2d_t img, global
int *out) {
+ int2 coord = (int2)(0, 0);
+ *out = read_imagei(img, glb_linear, coord).s0; //
expected-warning{{'read_imagei' sampler must use CLK_FILTER_NEAREST}}
+}
+
+kernel void test_read_imageui_local_constant(read_only image2d_t img, global
uint *out) {
+ __constant sampler_t s_linear =
+ CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR | CLK_ADDRESS_CLAMP;
+ int2 coord = (int2)(0, 0);
+ *out = read_imageui(img, s_linear, coord).s0; //
expected-warning{{'read_imageui' sampler must use CLK_FILTER_NEAREST}}
+}
+
+kernel void test_read_imageui_nearest_constant(read_only image2d_t img, global
uint *out) {
+ __constant sampler_t s_nearest =
+ CLK_NORMALIZED_COORDS_FALSE | CLK_FILTER_NEAREST | CLK_ADDRESS_NONE;
+ int2 coord = (int2)(0, 0);
+ *out = read_imageui(img, s_nearest, coord).s0; // no warning
+}
+
+kernel void test_read_imageui_local(read_only image2d_t img, global uint *out)
{
+ sampler_t s_linear =
+ CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR | CLK_ADDRESS_CLAMP;
+ int2 coord = (int2)(0, 0);
+ *out = read_imageui(img, s_linear, coord).s0; //
expected-warning{{'read_imageui' sampler must use CLK_FILTER_NEAREST}}
+}
+
+kernel void test_read_imageui_nearest(read_only image2d_t img, global uint
*out) {
+ sampler_t s_nearest =
+ CLK_NORMALIZED_COORDS_FALSE | CLK_FILTER_NEAREST | CLK_ADDRESS_NONE;
+ int2 coord = (int2)(0, 0);
+ *out = read_imageui(img, s_nearest, coord).s0; // no warning
+}
+
+kernel void test_read_imageui_literal(read_only image2d_t img, global uint
*out) {
+ int2 coord = (int2)(0, 0);
+ // CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR | CLK_ADDRESS_CLAMP = 0x21
+ *out = read_imageui(img, CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR |
CLK_ADDRESS_CLAMP, coord).s0; // expected-warning{{'read_imageui' sampler must
use CLK_FILTER_NEAREST}}
+ // CLK_NORMALIZED_COORDS_FALSE | CLK_FILTER_NEAREST | CLK_ADDRESS_NONE = 0x10
+ *out = read_imageui(img, CLK_NORMALIZED_COORDS_FALSE | CLK_FILTER_NEAREST |
CLK_ADDRESS_NONE, coord).s0; // no warning
+}
+
+kernel void test_read_imageui_parameter(read_only image2d_t img, global uint
*out, sampler_t smp) {
+ int2 coord = (int2)(0, 0);
+ *out = read_imageui(img, smp, coord).s0; // no warning
+}
+
+kernel void test_read_imagef_linear(read_only image2d_t img, global float
*out) {
+ // read_imagef supports linear filtering: no warning.
+ float2 coord = (float2)(0.5f, 0.5f);
+ *out = read_imagef(img, glb_linear, coord).s0; // no warning
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/204086
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits