llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Pengcheng Wang (wangpc-pp)

<details>
<summary>Changes</summary>

`__riscv_vlenb()` reads the `vlenb` CSR, which holds `VLEN/8`.

In this PR, we attach a range return attribute to the emitted
`read_register("vlenb")` call, derived from the target's VLEN
bounds via `TargetInfo::getVScaleRange()`:

  VLENB = VScale * RVVBytesPerBlock

So the result is in `[MinVLEN/8, MaxVLEN/8]`.

And, when the maximum VScale is unbounded we fall back to the
architectural maximum VLEN of 65536 (VLENB of 8192).

Fixes #<!-- -->217784.

Assisted-by: TRAE CLI (Opus 4.8)



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


2 Files Affected:

- (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+20-1) 
- (modified) clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/vlenb.c 
(+82-2) 


``````````diff
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp 
b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 66e04f2ea06b3..32dd6738df84d 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -12,6 +12,7 @@
 
 #include "CodeGenFunction.h"
 #include "clang/Basic/TargetBuiltins.h"
+#include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/IntrinsicsRISCV.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
 #include "llvm/TargetParser/RISCVTargetParser.h"
@@ -294,7 +295,25 @@ emitRVVVlenbBuiltin(CodeGenFunction *CGF, const CallExpr 
*E,
   llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
   llvm::Function *F =
       CGM.getIntrinsic(llvm::Intrinsic::read_register, {CGF->SizeTy});
-  return Builder.CreateCall(F, Metadata);
+  llvm::CallInst *Result = Builder.CreateCall(F, Metadata);
+
+  // vlenb reads the vlenb CSR, which holds VLEN/8. Attach a range return
+  // attribute derived from the target's VLEN bounds so generic value analyses
+  // (e.g. InstCombine via CallBase::getRange()) can fold vlenb comparisons.
+  // VScale is measured in units of RVVBitsPerBlock, so VLENB = VScale *
+  // RVVBytesPerBlock. A zero upper bound means unbounded, in which case we 
fall
+  // back to the architectural maximum VLEN of 65536 (i.e. VLENB of 8192).
+  if (auto VScale = CGM.getTarget().getVScaleRange(
+          CGF->getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming)) {
+    unsigned BitWidth = CGF->SizeTy->getBitWidth();
+    uint64_t Lo = (uint64_t)VScale->first * llvm::RISCV::RVVBytesPerBlock;
+    uint64_t Hi = VScale->second
+                      ? (uint64_t)VScale->second * 
llvm::RISCV::RVVBytesPerBlock
+                      : 65536 / 8;
+    Result->addRangeRetAttr(llvm::ConstantRange(llvm::APInt(BitWidth, Lo),
+                                                llvm::APInt(BitWidth, Hi + 
1)));
+  }
+  return Result;
 }
 
 static LLVM_ATTRIBUTE_NOINLINE Value *
diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/vlenb.c 
b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/vlenb.c
index 2b8875def7ced..f3ebc6da3bd9b 100644
--- a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/vlenb.c
+++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/vlenb.c
@@ -4,28 +4,102 @@
 // RUN:     | opt -S -O2 | FileCheck --check-prefix=RV32 %s
 // RUN: %clang_cc1 -triple riscv64 -target-feature +v -disable-O0-optnone 
-emit-llvm -Qn %s -o - \
 // RUN:     | opt -S -O2 | FileCheck --check-prefix=RV64 %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zvl512b 
-disable-O0-optnone -emit-llvm -Qn %s -o - \
+// RUN:     | opt -S -O2 | FileCheck --check-prefix=RV64V512 %s
 
 #include <riscv_vector.h>
 
 // RV32-LABEL: @test_vlenb(
 // RV32-NEXT:  entry:
