bool Is64Bit = Subtarget.is64Bit();
bool HasSSE2 = Subtarget.hasSSE2();
+ bool HasSSE41 = Subtarget.hasSSE41();
bool HasAVX2 = Subtarget.hasAVX2();
bool HasAVX512 = Subtarget.hasAVX512();
+ bool HasVLX = Subtarget.hasVLX();
+ bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
const LLT s8 = LLT::scalar(8);
.clampScalar(0, s8, sMaxScalar)
.scalarize(0);
+ // integer multiply
+ getActionDefinitionsBuilder(G_MUL)
+ .legalIf([=](const LegalityQuery &Query) -> bool {
+ if (typeInSet(0, {s8, s16, s32})(Query))
+ return true;
+ if (Is64Bit && typeInSet(0, {s64})(Query))
+ return true;
+ if (HasSSE2 && typeInSet(0, {v8s16})(Query))
+ return true;
+ if (HasSSE41 && typeInSet(0, {v4s32})(Query))
+ return true;
+ if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query))
+ return true;
+ if (HasAVX512 && typeInSet(0, {v16s32})(Query))
+ return true;
+ if (HasDQI && typeInSet(0, {v8s64})(Query))
+ return true;
+ if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query))
+ return true;
+ if (HasBWI && typeInSet(0, {v32s16})(Query))
+ return true;
+ return false;
+ })
+ .clampMinNumElements(0, s16, 8)
+ .clampMinNumElements(0, s32, 4)
+ .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
+ .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
+ .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
+ .clampMaxNumElements(0, s64, 8)
+ .widenScalarToNextPow2(0, /*Min=*/32)
+ .clampScalar(0, s8, sMaxScalar)
+ .scalarize(0);
+
// integer divisions
getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
.legalIf([=](const LegalityQuery &Query) -> bool {
auto &LegacyInfo = getLegacyLegalizerInfo();
LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(G_PHI, 0, widen_1);
- for (unsigned BinOp : {G_MUL, G_AND, G_OR, G_XOR})
+ for (unsigned BinOp : {G_AND, G_OR, G_XOR})
LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(BinOp, 0, widen_1);
for (unsigned MemOp : {G_LOAD, G_STORE})
LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(
for (auto Ty : {s8, s16, s32, p0})
LegacyInfo.setAction({G_PHI, Ty}, LegacyLegalizeActions::Legal);
- for (unsigned BinOp : {G_MUL, G_AND, G_OR, G_XOR})
+ for (unsigned BinOp : {G_AND, G_OR, G_XOR})
for (auto Ty : {s8, s16, s32})
LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal);
LegacyInfo.setAction({G_PHI, s64}, LegacyLegalizeActions::Legal);
- for (unsigned BinOp : {G_MUL, G_AND, G_OR, G_XOR})
+ for (unsigned BinOp : {G_AND, G_OR, G_XOR})
LegacyInfo.setAction({BinOp, s64}, LegacyLegalizeActions::Legal);
for (unsigned MemOp : {G_LOAD, G_STORE})
for (auto Ty : {s64, v2s64})
LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal);
- LegacyInfo.setAction({G_MUL, v8s16}, LegacyLegalizeActions::Legal);
-
LegacyInfo.setAction({G_FPEXT, s64}, LegacyLegalizeActions::Legal);
LegacyInfo.setAction({G_FPEXT, 1, s32}, LegacyLegalizeActions::Legal);
void X86LegalizerInfo::setLegalizerInfoSSE41() {
if (!Subtarget.hasSSE41())
return;
-
- const LLT v4s32 = LLT::fixed_vector(4, 32);
-
- auto &LegacyInfo = getLegacyLegalizerInfo();
-
- LegacyInfo.setAction({G_MUL, v4s32}, LegacyLegalizeActions::Legal);
}
void X86LegalizerInfo::setLegalizerInfoSSE42() {
if (!Subtarget.hasSSE42())
return;
-
}
void X86LegalizerInfo::setLegalizerInfoAVX() {
auto &LegacyInfo = getLegacyLegalizerInfo();
- for (auto Ty : {v16s16, v8s32})
- LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
-
// Merge/Unmerge
for (const auto &Ty : {v64s8, v32s16, v16s32, v8s64}) {
LegacyInfo.setAction({G_CONCAT_VECTORS, Ty}, LegacyLegalizeActions::Legal);
auto &LegacyInfo = getLegacyLegalizerInfo();
-
- LegacyInfo.setAction({G_MUL, v16s32}, LegacyLegalizeActions::Legal);
-
for (unsigned MemOp : {G_LOAD, G_STORE})
for (auto Ty : {v16s32, v8s64})
LegacyInfo.setAction({MemOp, Ty}, LegacyLegalizeActions::Legal);
LegacyInfo.setAction({G_INSERT, 1, Ty}, LegacyLegalizeActions::Legal);
LegacyInfo.setAction({G_EXTRACT, Ty}, LegacyLegalizeActions::Legal);
}
-
- /************ VLX *******************/
- if (!Subtarget.hasVLX())
- return;
-
- for (auto Ty : {v4s32, v8s32})
- LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
}
void X86LegalizerInfo::setLegalizerInfoAVX512DQ() {
if (!(Subtarget.hasAVX512() && Subtarget.hasDQI()))
return;
-
- const LLT v8s64 = LLT::fixed_vector(8, 64);
-
- auto &LegacyInfo = getLegacyLegalizerInfo();
-
- LegacyInfo.setAction({G_MUL, v8s64}, LegacyLegalizeActions::Legal);
-
- /************ VLX *******************/
- if (!Subtarget.hasVLX())
- return;
-
- const LLT v2s64 = LLT::fixed_vector(2, 64);
- const LLT v4s64 = LLT::fixed_vector(4, 64);
-
- for (auto Ty : {v2s64, v4s64})
- LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
}
void X86LegalizerInfo::setLegalizerInfoAVX512BW() {
if (!(Subtarget.hasAVX512() && Subtarget.hasBWI()))
return;
-
- const LLT v32s16 = LLT::fixed_vector(32, 16);
-
- auto &LegacyInfo = getLegacyLegalizerInfo();
-
- LegacyInfo.setAction({G_MUL, v32s16}, LegacyLegalizeActions::Legal);
-
- /************ VLX *******************/
- if (!Subtarget.hasVLX())
- return;
-
- const LLT v8s16 = LLT::fixed_vector(8, 16);
- const LLT v16s16 = LLT::fixed_vector(16, 16);
-
- for (auto Ty : {v8s16, v16s16})
- LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
}
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -O0 -mtriple=x86_64-linux-gnu -run-pass=legalizer %s -o - | FileCheck %s
+# RUN: llc -O0 -mtriple=x86_64-linux-gnu -run-pass=legalizer %s -o - | FileCheck %s --check-prefixes=CHECK,X64
+# RUN: llc -O0 -mtriple=i386-linux-gnu -run-pass=legalizer -global-isel-abort=2 -pass-remarks-missed='gisel*' %s 2>%t -o - | FileCheck %s --check-prefixes=CHECK,X86
+# RUN: FileCheck -check-prefix=ERR32 %s < %t
+
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %14:_(s32) = G_UMULH %7:_, %9:_ (in function: test_mul_i42)
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %10:_(s32) = G_UMULH %3:_, %5:_ (in function: test_mul_i64)
--- |
define void @test_mul_i1() { ret void }
ret i16 %ret
}
+ define i27 @test_mul_i27(i27 %arg1, i27 %arg2) {
+ %ret = mul i27 %arg1, %arg2
+ ret i27 %ret
+ }
+
define i32 @test_mul_i32(i32 %arg1, i32 %arg2) {
%ret = mul i32 %arg1, %arg2
ret i32 %ret
}
+ define i42 @test_mul_i42(i42 %arg1, i42 %arg2) {
+ %ret = mul i42 %arg1, %arg2
+ ret i42 %ret
+ }
+
define i64 @test_mul_i64(i64 %arg1, i64 %arg2) {
%ret = mul i64 %arg1, %arg2
ret i64 %ret
RET 0, implicit $ax
...
---
+name: test_mul_i27
+alignment: 16
+legalized: false
+regBankSelected: false
+registers:
+ - { id: 0, class: _ }
+ - { id: 1, class: _ }
+ - { id: 2, class: _ }
+body: |
+ bb.1 (%ir-block.0):
+
+ ;
+ ;
+ ; CHECK-LABEL: name: test_mul_i27
+ ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edx
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY]], [[COPY]]
+ ; CHECK-NEXT: $eax = COPY [[MUL]](s32)
+ ; CHECK-NEXT: RET 0
+ %0(s32) = COPY $edx
+ %1(s27) = G_TRUNC %0(s32)
+ %2(s27) = G_MUL %1, %1
+ %3:_(s32) = G_ANYEXT %2
+ $eax = COPY %3
+ RET 0
+...
+---
+
name: test_mul_i32
alignment: 16
legalized: false
RET 0, implicit $eax
...
---
+name: test_mul_i42
+alignment: 16
+legalized: false
+regBankSelected: false
+registers:
+ - { id: 0, class: _ }
+ - { id: 1, class: _ }
+ - { id: 2, class: _ }
+body: |
+ bb.1 (%ir-block.0):
+ liveins: $rdi, $rsi
+
+ ; X64-LABEL: name: test_mul_i42
+ ; X64: liveins: $rdi, $rsi
+ ; X64-NEXT: {{ $}}
+ ; X64-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdx
+ ; X64-NEXT: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY]]
+ ; X64-NEXT: $rax = COPY [[MUL]](s64)
+ ; X64-NEXT: RET 0
+ ; X86-LABEL: name: test_mul_i42
+ ; X86: liveins: $rdi, $rsi
+ ; X86-NEXT: {{ $}}
+ ; X86-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdx
+ ; X86-NEXT: [[TRUNC:%[0-9]+]]:_(s42) = G_TRUNC [[COPY]](s64)
+ ; X86-NEXT: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[TRUNC]](s42)
+ ; X86-NEXT: [[ANYEXT1:%[0-9]+]]:_(s64) = G_ANYEXT [[TRUNC]](s42)
+ ; X86-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[ANYEXT]](s64)
+ ; X86-NEXT: [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[ANYEXT1]](s64)
+ ; X86-NEXT: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV2]]
+ ; X86-NEXT: [[MUL1:%[0-9]+]]:_(s32) = G_MUL [[UV1]], [[UV2]]
+ ; X86-NEXT: [[MUL2:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV3]]
+ ; X86-NEXT: [[UMULH:%[0-9]+]]:_(s32) = G_UMULH [[UV]], [[UV2]]
+ ; X86-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[MUL1]], [[MUL2]]
+ ; X86-NEXT: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[UMULH]]
+ ; X86-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[MUL]](s32), [[ADD1]](s32)
+ ; X86-NEXT: [[TRUNC1:%[0-9]+]]:_(s42) = G_TRUNC [[MV]](s64)
+ ; X86-NEXT: [[ANYEXT2:%[0-9]+]]:_(s64) = G_ANYEXT [[TRUNC1]](s42)
+ ; X86-NEXT: $rax = COPY [[ANYEXT2]](s64)
+ ; X86-NEXT: RET 0
+ %0(s64) = COPY $rdx
+ %1(s42) = G_TRUNC %0(s64)
+ %2(s42) = G_MUL %1, %1
+ %3:_(s64) = G_ANYEXT %2
+ $rax = COPY %3
+ RET 0
+...
+---
name: test_mul_i64
alignment: 16
legalized: false
bb.1 (%ir-block.0):
liveins: $rdi, $rsi
- ; CHECK-LABEL: name: test_mul_i64
- ; CHECK: liveins: $rdi, $rsi
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdi
- ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $rsi
- ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]]
- ; CHECK-NEXT: $rax = COPY [[MUL]](s64)
- ; CHECK-NEXT: RET 0, implicit $rax
+ ; X64-LABEL: name: test_mul_i64
+ ; X64: liveins: $rdi, $rsi
+ ; X64-NEXT: {{ $}}
+ ; X64-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdi
+ ; X64-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $rsi
+ ; X64-NEXT: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]]
+ ; X64-NEXT: $rax = COPY [[MUL]](s64)
+ ; X64-NEXT: RET 0, implicit $rax
+ ; X86-LABEL: name: test_mul_i64
+ ; X86: liveins: $rdi, $rsi
+ ; X86-NEXT: {{ $}}
+ ; X86-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdi
+ ; X86-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $rsi
+ ; X86-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY]](s64)
+ ; X86-NEXT: [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY1]](s64)
+ ; X86-NEXT: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV2]]
+ ; X86-NEXT: [[MUL1:%[0-9]+]]:_(s32) = G_MUL [[UV1]], [[UV2]]
+ ; X86-NEXT: [[MUL2:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV3]]
+ ; X86-NEXT: [[UMULH:%[0-9]+]]:_(s32) = G_UMULH [[UV]], [[UV2]]
+ ; X86-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[MUL1]], [[MUL2]]
+ ; X86-NEXT: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[UMULH]]
+ ; X86-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[MUL]](s32), [[ADD1]](s32)
+ ; X86-NEXT: $rax = COPY [[MV]](s64)
+ ; X86-NEXT: RET 0, implicit $rax
%0(s64) = COPY $rdi
%1(s64) = COPY $rsi
%2(s64) = G_MUL %0, %1