diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -1996,11 +1996,6 @@ } } else if (auto *C1VTy = dyn_cast(C1->getType())) { - // Do not iterate on scalable vector. The number of elements is unknown at - // compile-time. - if (isa(C1VTy)) - return nullptr; - // Fast path for splatted constants. if (Constant *C1Splat = C1->getSplatValue()) if (Constant *C2Splat = C2->getSplatValue()) @@ -2008,6 +2003,11 @@ C1VTy->getElementCount(), ConstantExpr::getCompare(pred, C1Splat, C2Splat)); + // Do not iterate on scalable vector. The number of elements is unknown at + // compile-time. + if (isa(C1VTy)) + return nullptr; + // If we can constant fold the comparison of each element, constant fold // the whole vector comparison. SmallVector ResElts; diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -1501,6 +1501,8 @@ return CV->getSplatValue(); if (const ConstantVector *CV = dyn_cast(this)) return CV->getSplatValue(AllowUndefs); + // FIXME: this should be able to get a splat value from scalable vector splats + // of the form returned by ConstantVector::getSplat() return nullptr; } diff --git a/llvm/test/Analysis/ConstantFolding/cmp-vec-fast-path.ll b/llvm/test/Analysis/ConstantFolding/cmp-vec-fast-path.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/ConstantFolding/cmp-vec-fast-path.ll @@ -0,0 +1,424 @@ + +; Check that cmp's of scalable vector splats are constant folded +; FIXME: Constant::getSplatValue() only knows how to get the splat value of +; ConstantAggregateZero values with scalable vector type. Once it is +; extended to support arbitrary splats, this test should be updated + +; RUN: opt -instcombine -S < %s | FileCheck %s + + +; CHECK-LABEL: i32cmp_eq_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @i32cmp_eq_fixed() { + %res = icmp eq <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_eq_scalable +; CHECK: ret +define @i32cmp_eq_scalable() { + %res = icmp eq zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_ne_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @i32cmp_ne_fixed() { + %res = icmp ne <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_ne_scalable +; CHECK: ret zeroinitializer +define @i32cmp_ne_scalable() { + %res = icmp ne zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_ugt_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @i32cmp_ugt_fixed() { + %res = icmp ugt <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_ugt_scalable +; CHECK: ret zeroinitializer +define @i32cmp_ugt_scalable() { + %res = icmp ugt zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_uge_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @i32cmp_uge_fixed() { + %res = icmp uge <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_uge_scalable +; CHECK: ret +define @i32cmp_uge_scalable() { + %res = icmp uge zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_ult_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @i32cmp_ult_fixed() { + %res = icmp ult <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_ult_scalable +; CHECK: ret zeroinitializer +define @i32cmp_ult_scalable() { + %res = icmp ult zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_ule_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @i32cmp_ule_fixed() { + %res = icmp ule <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_ule_scalable +; CHECK: ret +define @i32cmp_ule_scalable() { + %res = icmp ule zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_sgt_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @i32cmp_sgt_fixed() { + %res = icmp sgt <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_sgt_scalable +; CHECK: ret zeroinitializer +define @i32cmp_sgt_scalable() { + %res = icmp sgt zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_sge_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @i32cmp_sge_fixed() { + %res = icmp sge <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_sge_scalable +; CHECK: ret +define @i32cmp_sge_scalable() { + %res = icmp sge zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_slt_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @i32cmp_slt_fixed() { + %res = icmp slt <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_slt_scalable +; CHECK: ret zeroinitializer +define @i32cmp_slt_scalable() { + %res = icmp slt zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: i32cmp_sle_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @i32cmp_sle_fixed() { + %res = icmp sle <2 x i32> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: i32cmp_sle_scalable +; CHECK: ret +define @i32cmp_sle_scalable() { + %res = icmp sle zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_false_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_false_fixed() { + %res = fcmp false <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_false_scalable +; CHECK: ret zeroinitializer +define @floatcmp_false_scalable() { + %res = fcmp false zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_oeq_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_oeq_fixed() { + %res = fcmp oeq <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_oeq_scalable +; CHECK: ret +define @floatcmp_oeq_scalable() { + %res = fcmp oeq zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_ogt_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_ogt_fixed() { + %res = fcmp ogt <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_ogt_scalable +; CHECK: ret zeroinitializer +define @floatcmp_ogt_scalable() { + %res = fcmp ogt zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_oge_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_oge_fixed() { + %res = fcmp oge <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_oge_scalable +; CHECK: ret +define @floatcmp_oge_scalable() { + %res = fcmp oge zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_olt_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_olt_fixed() { + %res = fcmp olt <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_olt_scalable +; CHECK: ret zeroinitializer +define @floatcmp_olt_scalable() { + %res = fcmp olt zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_ole_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_ole_fixed() { + %res = fcmp ole <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_ole_scalable +; CHECK: ret +define @floatcmp_ole_scalable() { + %res = fcmp ole zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_one_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_one_fixed() { + %res = fcmp one <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_one_scalable +; CHECK: ret zeroinitializer +define @floatcmp_one_scalable() { + %res = fcmp one zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_ord_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_ord_fixed() { + %res = fcmp ord <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_ord_scalable +; CHECK: ret +define @floatcmp_ord_scalable() { + %res = fcmp ord zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_ueq_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_ueq_fixed() { + %res = fcmp ueq <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_ueq_scalable +; CHECK: ret +define @floatcmp_ueq_scalable() { + %res = fcmp ueq zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_ugt_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_ugt_fixed() { + %res = fcmp ugt <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_ugt_scalable +; CHECK: ret zeroinitializer +define @floatcmp_ugt_scalable() { + %res = fcmp ugt zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_uge_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_uge_fixed() { + %res = fcmp uge <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_uge_scalable +; CHECK: ret +define @floatcmp_uge_scalable() { + %res = fcmp uge zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_ult_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_ult_fixed() { + %res = fcmp ult <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_ult_scalable +; CHECK: ret zeroinitializer +define @floatcmp_ult_scalable() { + %res = fcmp ult zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_ule_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_ule_fixed() { + %res = fcmp ule <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_ule_scalable +; CHECK: ret +define @floatcmp_ule_scalable() { + %res = fcmp ule zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_une_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_une_fixed() { + %res = fcmp une <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_une_scalable +; CHECK: ret zeroinitializer +define @floatcmp_une_scalable() { + %res = fcmp une zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_uno_fixed +; CHECK: ret <2 x i1> zeroinitializer +define <2 x i1> @floatcmp_uno_fixed() { + %res = fcmp uno <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_uno_scalable +; CHECK: ret zeroinitializer +define @floatcmp_uno_scalable() { + %res = fcmp uno zeroinitializer, zeroinitializer + ret %res +} + + +; CHECK-LABEL: floatcmp_true_fixed +; CHECK: ret <2 x i1> shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer) +define <2 x i1> @floatcmp_true_fixed() { + %res = fcmp true <2 x float> zeroinitializer, zeroinitializer + ret <2 x i1> %res +} + + +; CHECK-LABEL: floatcmp_true_scalable +; CHECK: ret +define @floatcmp_true_scalable() { + %res = fcmp true zeroinitializer, zeroinitializer + ret %res +} +