-// RV32-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.read_register.i32(metadata 
[[META4:![0-9]+]])
+// RV32-NEXT:    [[TMP0:%.*]] = tail call range(i32 16, 8193) i32 
@llvm.read_register.i32(metadata [[META4:![0-9]+]])
 // RV32-NEXT:    ret i32 [[TMP0]]
 //
 // RV64-LABEL: @test_vlenb(
 // RV64-NEXT:  entry:
-// RV64-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.read_register.i64(metadata 
[[META4:![0-9]+]])
+// RV64-NEXT:    [[TMP0:%.*]] = tail call range(i64 16, 8193) i64 
@llvm.read_register.i64(metadata [[META4:![0-9]+]])
 // RV64-NEXT:    ret i64 [[TMP0]]
 //
+// RV64V512-LABEL: @test_vlenb(
+// RV64V512-NEXT:  entry:
+// RV64V512-NEXT:    [[TMP0:%.*]] = tail call range(i64 64, 8193) i64 
@llvm.read_register.i64(metadata [[META4:![0-9]+]])
+// RV64V512-NEXT:    ret i64 [[TMP0]]
+//
 unsigned long test_vlenb(void) {
   return __riscv_vlenb();
 }
+
+// VLENB is at least VLEN/8, and the V extension guarantees VLEN >= 128, so
+// vlenb >= 16 always holds and the comparison folds to true.
+// RV32-LABEL: @test_vlenb_ge_min(
+// RV32-NEXT:  entry:
+// RV32-NEXT:    ret i32 1
+//
+// RV64-LABEL: @test_vlenb_ge_min(
+// RV64-NEXT:  entry:
+// RV64-NEXT:    ret i32 1
+//
+// RV64V512-LABEL: @test_vlenb_ge_min(
+// RV64V512-NEXT:  entry:
+// RV64V512-NEXT:    ret i32 1
+//
+int test_vlenb_ge_min(void) {
+  return __riscv_vlenb() >= 16;
+}
+
+// VLENB is at most VLEN/8 = 65536/8 = 8192, so vlenb > 8192 is never true and
+// the comparison folds to false.
+// RV32-LABEL: @test_vlenb_gt_max(
+// RV32-NEXT:  entry:
+// RV32-NEXT:    ret i32 0
+//
+// RV64-LABEL: @test_vlenb_gt_max(
+// RV64-NEXT:  entry:
+// RV64-NEXT:    ret i32 0
+//
+// RV64V512-LABEL: @test_vlenb_gt_max(
+// RV64V512-NEXT:  entry:
+// RV64V512-NEXT:    ret i32 0
+//
+int test_vlenb_gt_max(void) {
+  return __riscv_vlenb() > 8192;
+}
+
+// With zvl512b the minimum VLEN is 512, so vlenb >= 64 always holds and folds
+// to true there; plain +v only guarantees vlenb >= 16, so the comparison must
+// stay for the RV32/RV64 (VLEN128) runs.
+// RV32-LABEL: @test_vlenb_ge_zvl512(
+// RV32-NEXT:  entry:
+// RV32-NEXT:    [[TMP0:%.*]] = tail call range(i32 16, 8193) i32 
@llvm.read_register.i32(metadata [[META4]])
+// RV32-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[TMP0]], 63
+// RV32-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+// RV32-NEXT:    ret i32 [[CONV]]
+//
+// RV64-LABEL: @test_vlenb_ge_zvl512(
+// RV64-NEXT:  entry:
+// RV64-NEXT:    [[TMP0:%.*]] = tail call range(i64 16, 8193) i64 
@llvm.read_register.i64(metadata [[META4]])
+// RV64-NEXT:    [[CMP:%.*]] = icmp samesign ugt i64 [[TMP0]], 63
+// RV64-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+// RV64-NEXT:    ret i32 [[CONV]]
+//
+// RV64V512-LABEL: @test_vlenb_ge_zvl512(
+// RV64V512-NEXT:  entry:
+// RV64V512-NEXT:    ret i32 1
+//
+int test_vlenb_ge_zvl512(void) {
+  return __riscv_vlenb() >= 64;
+}
 //.
 // RV32: attributes #[[ATTR0:[0-9]+]] = { mustprogress nofree noinline 
