Index: llvm/docs/BitCodeFormat.rst =================================================================== --- llvm/docs/BitCodeFormat.rst +++ llvm/docs/BitCodeFormat.rst @@ -1091,7 +1091,8 @@ The ``vscale_range`` attribute has a special encoding for its arguments. Its two arguments, which are 32-bit integers, are packed into one 64-bit integer value (i.e. ``(Min << 32) | Max``), with ``Max`` taking on the value of ``Min`` if - it is not specified. + it is not specified. The definition of ``vscale_range`` implies the ``vscale`` + is power-of-two value. .. _TYPE_BLOCK: Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -2336,7 +2336,8 @@ 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. + about the range of vscale. The values of min and max are power-of-two + value if the attribute is present. ``"nooutline"`` This attribute indicates that outlining passes should not modify the function. Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -2195,10 +2195,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")) { Index: llvm/test/Transforms/InstCombine/icmp-vscale.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-vscale.ll +++ 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 ; Index: llvm/test/Transforms/InstCombine/vscale_sext_and_zext.ll =================================================================== --- llvm/test/Transforms/InstCombine/vscale_sext_and_zext.ll +++ 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() Index: llvm/test/Transforms/InstCombine/vscale_trunc.ll =================================================================== --- llvm/test/Transforms/InstCombine/vscale_trunc.ll +++ 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() Index: llvm/test/Verifier/vscale_range.ll =================================================================== --- llvm/test/Verifier/vscale_range.ll +++ 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)