[clang] [llvm] [Clang] Add diagnostic reasoning for unsatisfied is_destructible trait (PR #166967)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 9 09:29:04 PST 2025
https://github.com/AnushaK6 updated https://github.com/llvm/llvm-project/pull/166967
>From 14182fb64adde6e86a96f7a6ea0c22749124b827 Mon Sep 17 00:00:00 2001
From: AnushaK6 <anusha.k1300 at gmail.com>
Date: Fri, 7 Nov 2025 22:33:04 +0530
Subject: [PATCH 1/3] Add diagnostic reasoning for unsatisfied is_destructible
trait
---
.../clang/Basic/DiagnosticSemaKinds.td | 5 +-
clang/lib/Sema/SemaTypeTraits.cpp | 62 +++++++++++++++
.../type-traits-unsatisfied-diags-std.cpp | 76 +++++++++++++++++++
.../SemaCXX/type-traits-unsatisfied-diags.cpp | 49 ++++++++++++
4 files changed, 191 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4e369be0bbb92..ee357936e3a87 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1776,7 +1776,8 @@ def note_unsatisfied_trait
"%StandardLayout{standard-layout}|"
"%Aggregate{aggregate}|"
"%Final{final}|"
- "%Abstract{abstract}"
+ "%Abstract{abstract}|"
+ "%Destructible{destructible}"
"}1">;
def note_unsatisfied_trait_reason
@@ -1808,6 +1809,7 @@ def note_unsatisfied_trait_reason
"%NonStandardLayoutMember{has a non-standard-layout member %1 of type %2}|"
"%IndirectBaseWithFields{has an indirect base %1 with data members}|"
"%DeletedDtr{has a %select{deleted|user-provided}1 destructor}|"
+ "%InaccessibleDtr{has a %select{private|protected}1 destructor}|"
"%UserProvidedCtr{has a user provided %select{copy|move}1 "
"constructor}|"
"%UserDeclaredCtr{has a user-declared constructor}|"
@@ -1823,6 +1825,7 @@ def note_unsatisfied_trait_reason
"%FunctionType{is a function type}|"
"%CVVoidType{is a cv void type}|"
"%IncompleteArrayType{is an incomplete array type}|"
+ "%IncompleteType{is an incomplete type}|"
"%PrivateProtectedDirectDataMember{has a %select{private|protected}1 direct data member}|"
"%PrivateProtectedDirectBase{has a %select{private|protected}1 direct base}|"
"%NotClassOrUnion{is not a class or union type}|"
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 38877967af05e..e9b8032733efc 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2028,6 +2028,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
.Case("is_constructible", TypeTrait::TT_IsConstructible)
.Case("is_final", TypeTrait::UTT_IsFinal)
.Case("is_abstract", TypeTrait::UTT_IsAbstract)
+ .Case("is_destructible", TypeTrait::UTT_IsDestructible)
.Default(std::nullopt);
}
@@ -2399,6 +2400,64 @@ static void DiagnoseNonConstructibleReason(
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
}
+static void DiagnoseNonDestructibleReason(
+ Sema &SemaRef, SourceLocation Loc,
+ QualType T) {
+
+ QualType CoreT = T.getCanonicalType();
+ if (const ArrayType *AT = SemaRef.Context.getAsArrayType(CoreT))
+ CoreT = AT->getElementType();
+
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait) << CoreT << diag::TraitName::Destructible;
+
+
+ if (CoreT->isFunctionType()){
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) << diag::TraitNotSatisfiedReason::FunctionType;
+ return;
+ }
+
+ if(CoreT->isVoidType()){
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) << diag::TraitNotSatisfiedReason::CVVoidType;
+ return;
+ }
+
+ if (CoreT->isIncompleteType()) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) << diag::TraitNotSatisfiedReason::IncompleteType;
+ return;
+ }
+
+ const CXXRecordDecl *RD = CoreT->getAsCXXRecordDecl();
+ if (!RD || RD->isInvalidDecl())
+ return;
+
+ const CXXRecordDecl *Def = RD->getDefinition();
+ if (!Def) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::IncompleteType;
+ return;
+ }
+
+ CXXDestructorDecl *Dtor = Def->getDestructor();
+ if (!Dtor)
+ return;
+
+ if (Dtor->isDeleted()) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::DeletedDtr << 0
+ << Dtor->getSourceRange();
+ return;
+ }
+
+ AccessSpecifier AS = Dtor->getAccess();
+ if (AS == AS_private || AS == AS_protected) {
+ unsigned Select = (AS == AS_private) ? 0 : 1;
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::InaccessibleDtr << Select
+ << Dtor->getSourceRange();
+ return;
+ }
+}
+
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
SourceLocation Loc, QualType T) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
@@ -2889,6 +2948,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
case TT_IsConstructible:
DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
break;
+ case UTT_IsDestructible:
+ DiagnoseNonDestructibleReason(*this, E->getBeginLoc(), Args[0]);
+ break;
case UTT_IsAggregate:
DiagnoseNonAggregateReason(*this, E->getBeginLoc(), Args[0]);
break;
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 3e03a79275232..3e02fe8f10f56 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -73,6 +73,15 @@ struct is_abstract {
template <typename T>
constexpr bool is_abstract_v = __is_abstract(T);
+template <typename T>
+struct is_destructible {
+ static constexpr bool value = __is_destructible(T);
+};
+
+template <typename T>
+constexpr bool is_destructible_v = __is_destructible(T);
+
+
#endif
#ifdef STD2
@@ -167,6 +176,17 @@ using is_abstract = __details_is_abstract<T>;
template <typename T>
constexpr bool is_abstract_v = __is_abstract(T);
+template <typename T>
+struct __details_is_destructible {
+ static constexpr bool value = __is_destructible(T);
+};
+
+template <typename T>
+using is_destructible = __details_is_destructible<T>;
+
+template <typename T>
+constexpr bool is_destructible_v = __is_destructible(T);
+
#endif
@@ -252,6 +272,15 @@ using is_abstract = __details_is_abstract<T>;
template <typename T>
constexpr bool is_abstract_v = is_abstract<T>::value;
+template <typename T>
+struct __details_is_destructible : bool_constant<__is_destructible(T)> {};
+
+template <typename T>
+using is_destructible = __details_is_destructible<T>;
+
+template <typename T>
+constexpr bool is_destructible_v = is_destructible<T>::value;
+
#endif
}
@@ -374,6 +403,18 @@ static_assert(std::is_abstract_v<int&>);
// expected-note at -1 {{because it is a reference type}} \
// expected-note at -1 {{because it is not a struct or class type}}
+static_assert(std::is_destructible<int>::value);
+
+static_assert(std::is_destructible<void>::value);
+// expected-error-re at -1 {{static assertion failed due to requirement 'std::{{.*}}is_destructible<void>::value'}} \
+// expected-note at -1 {{'void' is not destructible}} \
+// expected-note at -1 {{because it is a cv void type}}
+
+static_assert(std::is_destructible_v<void>);
+// expected-error at -1 {{static assertion failed due to requirement 'std::is_destructible_v<void>'}} \
+// expected-note at -1 {{'void' is not destructible}} \
+// expected-note at -1 {{because it is a cv void type}}
+
namespace test_namespace {
using namespace std;
@@ -473,6 +514,17 @@ namespace test_namespace {
// expected-note at -1 {{'int &' is not abstract}} \
// expected-note at -1 {{because it is a reference type}} \
// expected-note at -1 {{because it is not a struct or class type}}
+
+ static_assert(is_destructible<void>::value);
+ // expected-error-re at -1 {{static assertion failed due to requirement '{{.*}}is_destructible<void>::value'}} \
+ // expected-note at -1 {{'void' is not destructible}} \
+ // expected-note at -1 {{because it is a cv void type}}
+
+ static_assert(is_destructible_v<void>);
+ // expected-error at -1 {{static assertion failed due to requirement 'is_destructible_v<void>'}} \
+ // expected-note at -1 {{'void' is not destructible}} \
+ // expected-note at -1 {{because it is a cv void type}}
+
}
@@ -518,6 +570,15 @@ concept C5 = std::is_aggregate_v<T>; // #concept10
template <C5 T> void g5(); // #cand10
+template <typename T>
+requires std::is_destructible<T>::value void f6(); // #cand11
+
+template <typename T>
+concept C6 = std::is_destructible_v<T>; // #concept11
+
+template <C6 T> void g6(); // #cand12
+
+
void test() {
f<int&>();
// expected-error at -1 {{no matching function for call to 'f'}} \
@@ -589,6 +650,21 @@ void test() {
// expected-note@#concept10 {{because 'std::is_aggregate_v<void>' evaluated to false}} \
// expected-note@#concept10 {{'void' is not aggregate}} \
// expected-note@#concept10 {{because it is a cv void type}}
+
+ f6<void>();
+ // expected-error at -1 {{no matching function for call to 'f6'}} \
+ // expected-note@#cand11 {{candidate template ignored: constraints not satisfied [with T = void]}} \
+ // expected-note-re@#cand11 {{because '{{.*}}is_destructible<void>::value' evaluated to false}} \
+ // expected-note@#cand11 {{'void' is not destructible}} \
+ // expected-note@#cand11 {{because it is a cv void type}}
+
+ g6<void>();
+ // expected-error at -1 {{no matching function for call to 'g6'}} \
+ // expected-note@#cand12 {{candidate template ignored: constraints not satisfied [with T = void]}} \
+ // expected-note@#cand12 {{because 'void' does not satisfy 'C6'}} \
+ // expected-note@#concept11 {{because 'std::is_destructible_v<void>' evaluated to false}} \
+ // expected-note@#concept11 {{'void' is not destructible}} \
+ // expected-note@#concept11 {{because it is a cv void type}}
}
}
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index 22740418f09f5..858a5cc24868f 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -1052,3 +1052,52 @@ static_assert(__is_abstract(U));
// expected-note at -1 {{because it is not a struct or class type}}
}
+namespace destructible {
+
+struct Incomplete; // expected-note {{forward declaration of 'destructible::Incomplete'}}
+static_assert(__is_destructible(Incomplete));
+// expected-error at -1 {{incomplete type 'Incomplete' used in type trait expression}}
+
+static_assert(__is_destructible(void));
+// expected-error at -1 {{static assertion failed due to requirement '__is_destructible(void)'}} \
+// expected-note at -1 {{'void' is not destructible}} \
+// expected-note at -1 {{because it is a cv void type}}
+
+using F = void();
+static_assert(__is_destructible(F));
+// expected-error at -1 {{static assertion failed due to requirement '__is_destructible(void ())'}} \
+// expected-note at -1 {{'void ()' is not destructible}} \
+// expected-note at -1 {{because it is a function type}}
+
+using Ref = int&;
+static_assert(__is_destructible(Ref)); // no diagnostics (true)
+
+struct DeletedDtor { // #d-DeletedDtor
+ ~DeletedDtor() = delete;
+};
+static_assert(__is_destructible(DeletedDtor));
+// expected-error at -1 {{static assertion failed due to requirement '__is_destructible(destructible::DeletedDtor)'}} \
+// expected-note at -1 {{'destructible::DeletedDtor' is not destructible}} \
+// expected-note at -1 {{because it has a deleted destructor}}
+
+struct PrivateDtor { // #d-PrivateDtor
+private:
+ ~PrivateDtor(); // #d-PrivateDtor-dtor
+};
+static_assert(__is_destructible(PrivateDtor));
+// expected-error at -1 {{static assertion failed due to requirement '__is_destructible(destructible::PrivateDtor)'}} \
+// expected-note at -1 {{'destructible::PrivateDtor' is not destructible}} \
+// expected-note at -1 {{because it has a private destructor}}
+
+struct BaseInaccessible { // #d-BaseInacc
+private:
+ ~BaseInaccessible(); // #d-BaseInacc-dtor
+};
+
+struct DerivedFromInaccessible : BaseInaccessible {}; // #d-DerivedInacc
+static_assert(__is_destructible(DerivedFromInaccessible));
+// expected-error at -1 {{static assertion failed due to requirement '__is_destructible(destructible::DerivedFromInaccessible)'}} \
+// expected-note at -1 {{'destructible::DerivedFromInaccessible' is not destructible}} \
+// expected-note at -1 {{because it has a deleted destructor}}
+
+}
>From 5b5bdbfeafceedec79b173bf8e1d317818d7127d Mon Sep 17 00:00:00 2001
From: AnushaK6 <anusha.k1300 at gmail.com>
Date: Fri, 7 Nov 2025 22:34:51 +0530
Subject: [PATCH 2/3] [NFC] Format code using clang-format
---
clang/lib/Sema/SemaTypeTraits.cpp | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index e9b8032733efc..fef47dfc2cc51 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2400,29 +2400,31 @@ static void DiagnoseNonConstructibleReason(
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
}
-static void DiagnoseNonDestructibleReason(
- Sema &SemaRef, SourceLocation Loc,
- QualType T) {
+static void DiagnoseNonDestructibleReason(Sema &SemaRef, SourceLocation Loc,
+ QualType T) {
QualType CoreT = T.getCanonicalType();
if (const ArrayType *AT = SemaRef.Context.getAsArrayType(CoreT))
CoreT = AT->getElementType();
- SemaRef.Diag(Loc, diag::note_unsatisfied_trait) << CoreT << diag::TraitName::Destructible;
-
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
+ << CoreT << diag::TraitName::Destructible;
- if (CoreT->isFunctionType()){
- SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) << diag::TraitNotSatisfiedReason::FunctionType;
+ if (CoreT->isFunctionType()) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::FunctionType;
return;
}
-
- if(CoreT->isVoidType()){
- SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) << diag::TraitNotSatisfiedReason::CVVoidType;
+
+ if (CoreT->isVoidType()) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::CVVoidType;
return;
}
if (CoreT->isIncompleteType()) {
- SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) << diag::TraitNotSatisfiedReason::IncompleteType;
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::IncompleteType;
return;
}
@@ -2433,7 +2435,7 @@ static void DiagnoseNonDestructibleReason(
const CXXRecordDecl *Def = RD->getDefinition();
if (!Def) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
- << diag::TraitNotSatisfiedReason::IncompleteType;
+ << diag::TraitNotSatisfiedReason::IncompleteType;
return;
}
>From 8ba77ae65bbfd5b809c17de7c718c451c535ca54 Mon Sep 17 00:00:00 2001
From: AnushaK6 <anusha.k1300 at gmail.com>
Date: Sun, 9 Nov 2025 22:58:51 +0530
Subject: [PATCH 3/3] [GlobalISel] Port computeNumSignBits for G_MUL
---
.../CodeGen/GlobalISel/GISelValueTracking.cpp | 37 +++++++++
.../AArch64/GlobalISel/knownbits-mul.mir | 79 +++++++++++++++++++
llvm/test/CodeGen/AArch64/combine-sdiv.ll | 4 +-
llvm/test/CodeGen/AArch64/rem-by-const.ll | 3 +-
4 files changed, 118 insertions(+), 5 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-mul.mir
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index c1fb8b6d78ff8..3a4d8c27ac88b 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -37,6 +37,8 @@
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/KnownFPClass.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/CodeGen/GlobalISel/Utils.h"
+#include "llvm/IR/Constants.h"
#define DEBUG_TYPE "gisel-known-bits"
@@ -2084,6 +2086,41 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
break;
}
+ case TargetOpcode::G_MUL: {
+ Register Src1 = MI.getOperand(1).getReg();
+ Register Src2 = MI.getOperand(2).getReg();
+
+ KnownBits Known1 = getKnownBits(Src1, DemandedElts, Depth + 1);
+ KnownBits Known2 = getKnownBits(Src2, DemandedElts, Depth + 1);
+
+ if (Known1.isZero() || Known2.isZero())
+ return TyBits;
+
+ auto C1 = getIConstantVRegValWithLookThrough(Src1, MRI);
+ auto C2 = getIConstantVRegValWithLookThrough(Src2, MRI);
+
+ if (C1 && C2) {
+ APInt Val1 = C1->Value;
+ APInt Val2 = C2->Value;
+ APInt Product = Val1 * Val2;
+ return Product.getNumSignBits();
+ }
+ unsigned Src1NumSignBits =
+ computeNumSignBits(Src1, DemandedElts, Depth + 1);
+ if(Src1NumSignBits==1){
+ return 1;
+ }
+ unsigned Src2NumSignBits =
+ computeNumSignBits(Src2, DemandedElts, Depth + 1);
+ if(Src2NumSignBits==1){
+ return 1;
+ }
+
+ unsigned OutValidBits =
+ (TyBits - Src1NumSignBits + 1) + (TyBits - Src2NumSignBits + 1);
+ FirstAnswer = OutValidBits > TyBits ? 1 : TyBits - OutValidBits + 1;
+ break;
+ }
case TargetOpcode::G_FCMP:
case TargetOpcode::G_ICMP: {
bool IsFP = Opcode == TargetOpcode::G_FCMP;
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-mul.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-mul.mir
new file mode 100644
index 0000000000000..ea5281948a211
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-mul.mir
@@ -0,0 +1,79 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=aarch64 -passes="print<gisel-value-tracking>" -filetype=null %s 2>&1 | FileCheck %s
+
+---
+name: ConstPositives
+body: |
+ bb.1:
+ ; CHECK-LABEL: name: @ConstPositives
+ ; CHECK-NEXT: %0:_ KnownBits:00000011 SignBits:6
+ ; CHECK-NEXT: %1:_ KnownBits:00000101 SignBits:5
+ ; CHECK-NEXT: %2:_ KnownBits:00001111 SignBits:4
+ %0:_(s8) = G_CONSTANT i8 3
+ %1:_(s8) = G_CONSTANT i8 5
+ %2:_(s8) = G_MUL %0, %1
+...
+---
+name: ConstZero
+body: |
+ bb.1:
+ ; CHECK-LABEL: name: @ConstZero
+ ; CHECK-NEXT: %0:_ KnownBits:00000000 SignBits:8
+ ; CHECK-NEXT: %1:_ KnownBits:00000001 SignBits:7
+ ; CHECK-NEXT: %2:_ KnownBits:00000000 SignBits:8
+ %0:_(s8) = G_CONSTANT i8 0
+ %1:_(s8) = G_CONSTANT i8 1
+ %2:_(s8) = G_MUL %0, %1
+...
+---
+name: ConstNegatives
+body: |
+ bb.1:
+ ; CHECK-LABEL: name: @ConstNegatives
+ ; CHECK-NEXT: %0:_ KnownBits:11111110 SignBits:7
+ ; CHECK-NEXT: %1:_ KnownBits:11111100 SignBits:6
+ ; CHECK-NEXT: %2:_ KnownBits:00001000 SignBits:4
+ %0:_(s8) = G_CONSTANT i8 -2
+ %1:_(s8) = G_CONSTANT i8 -4
+ %2:_(s8) = G_MUL %0, %1
+...
+---
+name: MixedSigns
+body: |
+ bb.1:
+ ; CHECK-LABEL: name: @MixedSigns
+ ; CHECK-NEXT: %0:_ KnownBits:11111100 SignBits:6
+ ; CHECK-NEXT: %1:_ KnownBits:00000011 SignBits:6
+ ; CHECK-NEXT: %2:_ KnownBits:11110100 SignBits:4
+ %0:_(s8) = G_CONSTANT i8 -4
+ %1:_(s8) = G_CONSTANT i8 3
+ %2:_(s8) = G_MUL %0, %1
+...
+---
+name: UnknownVar
+body: |
+ bb.1:
+ ; CHECK-LABEL: name: @UnknownVar
+ ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+ ; CHECK-NEXT: %1:_ KnownBits:00000010 SignBits:6
+ ; CHECK-NEXT: %2:_ KnownBits:???????0 SignBits:1
+ %0:_(s8) = COPY $b0
+ %1:_(s8) = G_CONSTANT i8 2
+ %2:_(s8) = G_MUL %0, %1
+...
+---
+name: VectorMul
+body: |
+ bb.1:
+ ; CHECK-LABEL: name: @VectorMul
+ ; CHECK-NEXT: %0:_ KnownBits:0000000000000001 SignBits:15
+ ; CHECK-NEXT: %1:_ KnownBits:0000000000000010 SignBits:14
+ ; CHECK-NEXT: %2:_ KnownBits:00000000000000?? SignBits:14
+ ; CHECK-NEXT: %3:_ KnownBits:00000000000000?? SignBits:14
+ ; CHECK-NEXT: %4:_ KnownBits:000000000000???? SignBits:12
+ %0:_(s16) = G_CONSTANT i16 1
+ %1:_(s16) = G_CONSTANT i16 2
+ %2:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0
+ %3:_(<4 x s16>) = G_BUILD_VECTOR %1, %0, %0, %1
+ %4:_(<4 x s16>) = G_MUL %2, %3
+...
diff --git a/llvm/test/CodeGen/AArch64/combine-sdiv.ll b/llvm/test/CodeGen/AArch64/combine-sdiv.ll
index cca190f08df2b..37ea64f700fd8 100644
--- a/llvm/test/CodeGen/AArch64/combine-sdiv.ll
+++ b/llvm/test/CodeGen/AArch64/combine-sdiv.ll
@@ -1510,7 +1510,6 @@ define i5 @combine_i5_sdiv_const7(i5 %x) {
; CHECK-GI-NEXT: sbfx w9, w0, #0, #5
; CHECK-GI-NEXT: sbfx w8, w8, #0, #5
; CHECK-GI-NEXT: mul w8, w9, w8
-; CHECK-GI-NEXT: sbfx w8, w8, #0, #10
; CHECK-GI-NEXT: add w8, w0, w8, asr #5
; CHECK-GI-NEXT: sbfx w8, w8, #0, #5
; CHECK-GI-NEXT: asr w8, w8, #2
@@ -1560,7 +1559,6 @@ define i8 @combine_i8_sdiv_const7(i8 %x) {
; CHECK-GI-NEXT: sxtb w8, w0
; CHECK-GI-NEXT: mov w9, #-109 // =0xffffff93
; CHECK-GI-NEXT: mul w8, w8, w9
-; CHECK-GI-NEXT: sxth w8, w8
; CHECK-GI-NEXT: add w8, w0, w8, asr #8
; CHECK-GI-NEXT: sbfx w8, w8, #2, #6
; CHECK-GI-NEXT: ubfx w9, w8, #7, #1
@@ -1585,7 +1583,7 @@ define i8 @combine_i8_sdiv_const100(i8 %x) {
; CHECK-GI-NEXT: sxtb w8, w0
; CHECK-GI-NEXT: mov w9, #41 // =0x29
; CHECK-GI-NEXT: mul w8, w8, w9
-; CHECK-GI-NEXT: sbfx w8, w8, #8, #8
+; CHECK-GI-NEXT: asr w8, w8, #8
; CHECK-GI-NEXT: asr w8, w8, #4
; CHECK-GI-NEXT: ubfx w9, w8, #7, #1
; CHECK-GI-NEXT: add w0, w8, w9
diff --git a/llvm/test/CodeGen/AArch64/rem-by-const.ll b/llvm/test/CodeGen/AArch64/rem-by-const.ll
index 87b11086e28d5..9cc00fae412a0 100644
--- a/llvm/test/CodeGen/AArch64/rem-by-const.ll
+++ b/llvm/test/CodeGen/AArch64/rem-by-const.ll
@@ -21,7 +21,6 @@ define i8 @si8_7(i8 %a, i8 %b) {
; CHECK-GI-NEXT: sxtb w8, w0
; CHECK-GI-NEXT: mov w9, #-109 // =0xffffff93
; CHECK-GI-NEXT: mul w8, w8, w9
-; CHECK-GI-NEXT: sxth w8, w8
; CHECK-GI-NEXT: add w8, w0, w8, asr #8
; CHECK-GI-NEXT: sbfx w8, w8, #2, #6
; CHECK-GI-NEXT: ubfx w9, w8, #7, #1
@@ -52,7 +51,7 @@ define i8 @si8_100(i8 %a, i8 %b) {
; CHECK-GI-NEXT: sxtb w8, w0
; CHECK-GI-NEXT: mov w9, #41 // =0x29
; CHECK-GI-NEXT: mul w8, w8, w9
-; CHECK-GI-NEXT: sbfx w8, w8, #8, #8
+; CHECK-GI-NEXT: asr w8, w8, #8
; CHECK-GI-NEXT: asr w8, w8, #4
; CHECK-GI-NEXT: ubfx w9, w8, #7, #1
; CHECK-GI-NEXT: add w8, w8, w9
More information about the llvm-commits
mailing list