norecurse nosync nounwind willreturn memory(read) vscale_range(2,1024) 
"no-trapping-math"="true" "stack-protector-buffer-size"="8" 
"target-features"="+32bit,+d,+f,+i,+v,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b"
 }
 // RV32: attributes #[[ATTR1:[0-9]+]] = { mustprogress nocallback nofree 
nosync nounwind willreturn memory(read) }
+// RV32: attributes #[[ATTR2:[0-9]+]] = { mustprogress nofree noinline 
norecurse nosync nounwind willreturn memory(none) vscale_range(2,1024) 
"no-trapping-math"="true" "stack-protector-buffer-size"="8" 
"target-features"="+32bit,+d,+f,+i,+v,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b"
 }
 //.
 // RV64: attributes #[[ATTR0:[0-9]+]] = { mustprogress nofree noinline 
norecurse nosync nounwind willreturn memory(read) vscale_range(2,1024) 
"no-trapping-math"="true" "stack-protector-buffer-size"="8" 
"target-features"="+64bit,+d,+f,+i,+v,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b"
 }
 // RV64: attributes #[[ATTR1:[0-9]+]] = { mustprogress nocallback nofree 
nosync nounwind willreturn memory(read) }
+// RV64: attributes #[[ATTR2:[0-9]+]] = { mustprogress nofree noinline 
norecurse nosync nounwind willreturn memory(none) vscale_range(2,1024) 
"no-trapping-math"="true" "stack-protector-buffer-size"="8" 
"target-features"="+64bit,+d,+f,+i,+v,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b"
 }
+//.
+// RV64V512: attributes #[[ATTR0:[0-9]+]] = { mustprogress nofree noinline 
norecurse nosync nounwind willreturn memory(read) vscale_range(8,1024) 
"no-trapping-math"="true" "stack-protector-buffer-size"="8" 
"target-features"="+64bit,+d,+f,+i,+v,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl256b,+zvl32b,+zvl512b,+zvl64b"
 }
+// RV64V512: attributes #[[ATTR1:[0-9]+]] = { mustprogress nocallback nofree 
nosync nounwind willreturn memory(read) }
+// RV64V512: attributes #[[ATTR2:[0-9]+]] = { mustprogress nofree noinline 
norecurse nosync nounwind willreturn memory(none) vscale_range(8,1024) 
"no-trapping-math"="true" "stack-protector-buffer-size"="8" 
"target-features"="+64bit,+d,+f,+i,+v,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl256b,+zvl32b,+zvl512b,+zvl64b"
 }
 //.
 // RV32: [[META0:![0-9]+]] = !{i32 1, !"target-abi", !"ilp32d"}
 // RV32: [[META1:![0-9]+]] = !{i32 6, !"riscv-isa", [[META2:![0-9]+]]}
@@ -39,3 +113,9 @@ unsigned long test_vlenb(void) {
 // RV64: [[META3:![0-9]+]] = !{i32 8, !"SmallDataLimit", i32 0}
 // RV64: [[META4]] = !{!"vlenb"}
 //.
+// RV64V512: [[META0:![0-9]+]] = !{i32 1, !"target-abi", !"lp64d"}
+// RV64V512: [[META1:![0-9]+]] = !{i32 6, !"riscv-isa", [[META2:![0-9]+]]}
+// RV64V512: [[META2]] = 
!{!"rv64i2p1_f2p2_d2p2_v1p0_zicsr2p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl256b1p0_zvl32b1p0_zvl512b1p0_zvl64b1p0"}
+// RV64V512: [[META3:![0-9]+]] = !{i32 8, !"SmallDataLimit", i32 0}
+// RV64V512: [[META4]] = !{!"vlenb"}
+//.

``````````

</details>


https://github.com/llvm/llvm-project/pull/219924
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to