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

Reply via email to