diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2331,11 +2331,12 @@ than `UINT_MAX`. It's unspecified which threshold will be used when duplicate definitions are linked together with differing values. ``vscale_range([, ])`` - This attribute indicates the minimum and maximum vscale value for the given - function. The min must be greater than 0. A maximum value of 0 means - unbounded. If the optional max value is omitted then max is set to the - value of min. If the attribute is not present, no assumptions are made - about the range of vscale. + This function attribute indicates `vscale` is a power-of-two within a + specified range. `min` must be a power-of-two that is greater than 0. When + specified, `max` must be a power-of-two greater-than-or-equal to `min` or 0 + to signify an unbounded maximum. The syntax `vscale_range()` can be + used to set both `min` and `max` to the same value. Functions that don't + include this attribute make no assumptions about the value of `vscale`. ``"nooutline"`` This attribute indicates that outlining passes should not modify the function. diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2181,10 +2181,13 @@ unsigned VScaleMin = Attrs.getFnAttrs().getVScaleRangeMin(); if (VScaleMin == 0) CheckFailed("'vscale_range' minimum must be greater than 0", V); - + else if (!isPowerOf2_32(VScaleMin)) + CheckFailed("'vscale_range' minimum must be power-of-two value", V); std::optional VScaleMax = Attrs.getFnAttrs().getVScaleRangeMax(); if (VScaleMax && VScaleMin > VScaleMax) CheckFailed("'vscale_range' minimum cannot be greater than maximum", V); + else if (VScaleMax && !isPowerOf2_32(*VScaleMax)) + CheckFailed("'vscale_range' maximum must be power-of-two value", V); } if (Attrs.hasFnAttr("frame-pointer")) { diff --git a/llvm/test/Transforms/InstCombine/icmp-vscale.ll b/llvm/test/Transforms/InstCombine/icmp-vscale.ll --- a/llvm/test/Transforms/InstCombine/icmp-vscale.ll +++ b/llvm/test/Transforms/InstCombine/icmp-vscale.ll @@ -82,85 +82,85 @@ ret i1 %res } -define i1 @vscale_ule_max() vscale_range(5,10) { +define i1 @vscale_ule_max() vscale_range(4,8) { ; CHECK-LABEL: @vscale_ule_max( ; CHECK-NEXT: ret i1 true ; %vscale = call i16 @llvm.vscale.i16() - %res = icmp ule i16 %vscale, 10 + %res = icmp ule i16 %vscale, 8 ret i1 %res } -define i1 @vscale_ult_max() vscale_range(5,10) { +define i1 @vscale_ult_max() vscale_range(4,8) { ; CHECK-LABEL: @vscale_ult_max( ; CHECK-NEXT: [[VSCALE:%.*]] = call i16 @llvm.vscale.i16() -; CHECK-NEXT: [[RES:%.*]] = icmp ult i16 [[VSCALE]], 10 +; CHECK-NEXT: [[RES:%.*]] = icmp ult i16 [[VSCALE]], 8 ; CHECK-NEXT: ret i1 [[RES]] ; %vscale = call i16 @llvm.vscale.i16() - %res = icmp ult i16 %vscale, 10 + %res = icmp ult i16 %vscale, 8 ret i1 %res } -define i1 @vscale_uge_min() vscale_range(5,10) { +define i1 @vscale_uge_min() vscale_range(4,8) { ; CHECK-LABEL: @vscale_uge_min( ; CHECK-NEXT: ret i1 true ; %vscale = call i16 @llvm.vscale.i16() - %res = icmp uge i16 %vscale, 5 + %res = icmp uge i16 %vscale, 4 ret i1 %res } -define i1 @vscale_ugt_min() vscale_range(5,10) { +define i1 @vscale_ugt_min() vscale_range(4,8) { ; CHECK-LABEL: @vscale_ugt_min( ; CHECK-NEXT: [[VSCALE:%.*]] = call i16 @llvm.vscale.i16() -; CHECK-NEXT: [[RES:%.*]] = icmp ugt i16 [[VSCALE]], 5 +; CHECK-NEXT: [[RES:%.*]] = icmp ugt i16 [[VSCALE]], 4 ; CHECK-NEXT: ret i1 [[RES]] ; %vscale = call i16 @llvm.vscale.i16() - %res = icmp ugt i16 %vscale, 5 + %res = icmp ugt i16 %vscale, 4 ret i1 %res } -define i1 @vscale_uge_no_max() vscale_range(5) { +define i1 @vscale_uge_no_max() vscale_range(4) { ; CHECK-LABEL: @vscale_uge_no_max( ; CHECK-NEXT: ret i1 true ; %vscale = call i8 @llvm.vscale.i8() - %res = icmp uge i8 %vscale, 5 + %res = icmp uge i8 %vscale, 4 ret i1 %res } -define i1 @vscale_ugt_no_max() vscale_range(5) { +define i1 @vscale_ugt_no_max() vscale_range(4) { ; CHECK-LABEL: @vscale_ugt_no_max( ; CHECK-NEXT: ret i1 false ; %vscale = call i8 @llvm.vscale.i8() - %res = icmp ugt i8 %vscale, 5 + %res = icmp ugt i8 %vscale, 4 ret i1 %res } -define i1 @vscale_uge_max_overflow() vscale_range(5,256) { +define i1 @vscale_uge_max_overflow() vscale_range(4,256) { ; CHECK-LABEL: @vscale_uge_max_overflow( ; CHECK-NEXT: ret i1 true ; %vscale = call i8 @llvm.vscale.i8() - %res = icmp uge i8 %vscale, 5 + %res = icmp uge i8 %vscale, 4 ret i1 %res } -define i1 @vscale_ugt_max_overflow() vscale_range(5,256) { +define i1 @vscale_ugt_max_overflow() vscale_range(4,256) { ; CHECK-LABEL: @vscale_ugt_max_overflow( ; CHECK-NEXT: [[VSCALE:%.*]] = call i8 @llvm.vscale.i8() -; CHECK-NEXT: [[RES:%.*]] = icmp ugt i8 [[VSCALE]], 5 +; CHECK-NEXT: [[RES:%.*]] = icmp ugt i8 [[VSCALE]], 4 ; CHECK-NEXT: ret i1 [[RES]] ; %vscale = call i8 @llvm.vscale.i8() - %res = icmp ugt i8 %vscale, 5 + %res = icmp ugt i8 %vscale, 4 ret i1 %res } -define i1 @vscale_eq_min_overflow() vscale_range(256,300) { +define i1 @vscale_eq_min_overflow() vscale_range(256,512) { ; CHECK-LABEL: @vscale_eq_min_overflow( ; CHECK-NEXT: ret i1 true ; @@ -169,7 +169,7 @@ ret i1 %res } -define i1 @vscale_ult_min_overflow() vscale_range(256,300) { +define i1 @vscale_ult_min_overflow() vscale_range(256,512) { ; CHECK-LABEL: @vscale_ult_min_overflow( ; CHECK-NEXT: ret i1 true ; @@ -178,7 +178,7 @@ ret i1 %res } -define i1 @vscale_ugt_min_overflow() vscale_range(256,300) { +define i1 @vscale_ugt_min_overflow() vscale_range(256,512) { ; CHECK-LABEL: @vscale_ugt_min_overflow( ; CHECK-NEXT: ret i1 true ; diff --git a/llvm/test/Transforms/InstCombine/vscale_sext_and_zext.ll b/llvm/test/Transforms/InstCombine/vscale_sext_and_zext.ll --- a/llvm/test/Transforms/InstCombine/vscale_sext_and_zext.ll +++ b/llvm/test/Transforms/InstCombine/vscale_sext_and_zext.ll @@ -5,7 +5,7 @@ ; Sign-extend ; -define i32 @vscale_SExt_i8toi32() vscale_range(1, 127) { +define i32 @vscale_SExt_i8toi32() vscale_range(1, 64) { ; CHECK-LABEL: @vscale_SExt_i8toi32( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.vscale.i32() diff --git a/llvm/test/Transforms/InstCombine/vscale_trunc.ll b/llvm/test/Transforms/InstCombine/vscale_trunc.ll --- a/llvm/test/Transforms/InstCombine/vscale_trunc.ll +++ b/llvm/test/Transforms/InstCombine/vscale_trunc.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s -define i8 @vscale_trunc_i32toi8() vscale_range(1, 255) { +define i8 @vscale_trunc_i32toi8() vscale_range(1, 128) { ; CHECK-LABEL: @vscale_trunc_i32toi8( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i8 @llvm.vscale.i8() diff --git a/llvm/test/Verifier/vscale_range.ll b/llvm/test/Verifier/vscale_range.ll --- a/llvm/test/Verifier/vscale_range.ll +++ b/llvm/test/Verifier/vscale_range.ll @@ -5,3 +5,9 @@ ; CHECK: 'vscale_range' minimum cannot be greater than maximum declare ptr @b(ptr) vscale_range(8, 1) + +; CHECK: 'vscale_range' minimum must be power-of-two value +declare ptr @c(ptr) vscale_range(3, 16) + +; CHECK: 'vscale_range' maximum must be power-of-two value +declare ptr @d(ptr) vscale_range(2, 5)