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