[llvm] [LLVM][CodeGen][AArch64] Increase opportunities to fold shift-of-extend into sshll/ushll. (PR #213989)
Paul Walker via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 08:44:16 PDT 2026
https://github.com/paulwalker-arm updated https://github.com/llvm/llvm-project/pull/213989
>From 83faa3d1489d77e777f0b50457f8e89e6574db30 Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Tue, 4 Aug 2026 16:43:14 +0100
Subject: [PATCH 1/5] Add tests.
---
.../CodeGen/AArch64/neon-shift-left-long.ll | 139 ++++++++++++++++++
1 file changed, 139 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
index a8c55b476b810..6c879026f5e90 100644
--- a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
+++ b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
@@ -473,3 +473,142 @@ define <8 x i16> @test_ushll_cmp(<8 x i8> %a, <8 x i8> %b) #0 {
%vmovl.i.i.i = zext <8 x i8> %vcgtz.i.i to <8 x i16>
ret <8 x i16> %vmovl.i.i.i
}
+
+define <8 x i16> @mul_of_shl_zext(<8 x i8> %a, <8 x i16> %b) {
+; CHECK-SD-LABEL: mul_of_shl_zext:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: ushll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: mul_of_shl_zext:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: ushll v0.8h, v0.8b, #1
+; CHECK-GI-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-GI-NEXT: ret
+ %a.ext = zext <8 x i8> %a to <8 x i16>
+ %shl = shl <8 x i16> %a.ext, splat (i16 1)
+ %mul = mul <8 x i16> %shl, %b
+ ret <8 x i16> %mul
+}
+
+define <8 x i16> @shl_of_mul_zext(<8 x i8> %a, <8 x i16> %b) {
+; CHECK-SD-LABEL: shl_of_mul_zext:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: ushll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: shl_of_mul_zext:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: ushll v0.8h, v0.8b, #0
+; CHECK-GI-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-GI-NEXT: shl v0.8h, v0.8h, #1
+; CHECK-GI-NEXT: ret
+ %a.ext = zext <8 x i8> %a to <8 x i16>
+ %mul = mul <8 x i16> %a.ext, %b
+ %shl = shl <8 x i16> %mul, splat (i16 1)
+ ret <8 x i16> %shl
+}
+
+define <8 x i16> @shl_of_mul_zext_zext(<8 x i8> %a, <8 x i8> %b) {
+; CHECK-SD-LABEL: shl_of_mul_zext_zext:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: umull v0.8h, v0.8b, v1.8b
+; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: shl_of_mul_zext_zext:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: umull v0.8h, v0.8b, v1.8b
+; CHECK-GI-NEXT: shl v0.8h, v0.8h, #1
+; CHECK-GI-NEXT: ret
+ %a.ext = zext <8 x i8> %a to <8 x i16>
+ %b.ext = zext <8 x i8> %b to <8 x i16>
+ %mul = mul <8 x i16> %a.ext, %b.ext
+ %shl = shl <8 x i16> %mul, splat (i16 1)
+ ret <8 x i16> %shl
+}
+
+define <8 x i16> @mul_of_shl_sext(<8 x i8> %a, <8 x i16> %b) {
+; CHECK-SD-LABEL: mul_of_shl_sext:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: mul_of_shl_sext:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: sshll v0.8h, v0.8b, #1
+; CHECK-GI-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-GI-NEXT: ret
+ %a.ext = sext <8 x i8> %a to <8 x i16>
+ %shl = shl <8 x i16> %a.ext, splat (i16 1)
+ %mul = mul <8 x i16> %shl, %b
+ ret <8 x i16> %mul
+}
+
+define <8 x i16> @shl_of_mul_sext(<8 x i8> %a, <8 x i16> %b) {
+; CHECK-SD-LABEL: shl_of_mul_sext:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: shl_of_mul_sext:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: sshll v0.8h, v0.8b, #0
+; CHECK-GI-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-GI-NEXT: shl v0.8h, v0.8h, #1
+; CHECK-GI-NEXT: ret
+ %a.ext = sext <8 x i8> %a to <8 x i16>
+ %mul = mul <8 x i16> %a.ext, %b
+ %shl = shl <8 x i16> %mul, splat (i16 1)
+ ret <8 x i16> %shl
+}
+
+define <8 x i16> @shl_of_mul_sext_sext(<8 x i8> %a, <8 x i8> %b) {
+; CHECK-SD-LABEL: shl_of_mul_sext_sext:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: smull v0.8h, v0.8b, v1.8b
+; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: shl_of_mul_sext_sext:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: smull v0.8h, v0.8b, v1.8b
+; CHECK-GI-NEXT: shl v0.8h, v0.8h, #1
+; CHECK-GI-NEXT: ret
+ %a.ext = sext <8 x i8> %a to <8 x i16>
+ %b.ext = sext <8 x i8> %b to <8 x i16>
+ %mul = mul <8 x i16> %a.ext, %b.ext
+ %shl = shl <8 x i16> %mul, splat (i16 1)
+ ret <8 x i16> %shl
+}
+
+define <8 x i16> @shl_of_multi_use_mul_sext(<8 x i8> %a, <8 x i16> %b) {
+; CHECK-SD-LABEL: shl_of_multi_use_mul_sext:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: mul v1.8h, v0.8h, v1.8h
+; CHECK-SD-NEXT: add v0.8h, v1.8h, v1.8h
+; CHECK-SD-NEXT: // fake_use: $q1
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: shl_of_multi_use_mul_sext:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: sshll v0.8h, v0.8b, #0
+; CHECK-GI-NEXT: mul v1.8h, v0.8h, v1.8h
+; CHECK-GI-NEXT: shl v0.8h, v1.8h, #1
+; CHECK-GI-NEXT: // fake_use: $q1
+; CHECK-GI-NEXT: ret
+ %a.ext = sext <8 x i8> %a to <8 x i16>
+ %mul = mul <8 x i16> %a.ext, %b
+ %shl = shl <8 x i16> %mul, splat (i16 1)
+ call void (...) @llvm.fake.use(<8 x i16> %mul)
+ ret <8 x i16> %shl
+}
>From e918d162a164dad06d894d37c31781aa9ce04026 Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Tue, 4 Aug 2026 15:59:19 +0100
Subject: [PATCH 2/5] [LLVM][CodeGen][AArch64] Fold shift-of-extend into
sshll/ushll.
Add PreprocessISelDAG logic to undo mul-of-shl to shl-of-mul
canonicalisation when either operand is sign/zero extended because the
extension can be folded into the shift.
---
.../Target/AArch64/AArch64ISelDAGToDAG.cpp | 17 +++++++
.../CodeGen/AArch64/neon-shift-left-long.ll | 49 +++++++------------
2 files changed, 34 insertions(+), 32 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index f6b90594b064e..6ba1c6c357edb 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -17,6 +17,7 @@
#include "MCTargetDesc/AArch64AddressingModes.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/CodeGen/ISDOpcodes.h"
+#include "llvm/CodeGen/SDPatternMatch.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/Function.h" // To access function attributes.
#include "llvm/IR/GlobalValue.h"
@@ -29,6 +30,7 @@
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+using namespace llvm::SDPatternMatch;
#define DEBUG_TYPE "aarch64-isel"
#define PASS_NAME "AArch64 Instruction Selection"
@@ -8300,6 +8302,21 @@ void AArch64DAGToDAGISel::PreprocessISelDAG() {
case AArch64ISD::CSEL:
Result = tryFoldCselToFMaxMin(N);
break;
+ case AArch64ISD::VSHL: {
+ SDValue LHS, RHS;
+ // Undo mul(shl(A,C),B) -> shl(mul(A,B),C) canonicalisation when A is an
+ // extend that can be folded into the shift.
+ if (sd_match(
+ N.getOperand(0),
+ m_Mul(m_Value(LHS, m_AnyOf(m_ZExt(m_Value()), m_SExt(m_Value()))),
+ m_Value(RHS)))) {
+ SDLoc DL(&N);
+ SDValue SHL = CurDAG->getNode(AArch64ISD::VSHL, DL, N.getValueType(0),
+ LHS, N.getOperand(1));
+ Result = CurDAG->getNode(ISD::MUL, DL, N.getValueType(0), SHL, RHS);
+ }
+ break;
+ }
default:
break;
}
diff --git a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
index 6c879026f5e90..0dd0528969f0a 100644
--- a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
+++ b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
@@ -475,18 +475,11 @@ define <8 x i16> @test_ushll_cmp(<8 x i8> %a, <8 x i8> %b) #0 {
}
define <8 x i16> @mul_of_shl_zext(<8 x i8> %a, <8 x i16> %b) {
-; CHECK-SD-LABEL: mul_of_shl_zext:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: ushll v0.8h, v0.8b, #0
-; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: mul_of_shl_zext:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: ushll v0.8h, v0.8b, #1
-; CHECK-GI-NEXT: mul v0.8h, v0.8h, v1.8h
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: mul_of_shl_zext:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushll v0.8h, v0.8b, #1
+; CHECK-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ret
%a.ext = zext <8 x i8> %a to <8 x i16>
%shl = shl <8 x i16> %a.ext, splat (i16 1)
%mul = mul <8 x i16> %shl, %b
@@ -496,9 +489,8 @@ define <8 x i16> @mul_of_shl_zext(<8 x i8> %a, <8 x i16> %b) {
define <8 x i16> @shl_of_mul_zext(<8 x i8> %a, <8 x i16> %b) {
; CHECK-SD-LABEL: shl_of_mul_zext:
; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: ushll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: ushll v0.8h, v0.8b, #1
; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
; CHECK-SD-NEXT: ret
;
; CHECK-GI-LABEL: shl_of_mul_zext:
@@ -533,18 +525,11 @@ define <8 x i16> @shl_of_mul_zext_zext(<8 x i8> %a, <8 x i8> %b) {
}
define <8 x i16> @mul_of_shl_sext(<8 x i8> %a, <8 x i16> %b) {
-; CHECK-SD-LABEL: mul_of_shl_sext:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #0
-; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: mul_of_shl_sext:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: sshll v0.8h, v0.8b, #1
-; CHECK-GI-NEXT: mul v0.8h, v0.8h, v1.8h
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: mul_of_shl_sext:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sshll v0.8h, v0.8b, #1
+; CHECK-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ret
%a.ext = sext <8 x i8> %a to <8 x i16>
%shl = shl <8 x i16> %a.ext, splat (i16 1)
%mul = mul <8 x i16> %shl, %b
@@ -554,9 +539,8 @@ define <8 x i16> @mul_of_shl_sext(<8 x i8> %a, <8 x i16> %b) {
define <8 x i16> @shl_of_mul_sext(<8 x i8> %a, <8 x i16> %b) {
; CHECK-SD-LABEL: shl_of_mul_sext:
; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #1
; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT: add v0.8h, v0.8h, v0.8h
; CHECK-SD-NEXT: ret
;
; CHECK-GI-LABEL: shl_of_mul_sext:
@@ -593,10 +577,11 @@ define <8 x i16> @shl_of_mul_sext_sext(<8 x i8> %a, <8 x i8> %b) {
define <8 x i16> @shl_of_multi_use_mul_sext(<8 x i8> %a, <8 x i16> %b) {
; CHECK-SD-LABEL: shl_of_multi_use_mul_sext:
; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #0
-; CHECK-SD-NEXT: mul v1.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT: add v0.8h, v1.8h, v1.8h
-; CHECK-SD-NEXT: // fake_use: $q1
+; CHECK-SD-NEXT: sshll v2.8h, v0.8b, #0
+; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #1
+; CHECK-SD-NEXT: mul v2.8h, v2.8h, v1.8h
+; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
+; CHECK-SD-NEXT: // fake_use: $q2
; CHECK-SD-NEXT: ret
;
; CHECK-GI-LABEL: shl_of_multi_use_mul_sext:
>From a21c2b6db81efd28249c2f905c1bec69d16efe0b Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Wed, 5 Aug 2026 10:14:45 +0000
Subject: [PATCH 3/5] Match variable names to the documentation.
---
llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 6ba1c6c357edb..678ec7f4ce2ac 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -8303,17 +8303,17 @@ void AArch64DAGToDAGISel::PreprocessISelDAG() {
Result = tryFoldCselToFMaxMin(N);
break;
case AArch64ISD::VSHL: {
- SDValue LHS, RHS;
// Undo mul(shl(A,C),B) -> shl(mul(A,B),C) canonicalisation when A is an
// extend that can be folded into the shift.
+ EVT VT = N.getValueType(0);
+ SDValue A, B, C = N.getOperand(1);
if (sd_match(
N.getOperand(0),
- m_Mul(m_Value(LHS, m_AnyOf(m_ZExt(m_Value()), m_SExt(m_Value()))),
- m_Value(RHS)))) {
+ m_Mul(m_Value(A, m_AnyOf(m_ZExt(m_Value()), m_SExt(m_Value()))),
+ m_Value(B)))) {
SDLoc DL(&N);
- SDValue SHL = CurDAG->getNode(AArch64ISD::VSHL, DL, N.getValueType(0),
- LHS, N.getOperand(1));
- Result = CurDAG->getNode(ISD::MUL, DL, N.getValueType(0), SHL, RHS);
+ SDValue SHL = CurDAG->getNode(AArch64ISD::VSHL, DL, VT, A, C);
+ Result = CurDAG->getNode(ISD::MUL, DL, VT, SHL, B);
}
break;
}
>From 4787b02aba11da38fb5dac30a2da86b425a66df3 Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Wed, 5 Aug 2026 10:56:13 +0000
Subject: [PATCH 4/5] Limit transformation to single use multiplies.
---
llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 8 ++++----
llvm/test/CodeGen/AArch64/neon-shift-left-long.ll | 9 ++++-----
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 678ec7f4ce2ac..354dc75220e0c 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -8307,10 +8307,10 @@ void AArch64DAGToDAGISel::PreprocessISelDAG() {
// extend that can be folded into the shift.
EVT VT = N.getValueType(0);
SDValue A, B, C = N.getOperand(1);
- if (sd_match(
- N.getOperand(0),
- m_Mul(m_Value(A, m_AnyOf(m_ZExt(m_Value()), m_SExt(m_Value()))),
- m_Value(B)))) {
+ if (sd_match(N.getOperand(0),
+ m_OneUse(m_Mul(m_Value(A, m_AnyOf(m_ZExt(m_Value()),
+ m_SExt(m_Value()))),
+ m_Value(B))))) {
SDLoc DL(&N);
SDValue SHL = CurDAG->getNode(AArch64ISD::VSHL, DL, VT, A, C);
Result = CurDAG->getNode(ISD::MUL, DL, VT, SHL, B);
diff --git a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
index 0dd0528969f0a..afb21c137c2b7 100644
--- a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
+++ b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
@@ -577,11 +577,10 @@ define <8 x i16> @shl_of_mul_sext_sext(<8 x i8> %a, <8 x i8> %b) {
define <8 x i16> @shl_of_multi_use_mul_sext(<8 x i8> %a, <8 x i16> %b) {
; CHECK-SD-LABEL: shl_of_multi_use_mul_sext:
; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sshll v2.8h, v0.8b, #0
-; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #1
-; CHECK-SD-NEXT: mul v2.8h, v2.8h, v1.8h
-; CHECK-SD-NEXT: mul v0.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT: // fake_use: $q2
+; CHECK-SD-NEXT: sshll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: mul v1.8h, v0.8h, v1.8h
+; CHECK-SD-NEXT: add v0.8h, v1.8h, v1.8h
+; CHECK-SD-NEXT: // fake_use: $q1
; CHECK-SD-NEXT: ret
;
; CHECK-GI-LABEL: shl_of_multi_use_mul_sext:
>From 9e3c44b89fbcaa97b19cf0ced1a646e49f5e668e Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Wed, 5 Aug 2026 15:39:38 +0000
Subject: [PATCH 5/5] Preserve the smull/umull idiom.
---
llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 354dc75220e0c..44c5ab4e96520 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -8311,6 +8311,9 @@ void AArch64DAGToDAGISel::PreprocessISelDAG() {
m_OneUse(m_Mul(m_Value(A, m_AnyOf(m_ZExt(m_Value()),
m_SExt(m_Value()))),
m_Value(B))))) {
+ // If both mul operands are extended, preserve the smull/umull idiom.
+ if (B.getOpcode() == A.getOpcode())
+ break;
SDLoc DL(&N);
SDValue SHL = CurDAG->getNode(AArch64ISD::VSHL, DL, VT, A, C);
Result = CurDAG->getNode(ISD::MUL, DL, VT, SHL, B);
More information about the llvm-commits
mailing list