From f2bbb4cb3e211de82987b280aa98565bd3ff6ce7 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 23 May 2024 01:26:48 +0800 Subject: [PATCH] [GISel][RISCV] Legalize `G_{U|S}DIVREM` (#93067) This patch expands `G_{U|S}DIVREM` into `G_{U|S}DIV + G_{U|S}REM`. `G_{U|S}DIVREM` is generated by the following fold: https://github.com/llvm/llvm-project/blob/4ea21a0261cd8599a9ffa15f5c554ab0d4bbbe27/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp#L1410-L1471 It always folds `div + rem` pairs into `divrem` during pre-legalization. I tried to change `isLegalOrBeforeLegalizer` to `isLegal`, but it produced worse codegen on AArch64. --- .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 3 + .../legalizer/legalize-div-rv32.mir | 90 +++++++++++++++++++ .../legalizer/legalize-div-rv64.mir | 90 +++++++++++++++++++ 3 files changed, 183 insertions(+) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp index a1d3aadb816a..c6d11b8a8bd7 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp @@ -349,6 +349,9 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) .widenScalarToNextPow2(0); } + // TODO: Use libcall for sDoubleXLen. + getActionDefinitionsBuilder({G_UDIVREM, G_SDIVREM}).lower(); + auto &AbsActions = getActionDefinitionsBuilder(G_ABS); if (ST.hasStdExtZbb()) AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen); diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv32.mir index 4177a40e3826..26d8785afb47 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv32.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv32.mir @@ -555,3 +555,93 @@ body: | PseudoRET implicit $x10, implicit $x11 ... +--- +name: udivrem_i32 +body: | + bb.1.entry: + liveins: $x10, $x11 + + ; CHECK-I-LABEL: name: udivrem_i32 + ; CHECK-I: liveins: $x10, $x11 + ; CHECK-I-NEXT: {{ $}} + ; CHECK-I-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-I-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s32) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s32) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__udivsi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s32) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s32) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__umodsi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-I-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY2]], [[COPY3]] + ; CHECK-I-NEXT: $x10 = COPY [[ADD]](s32) + ; CHECK-I-NEXT: PseudoRET implicit $x10 + ; + ; CHECK-M-LABEL: name: udivrem_i32 + ; CHECK-M: liveins: $x10, $x11 + ; CHECK-M-NEXT: {{ $}} + ; CHECK-M-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-M-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11 + ; CHECK-M-NEXT: [[UDIV:%[0-9]+]]:_(s32) = G_UDIV [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[UREM:%[0-9]+]]:_(s32) = G_UREM [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[UDIV]], [[UREM]] + ; CHECK-M-NEXT: $x10 = COPY [[ADD]](s32) + ; CHECK-M-NEXT: PseudoRET implicit $x10 + %0:_(s32) = COPY $x10 + %1:_(s32) = COPY $x11 + %2:_(s32), %3:_(s32) = G_UDIVREM %0, %1 + %4:_(s32) = G_ADD %2, %3 + $x10 = COPY %4(s32) + PseudoRET implicit $x10 + +... +--- +name: sdivrem_i32 +body: | + bb.1.entry: + liveins: $x10, $x11 + + ; CHECK-I-LABEL: name: sdivrem_i32 + ; CHECK-I: liveins: $x10, $x11 + ; CHECK-I-NEXT: {{ $}} + ; CHECK-I-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-I-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s32) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s32) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__divsi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s32) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s32) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__modsi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-I-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY2]], [[COPY3]] + ; CHECK-I-NEXT: $x10 = COPY [[ADD]](s32) + ; CHECK-I-NEXT: PseudoRET implicit $x10 + ; + ; CHECK-M-LABEL: name: sdivrem_i32 + ; CHECK-M: liveins: $x10, $x11 + ; CHECK-M-NEXT: {{ $}} + ; CHECK-M-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10 + ; CHECK-M-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11 + ; CHECK-M-NEXT: [[SDIV:%[0-9]+]]:_(s32) = G_SDIV [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[SREM:%[0-9]+]]:_(s32) = G_SREM [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[SDIV]], [[SREM]] + ; CHECK-M-NEXT: $x10 = COPY [[ADD]](s32) + ; CHECK-M-NEXT: PseudoRET implicit $x10 + %0:_(s32) = COPY $x10 + %1:_(s32) = COPY $x11 + %2:_(s32), %3:_(s32) = G_SDIVREM %0, %1 + %4:_(s32) = G_ADD %2, %3 + $x10 = COPY %4(s32) + PseudoRET implicit $x10 + +... diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv64.mir index 492f9530997c..bbbe38f695d2 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv64.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-div-rv64.mir @@ -655,3 +655,93 @@ body: | PseudoRET implicit $x10, implicit $x11 ... +--- +name: udivrem_i64 +body: | + bb.1.entry: + liveins: $x10, $x11 + + ; CHECK-I-LABEL: name: udivrem_i64 + ; CHECK-I: liveins: $x10, $x11 + ; CHECK-I-NEXT: {{ $}} + ; CHECK-I-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-I-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s64) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s64) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__udivdi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s64) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s64) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__umoddi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-I-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY2]], [[COPY3]] + ; CHECK-I-NEXT: $x10 = COPY [[ADD]](s64) + ; CHECK-I-NEXT: PseudoRET implicit $x10 + ; + ; CHECK-M-LABEL: name: udivrem_i64 + ; CHECK-M: liveins: $x10, $x11 + ; CHECK-M-NEXT: {{ $}} + ; CHECK-M-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-M-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11 + ; CHECK-M-NEXT: [[UDIV:%[0-9]+]]:_(s64) = G_UDIV [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[UREM:%[0-9]+]]:_(s64) = G_UREM [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[UDIV]], [[UREM]] + ; CHECK-M-NEXT: $x10 = COPY [[ADD]](s64) + ; CHECK-M-NEXT: PseudoRET implicit $x10 + %0:_(s64) = COPY $x10 + %1:_(s64) = COPY $x11 + %2:_(s64), %3:_(s64) = G_UDIVREM %0, %1 + %4:_(s64) = G_ADD %2, %3 + $x10 = COPY %4(s64) + PseudoRET implicit $x10 + +... +--- +name: sdivrem_i64 +body: | + bb.1.entry: + liveins: $x10, $x11 + + ; CHECK-I-LABEL: name: sdivrem_i64 + ; CHECK-I: liveins: $x10, $x11 + ; CHECK-I-NEXT: {{ $}} + ; CHECK-I-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-I-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s64) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s64) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__divdi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-I-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: $x10 = COPY [[COPY]](s64) + ; CHECK-I-NEXT: $x11 = COPY [[COPY1]](s64) + ; CHECK-I-NEXT: PseudoCALL target-flags(riscv-call) &__moddi3, csr_ilp32_lp64, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10 + ; CHECK-I-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2 + ; CHECK-I-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-I-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY2]], [[COPY3]] + ; CHECK-I-NEXT: $x10 = COPY [[ADD]](s64) + ; CHECK-I-NEXT: PseudoRET implicit $x10 + ; + ; CHECK-M-LABEL: name: sdivrem_i64 + ; CHECK-M: liveins: $x10, $x11 + ; CHECK-M-NEXT: {{ $}} + ; CHECK-M-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10 + ; CHECK-M-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11 + ; CHECK-M-NEXT: [[SDIV:%[0-9]+]]:_(s64) = G_SDIV [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[SREM:%[0-9]+]]:_(s64) = G_SREM [[COPY]], [[COPY1]] + ; CHECK-M-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[SDIV]], [[SREM]] + ; CHECK-M-NEXT: $x10 = COPY [[ADD]](s64) + ; CHECK-M-NEXT: PseudoRET implicit $x10 + %0:_(s64) = COPY $x10 + %1:_(s64) = COPY $x11 + %2:_(s64), %3:_(s64) = G_SDIVREM %0, %1 + %4:_(s64) = G_ADD %2, %3 + $x10 = COPY %4(s64) + PseudoRET implicit $x10 + +...