diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -5772,13 +5772,29 @@ static Value *simplifyIntrinsic(CallBase *Call, const SimplifyQuery &Q) { - // Intrinsics with no operands have some kind of side effect. Don't simplify. unsigned NumOperands = Call->getNumArgOperands(); - if (!NumOperands) - return nullptr; - Function *F = cast(Call->getCalledFunction()); Intrinsic::ID IID = F->getIntrinsicID(); + + // Most of the intrinsics with no operands have some kind of side effect. + // Don't simplify. + if (!NumOperands) { + switch (IID) { + case Intrinsic::vscale: { + auto Attr = Call->getFunction()->getFnAttribute(Attribute::VScaleRange); + if (!Attr.isValid()) + return nullptr; + unsigned MinSVEVectorSize, MaxSVEVectorSize; + std::tie(MinSVEVectorSize, MaxSVEVectorSize) = Attr.getVScaleRangeArgs(); + if (MinSVEVectorSize == MaxSVEVectorSize && MaxSVEVectorSize != 0) + return ConstantInt::get(F->getReturnType(), MinSVEVectorSize); + return nullptr; + } + default: + return nullptr; + } + } + if (NumOperands == 1) return simplifyUnaryIntrinsic(F, Call->getArgOperand(0), Q); diff --git a/llvm/test/Transforms/InstSimplify/fold-vscale.ll b/llvm/test/Transforms/InstSimplify/fold-vscale.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fold-vscale.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i64 @vscale_i64() #1 { +; CHECK-LABEL: @vscale_i64( +; CHECK-NEXT: ret i64 16 +; + %1 = call i64 @llvm.vscale.i64() + %out = shl i64 %1, 4 + ret i64 %out +} + +define i32 @vscale_i32() #2 { +; CHECK-LABEL: @vscale_i32( +; CHECK-NEXT: ret i32 8 +; + %1 = call i32 @llvm.vscale.i32() + %out = shl i32 %1, 2 + ret i32 %out +} + +define i64 @vscale_i64_diff() #3 { +; CHECK-LABEL: @vscale_i64_diff( +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64() +; CHECK-NEXT: [[OUT:%.*]] = shl i64 [[TMP1]], 4 +; CHECK-NEXT: ret i64 [[OUT]] +; + %1 = call i64 @llvm.vscale.i64() + %out = shl i64 %1, 4 + ret i64 %out +} + +; Function Attrs: nofree nosync nounwind readnone willreturn +declare i64 @llvm.vscale.i64() #0 + +; Function Attrs: nofree nosync nounwind readnone willreturn +declare i32 @llvm.vscale.i32() #0 + +attributes #0 = { nofree nosync nounwind readnone willreturn } +attributes #1 = { mustprogress nofree nosync nounwind uwtable vscale_range(1,1) } +attributes #2 = { mustprogress nofree nosync nounwind uwtable vscale_range(2,2) } +attributes #3 = { mustprogress nofree nosync nounwind uwtable vscale_range(2,4) } + +