Skip to content

Conversation

@woruyu
Copy link
Member

@woruyu woruyu commented Sep 10, 2025

Summary

Try to implemente Lower G_SSUBE in LegalizerHelper::lower

@llvmbot
Copy link
Member

llvmbot commented Sep 10, 2025

@llvm/pr-subscribers-llvm-globalisel

@llvm/pr-subscribers-backend-risc-v

Author: woruyu (woruyu)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/157855.diff

5 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h (+1)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (+24)
  • (modified) llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp (+1-1)
  • (added) llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv32.mir (+171)
  • (added) llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv64.mir (+208)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
index 3be4f82d11bbf..71200c906fe0d 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
@@ -510,6 +510,7 @@ class LegalizerHelper {
   LLVM_ABI LegalizeResult lowerExtract(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerInsert(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerSADDO_SSUBO(MachineInstr &MI);
+  LLVM_ABI LegalizeResult lowerSSUBE(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerAddSubSatToMinMax(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerAddSubSatToAddoSubo(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerShlSat(MachineInstr &MI);
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index a38d305a8bb52..518cb6616a29e 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4447,6 +4447,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
   case TargetOpcode::G_SADDO:
   case TargetOpcode::G_SSUBO:
     return lowerSADDO_SSUBO(MI);
+  case TargetOpcode::G_SSUBE:
+    return lowerSSUBE(MI);
   case TargetOpcode::G_UMULH:
   case TargetOpcode::G_SMULH:
     return lowerSMULH_UMULH(MI);
@@ -9298,6 +9300,28 @@ LegalizerHelper::lowerSADDO_SSUBO(MachineInstr &MI) {
   return Legalized;
 }
 
+LegalizerHelper::LegalizeResult
+LegalizerHelper::lowerSSUBE(MachineInstr &MI) {
+  auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
+  const LLT Ty     = MRI.getType(Res);
+
+  // sum = LHS - (RHS + zext(CarryIn))
+  auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
+  auto RHSp   = MIRBuilder.buildAdd(Ty, RHS, CarryZ);
+  auto Sum    = MIRBuilder.buildSub(Ty, LHS, RHSp);
+  MIRBuilder.buildCopy(Res, Sum);
+
+  // ov = msb( (LHS ^ RHS) & (LHS ^ Sum) )
+  auto X1   = MIRBuilder.buildXor(Ty, LHS, RHS);
+  auto X2   = MIRBuilder.buildXor(Ty, LHS, Sum);
+  auto T    = MIRBuilder.buildAnd(Ty, X1, X2);
+  auto Zero = MIRBuilder.buildConstant(Ty, 0);
+  MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
+
+  MI.eraseFromParent();
+  return Legalized;
+}
+
 LegalizerHelper::LegalizeResult
 LegalizerHelper::lowerAddSubSatToMinMax(MachineInstr &MI) {
   auto [Res, LHS, RHS] = MI.getFirst3Regs();
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index ab5c9e17b9a37..d5354aad74bc3 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -151,7 +151,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
   getActionDefinitionsBuilder(
       {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower();
 
-  getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower();
+  getActionDefinitionsBuilder({G_SADDO, G_SSUBO, G_SSUBE}).minScalar(0, sXLen).lower();
 
   // TODO: Use Vector Single-Width Saturating Instructions for vector types.
   getActionDefinitionsBuilder(
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv32.mir
new file mode 100644
index 0000000000000..894979cc65d6f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv32.mir
@@ -0,0 +1,171 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv32 -run-pass=legalizer %s -o - | FileCheck %s
+
+---
+name:            ssube_i8
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12
+
+    ; CHECK-LABEL: name: ssube_i8
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 24
+    ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY]], [[C]](s32)
+    ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]](s32)
+    ; CHECK-NEXT: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY1]], [[C]](s32)
+    ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]](s32)
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[ASHR]], [[ASHR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C1]]
+    ; CHECK-NEXT: [[SUB1:%[0-9]+]]:_(s32) = G_SUB [[SUB]], [[AND]]
+    ; CHECK-NEXT: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[SUB1]], [[C]](s32)
+    ; CHECK-NEXT: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C]](s32)
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ne), [[SUB1]](s32), [[ASHR2]]
+    ; CHECK-NEXT: $x10 = COPY [[SUB1]](s32)
+    ; CHECK-NEXT: $x11 = COPY [[ICMP]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s32) = COPY $x10
+    %1:_(s8) = G_TRUNC %0(s32)
+    %2:_(s32) = COPY $x11
+    %3:_(s8) = G_TRUNC %2(s32)
+    %4:_(s32) = COPY $x12
+    %5:_(s1) = G_TRUNC %4(s32)
+    %6:_(s8), %7:_(s1) = G_SSUBE %1, %3, %5
+    %8:_(s32) = G_ANYEXT %6(s8)
+    %9:_(s32) = G_ANYEXT %7(s1)
+    $x10 = COPY %8(s32)
+    $x11 = COPY %9(s32)
+    PseudoRET implicit $x10, implicit $x11
+
+...
+---
+name:            ssube_i16
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12
+
+    ; CHECK-LABEL: name: ssube_i16
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+    ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY]], [[C]](s32)
+    ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]](s32)
+    ; CHECK-NEXT: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[COPY1]], [[C]](s32)
+    ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C]](s32)
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[ASHR]], [[ASHR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C1]]
+    ; CHECK-NEXT: [[SUB1:%[0-9]+]]:_(s32) = G_SUB [[SUB]], [[AND]]
+    ; CHECK-NEXT: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[SUB1]], [[C]](s32)
+    ; CHECK-NEXT: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[SHL2]], [[C]](s32)
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ne), [[SUB1]](s32), [[ASHR2]]
+    ; CHECK-NEXT: $x10 = COPY [[SUB1]](s32)
+    ; CHECK-NEXT: $x11 = COPY [[ICMP]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s32) = COPY $x10
+    %1:_(s16) = G_TRUNC %0(s32)
+    %2:_(s32) = COPY $x11
+    %3:_(s16) = G_TRUNC %2(s32)
+    %4:_(s32) = COPY $x12
+    %5:_(s1) = G_TRUNC %4(s32)
+    %6:_(s16), %7:_(s1) = G_SSUBE %1, %3, %5
+    %8:_(s32) = G_ANYEXT %6(s16)
+    %9:_(s32) = G_ANYEXT %7(s1)
+    $x10 = COPY %8(s32)
+    $x11 = COPY %9(s32)
+    PseudoRET implicit $x10, implicit $x11
+
+...
+---
+name:            ssube_i32
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12
+
+    ; CHECK-LABEL: name: ssube_i32
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C]]
+    ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY1]], [[AND]]
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY]], [[ADD]]
+    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY [[SUB]](s32)
+    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s32) = G_XOR [[COPY]], [[COPY1]]
+    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s32) = G_XOR [[COPY]], [[SUB]]
+    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s32) = G_AND [[XOR]], [[XOR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(slt), [[AND1]](s32), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[COPY3]](s32)
+    ; CHECK-NEXT: $x11 = COPY [[ICMP]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s32) = COPY $x10
+    %1:_(s32) = COPY $x11
+    %2:_(s32) = COPY $x12
+    %3:_(s1) = G_TRUNC %2(s32)
+    %4:_(s32), %5:_(s1) = G_SSUBE %0, %1, %3
+    %6:_(s32) = G_ANYEXT %5(s1)
+    $x10 = COPY %4(s32)
+    $x11 = COPY %6(s32)
+    PseudoRET implicit $x10, implicit $x11
+
+...
+---
+name:            ssube_i64
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12, $x13, $x14
+
+    ; CHECK-LABEL: name: ssube_i64
+    ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $x13
+    ; CHECK-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $x14
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY4]], [[C]]
+    ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY2]], [[AND]]
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY]], [[ADD]]
+    ; CHECK-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY [[SUB]](s32)
+    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s32) = G_XOR [[COPY]], [[COPY2]]
+    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s32) = G_XOR [[COPY]], [[SUB]]
+    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s32) = G_AND [[XOR]], [[XOR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(slt), [[AND1]](s32), [[C1]]
+    ; CHECK-NEXT: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[COPY3]], [[ICMP]]
+    ; CHECK-NEXT: [[SUB1:%[0-9]+]]:_(s32) = G_SUB [[COPY1]], [[ADD1]]
+    ; CHECK-NEXT: [[COPY6:%[0-9]+]]:_(s32) = COPY [[SUB1]](s32)
+    ; CHECK-NEXT: [[XOR2:%[0-9]+]]:_(s32) = G_XOR [[COPY1]], [[COPY3]]
+    ; CHECK-NEXT: [[XOR3:%[0-9]+]]:_(s32) = G_XOR [[COPY1]], [[SUB1]]
+    ; CHECK-NEXT: [[AND2:%[0-9]+]]:_(s32) = G_AND [[XOR2]], [[XOR3]]
+    ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(slt), [[AND2]](s32), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[COPY5]](s32)
+    ; CHECK-NEXT: $x11 = COPY [[COPY6]](s32)
+    ; CHECK-NEXT: $x12 = COPY [[ICMP1]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11, implicit $x12
+    %0:_(s32) = COPY $x10
+    %1:_(s32) = COPY $x11
+    %2:_(s32) = COPY $x12
+    %3:_(s32) = COPY $x13
+    %4:_(s32) = COPY $x14
+    %5:_(s1)  = G_TRUNC %4(s32)
+    %6:_(s32), %7:_(s1) = G_SSUBE %0, %2, %5
+    %8:_(s32), %9:_(s1) = G_SSUBE %1, %3, %7
+    %10:_(s32) = G_ANYEXT %9(s1)
+    $x10 = COPY %6(s32)
+    $x11 = COPY %8(s32)
+    $x12 = COPY %10(s32)
+
+    PseudoRET implicit $x10, implicit $x11, implicit $x12
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv64.mir
new file mode 100644
index 0000000000000..93757f0c0c65c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-ssube-rv64.mir
@@ -0,0 +1,208 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=legalizer %s -o - | FileCheck %s
+
+---
+name:            ssube_i8
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12
+
+    ; CHECK-LABEL: name: ssube_i8
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x12
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 56
+    ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[COPY]], [[C]](s64)
+    ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(s64) = G_ASHR [[SHL]], [[C]](s64)
+    ; CHECK-NEXT: [[SHL1:%[0-9]+]]:_(s64) = G_SHL [[COPY1]], [[C]](s64)
+    ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(s64) = G_ASHR [[SHL1]], [[C]](s64)
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB [[ASHR]], [[ASHR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY2]], [[C1]]
+    ; CHECK-NEXT: [[SUB1:%[0-9]+]]:_(s64) = G_SUB [[SUB]], [[AND]]
+    ; CHECK-NEXT: [[SHL2:%[0-9]+]]:_(s64) = G_SHL [[SUB1]], [[C]](s64)
+    ; CHECK-NEXT: [[ASHR2:%[0-9]+]]:_(s64) = G_ASHR [[SHL2]], [[C]](s64)
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(ne), [[SUB1]](s64), [[ASHR2]]
+    ; CHECK-NEXT: $x10 = COPY [[SUB1]](s64)
+    ; CHECK-NEXT: $x11 = COPY [[ICMP]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s64) = COPY $x10
+    %1:_(s8) = G_TRUNC %0(s64)
+    %2:_(s64) = COPY $x11
+    %3:_(s8) = G_TRUNC %2(s64)
+    %4:_(s64) = COPY $x12
+    %5:_(s1) = G_TRUNC %4(s64)
+    %6:_(s8), %7:_(s1) = G_SSUBE %1, %3, %5
+    %8:_(s64) = G_ANYEXT %6(s8)
+    %9:_(s64) = G_ANYEXT %7(s1)
+    $x10 = COPY %8(s64)
+    $x11 = COPY %9(s64)
+    PseudoRET implicit $x10, implicit $x11
+
+...
+---
+name:            ssube_i16
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12
+
+    ; CHECK-LABEL: name: ssube_i16
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x12
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 48
+    ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[COPY]], [[C]](s64)
+    ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(s64) = G_ASHR [[SHL]], [[C]](s64)
+    ; CHECK-NEXT: [[SHL1:%[0-9]+]]:_(s64) = G_SHL [[COPY1]], [[C]](s64)
+    ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(s64) = G_ASHR [[SHL1]], [[C]](s64)
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB [[ASHR]], [[ASHR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY2]], [[C1]]
+    ; CHECK-NEXT: [[SUB1:%[0-9]+]]:_(s64) = G_SUB [[SUB]], [[AND]]
+    ; CHECK-NEXT: [[SHL2:%[0-9]+]]:_(s64) = G_SHL [[SUB1]], [[C]](s64)
+    ; CHECK-NEXT: [[ASHR2:%[0-9]+]]:_(s64) = G_ASHR [[SHL2]], [[C]](s64)
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(ne), [[SUB1]](s64), [[ASHR2]]
+    ; CHECK-NEXT: $x10 = COPY [[SUB1]](s64)
+    ; CHECK-NEXT: $x11 = COPY [[ICMP]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s64) = COPY $x10
+    %1:_(s16) = G_TRUNC %0(s64)
+    %2:_(s64) = COPY $x11
+    %3:_(s16) = G_TRUNC %2(s64)
+    %4:_(s64) = COPY $x12
+    %5:_(s1) = G_TRUNC %4(s64)
+    %6:_(s16), %7:_(s1) = G_SSUBE %1, %3, %5
+    %8:_(s64) = G_ANYEXT %6(s16)
+    %9:_(s64) = G_ANYEXT %7(s1)
+    $x10 = COPY %8(s64)
+    $x11 = COPY %9(s64)
+    PseudoRET implicit $x10, implicit $x11
+
+...
+---
+name:            ssube_i32
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12
+
+    ; CHECK-LABEL: name: ssube_i32
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x12
+    ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(s64) = G_SEXT_INREG [[COPY]], 32
+    ; CHECK-NEXT: [[SEXT_INREG1:%[0-9]+]]:_(s64) = G_SEXT_INREG [[COPY1]], 32
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB [[SEXT_INREG]], [[SEXT_INREG1]]
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY2]], [[C]]
+    ; CHECK-NEXT: [[SUB1:%[0-9]+]]:_(s64) = G_SUB [[SUB]], [[AND]]
+    ; CHECK-NEXT: [[SEXT_INREG2:%[0-9]+]]:_(s64) = G_SEXT_INREG [[SUB1]], 32
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(ne), [[SUB1]](s64), [[SEXT_INREG2]]
+    ; CHECK-NEXT: $x10 = COPY [[SUB1]](s64)
+    ; CHECK-NEXT: $x11 = COPY [[ICMP]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s64) = COPY $x10
+    %1:_(s32) = G_TRUNC %0(s64)
+    %2:_(s64) = COPY $x11
+    %3:_(s32) = G_TRUNC %2(s64)
+    %4:_(s64) = COPY $x12
+    %5:_(s1) = G_TRUNC %4(s64)
+    %6:_(s32), %7:_(s1) = G_SSUBE %1, %3, %5
+    %8:_(s64) = G_ANYEXT %6(s32)
+    %9:_(s64) = G_ANYEXT %7(s1)
+    $x10 = COPY %8(s64)
+    $x11 = COPY %9(s64)
+    PseudoRET implicit $x10, implicit $x11
+
+...
+---
+name:            ssube_i64
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12
+
+    ; CHECK-LABEL: name: ssube_i64
+    ; CHECK: liveins: $x10, $x11, $x12
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x12
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY2]], [[C]]
+    ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY1]], [[AND]]
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB [[COPY]], [[ADD]]
+    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY [[SUB]](s64)
+    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s64) = G_XOR [[COPY]], [[COPY1]]
+    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s64) = G_XOR [[COPY]], [[SUB]]
+    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s64) = G_AND [[XOR]], [[XOR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(slt), [[AND1]](s64), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[COPY3]](s64)
+    ; CHECK-NEXT: $x11 = COPY [[ICMP]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s64) = COPY $x10
+    %1:_(s64) = COPY $x11
+    %2:_(s64) = COPY $x12
+    %3:_(s1) = G_TRUNC %2(s64)
+    %4:_(s64), %5:_(s1) = G_SSUBE %0, %1, %3
+    %6:_(s64) = G_ANYEXT %5(s1)
+    $x10 = COPY %4(s64)
+    $x11 = COPY %6(s64)
+    PseudoRET implicit $x10, implicit $x11
+
+...
+---
+name:            ssube_i128
+body:             |
+  bb.1:
+    liveins: $x10, $x11, $x12, $x13, $x14
+
+    ; CHECK-LABEL: name: ssube_i128
+    ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x12
+    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY $x13
+    ; CHECK-NEXT: [[COPY4:%[0-9]+]]:_(s64) = COPY $x14
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY4]], [[C]]
+    ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY2]], [[AND]]
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB [[COPY]], [[ADD]]
+    ; CHECK-NEXT: [[COPY5:%[0-9]+]]:_(s64) = COPY [[SUB]](s64)
+    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s64) = G_XOR [[COPY]], [[COPY2]]
+    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s64) = G_XOR [[COPY]], [[SUB]]
+    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s64) = G_AND [[XOR]], [[XOR1]]
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(slt), [[AND1]](s64), [[C1]]
+    ; CHECK-NEXT: [[ADD1:%[0-9]+]]:_(s64) = G_ADD [[COPY3]], [[ICMP]]
+    ; CHECK-NEXT: [[SUB1:%[0-9]+]]:_(s64) = G_SUB [[COPY1]], [[ADD1]]
+    ; CHECK-NEXT: [[COPY6:%[0-9]+]]:_(s64) = COPY [[SUB1]](s64)
+    ; CHECK-NEXT: [[XOR2:%[0-9]+]]:_(s64) = G_XOR [[COPY1]], [[COPY3]]
+    ; CHECK-NEXT: [[XOR3:%[0-9]+]]:_(s64) = G_XOR [[COPY1]], [[SUB1]]
+    ; CHECK-NEXT: [[AND2:%[0-9]+]]:_(s64) = G_AND [[XOR2]], [[XOR3]]
+    ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(s64) = G_ICMP intpred(slt), [[AND2]](s64), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[COPY5]](s64)
+    ; CHECK-NEXT: $x11 = COPY [[COPY6]](s64)
+    ; CHECK-NEXT: $x12 = COPY [[ICMP1]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11, implicit $x12
+    %0:_(s64) = COPY $x10
+    %1:_(s64) = COPY $x11
+    %2:_(s64) = COPY $x12
+    %3:_(s64) = COPY $x13
+    %4:_(s64) = COPY $x14
+    %5:_(s1)  = G_TRUNC %4(s64)
+    %6:_(s64), %7:_(s1) = G_SSUBE %0, %2, %5
+    %8:_(s64), %9:_(s1) = G_SSUBE %1, %3, %7
+    %10:_(s64) = G_ANYEXT %9(s1)
+    $x10 = COPY %6(s64)
+    $x11 = COPY %8(s64)
+    $x12 = COPY %10(s64)
+
+    PseudoRET implicit $x10, implicit $x11, implicit $x12
+...

@github-actions
Copy link

github-actions bot commented Sep 10, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@woruyu woruyu force-pushed the feat/add-global-isel-for-G_SSUBE branch from 21939aa to 478d5c8 Compare September 11, 2025 02:21
@woruyu
Copy link
Member Author

woruyu commented Sep 11, 2025

By the way, @topperc , RISCV enables lowering for G_USUBE via getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower() , but there’s no corresponding legalizer test.
I think:(1) a small PR adding G_USUBE tests;(2) a follow-up PR that merges G_UADDE, G_USUBE, G_SADDE, G_SSUBE tests into a single file.
First PR adds coverage; second is a mechanical cleanup. Is it a good idea?

@topperc
Copy link
Collaborator

topperc commented Sep 11, 2025

By the way, @topperc , RISCV enables lowering for G_USUBE via getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower() , but there’s no corresponding legalizer test. I think:(1) a small PR adding G_USUBE tests;(2) a follow-up PR that merges G_UADDE, G_USUBE, G_SADDE, G_SSUBE tests into a single file. First PR adds coverage; second is a mechanical cleanup. Is it a good idea?

I don't think we need legalizer tests for every instruction. If we have IR tests that cover it that's probably enough. We probably have too many legalizer tests.

@woruyu woruyu self-assigned this Sep 11, 2025
@woruyu woruyu requested a review from topperc September 12, 2025 10:06
@woruyu woruyu force-pushed the feat/add-global-isel-for-G_SSUBE branch from 478d5c8 to fc123e1 Compare September 17, 2025 09:20
Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@woruyu woruyu merged commit 1a172b9 into llvm:main Sep 18, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants