[GlobalISel][X86] Add handling of scalar G_USUBE opcodes
authorSimon Pilgrim <llvm-dev@redking.me.uk>
Fri, 16 Jun 2023 12:31:50 +0000 (13:31 +0100)
committerSimon Pilgrim <llvm-dev@redking.me.uk>
Fri, 16 Jun 2023 12:31:50 +0000 (13:31 +0100)
Extend the G_UADDE handling to also support G_USUBE

llvm/lib/Target/X86/X86InstructionSelector.cpp
llvm/lib/Target/X86/X86LegalizerInfo.cpp
llvm/test/CodeGen/X86/GlobalISel/legalize-leading-zeros.mir
llvm/test/CodeGen/X86/GlobalISel/legalize-sub.mir

index 0dbd9ca..7116295 100644 (file)
@@ -92,7 +92,7 @@ private:
                  MachineFunction &MF) const;
   bool selectFCmp(MachineInstr &I, MachineRegisterInfo &MRI,
                   MachineFunction &MF) const;
-  bool selectUadde(MachineInstr &I, MachineRegisterInfo &MRI,
+  bool selectUAddSubE(MachineInstr &I, MachineRegisterInfo &MRI,
                    MachineFunction &MF) const;
   bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI) const;
   bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
@@ -403,7 +403,8 @@ bool X86InstructionSelector::select(MachineInstr &I) {
   case TargetOpcode::G_FCMP:
     return selectFCmp(I, MRI, MF);
   case TargetOpcode::G_UADDE:
-    return selectUadde(I, MRI, MF);
+  case TargetOpcode::G_USUBE:
+    return selectUAddSubE(I, MRI, MF);
   case TargetOpcode::G_UNMERGE_VALUES:
     return selectUnmergeValues(I, MRI, MF);
   case TargetOpcode::G_MERGE_VALUES:
@@ -1069,41 +1070,52 @@ bool X86InstructionSelector::selectFCmp(MachineInstr &I,
   return true;
 }
 
-bool X86InstructionSelector::selectUadde(MachineInstr &I,
+bool X86InstructionSelector::selectUAddSubE(MachineInstr &I,
                                          MachineRegisterInfo &MRI,
                                          MachineFunction &MF) const {
-  assert((I.getOpcode() == TargetOpcode::G_UADDE) && "unexpected instruction");
+  assert((I.getOpcode() == TargetOpcode::G_UADDE ||
+          I.getOpcode() == TargetOpcode::G_USUBE) &&
+         "unexpected instruction");
 
   const Register DstReg = I.getOperand(0).getReg();
   const Register CarryOutReg = I.getOperand(1).getReg();
   const Register Op0Reg = I.getOperand(2).getReg();
   const Register Op1Reg = I.getOperand(3).getReg();
   Register CarryInReg = I.getOperand(4).getReg();
+  bool IsSub = I.getOpcode() == TargetOpcode::G_USUBE;
 
   const LLT DstTy = MRI.getType(DstReg);
   assert(DstTy.isScalar() && "G_UADDE only supported for scalar types");
 
   // TODO: Handle immediate argument variants?
-  unsigned OpADC, OpADD;
+  unsigned OpADC, OpADD, OpSBB, OpSUB;
   switch (DstTy.getSizeInBits()) {
   case 8:
     OpADC = X86::ADC8rr;
     OpADD = X86::ADD8rr;
+    OpSBB = X86::SBB8rr;
+    OpSUB = X86::SUB8rr;
     break;
   case 16:
     OpADC = X86::ADC16rr;
     OpADD = X86::ADD16rr;
+    OpSBB = X86::SBB16rr;
+    OpSUB = X86::SUB16rr;
     break;
   case 32:
     OpADC = X86::ADC32rr;
     OpADD = X86::ADD32rr;
+    OpSBB = X86::SBB32rr;
+    OpSUB = X86::SUB32rr;
     break;
   case 64:
     OpADC = X86::ADC64rr;
     OpADD = X86::ADD64rr;
+    OpSBB = X86::SBB64rr;
+    OpSUB = X86::SUB64rr;
     break;
   default:
-    llvm_unreachable("Can't select G_UADDE, unsupported type.");
+    llvm_unreachable("Can't select G_UADDE/G_USUBE, unsupported type.");
   }
 
   const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
@@ -1117,8 +1129,8 @@ bool X86InstructionSelector::selectUadde(MachineInstr &I,
   }
 
   unsigned Opcode = 0;
-  if (Def->getOpcode() == TargetOpcode::G_UADDE) {
-    // carry set by prev ADD.
+  if (Def->getOpcode() == I.getOpcode()) {
+    // carry set by prev ADD/SUB.
 
     BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), X86::EFLAGS)
         .addReg(CarryInReg);
@@ -1126,17 +1138,17 @@ bool X86InstructionSelector::selectUadde(MachineInstr &I,
     if (!RBI.constrainGenericRegister(CarryInReg, *DstRC, MRI))
       return false;
 
-    Opcode = OpADC;
+    Opcode = IsSub ? OpSBB : OpADC;
   } else if (auto val = getIConstantVRegVal(CarryInReg, MRI)) {
     // carry is constant, support only 0.
     if (*val != 0)
       return false;
 
-    Opcode = OpADD;
+    Opcode = IsSub ? OpSUB : OpADD;
   } else
     return false;
 
-  MachineInstr &AddInst =
+  MachineInstr &Inst =
       *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode), DstReg)
            .addReg(Op0Reg)
            .addReg(Op1Reg);
@@ -1144,7 +1156,7 @@ bool X86InstructionSelector::selectUadde(MachineInstr &I,
   BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), CarryOutReg)
       .addReg(X86::EFLAGS);
 
-  if (!constrainSelectedInstRegOperands(AddInst, TII, TRI, RBI) ||
+  if (!constrainSelectedInstRegOperands(Inst, TII, TRI, RBI) ||
       !RBI.constrainGenericRegister(CarryOutReg, *DstRC, MRI))
     return false;
 
index cf49d7c..406c9d4 100644 (file)
@@ -148,8 +148,8 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
       .clampScalar(0, s8, sMaxScalar)
       .scalarize(0);
 
-  // TODO: Add G_UADDO/G_USUBO/G_USUBE handling
-  getActionDefinitionsBuilder(G_UADDE)
+  // TODO: Add G_UADDO/G_USUBO handling
+  getActionDefinitionsBuilder({G_UADDE, G_USUBE})
       .legalIf([=](const LegalityQuery &Query) -> bool {
         return typePairInSet(0, 1, {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
                (Is64Bit && typePairInSet(0, 1, {{s64, s1}})(Query));
index 18052c6..5a0b341 100644 (file)
@@ -3,7 +3,7 @@
 # RUN: llc -mtriple=i386-linux-gnu -mattr=+lzcnt -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), %15:_(s1) = G_USUBE %9:_, %11:_, %13:_ (in function: test_ctlz35)
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %12:_(s32), %13:_(s1) = G_USUBO %8:_, %10:_ (in function: test_ctlz35)
 # ERR32: remark: <unknown>:0:0: unable to legalize instruction: %10:_(s64) = G_CTLZ_ZERO_UNDEF %4:_(s32) (in function: test_ctlz64)
 
 # test count leading zeros for s16, s32, and s64
index eeb89eb..1a14ab9 100644 (file)
@@ -5,11 +5,11 @@
 # 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,X32
 # RUN: FileCheck -check-prefix=ERR32  %s < %t
 
-# ERR64: remark: <unknown>:0:0: unable to legalize instruction: %11:_(s64), %12:_(s1) = G_USUBE %6:_, %8:_, %10:_ (in function: test_sub_i128)
+# ERR64: remark: <unknown>:0:0: unable to legalize instruction: %9:_(s64), %10:_(s1) = G_USUBO %5:_, %7:_ (in function: test_sub_i128)
 
-# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %13:_(s32), %14:_(s1) = G_USUBE %8:_, %10:_, %12:_ (in function: test_sub_i42)
-# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %9:_(s32), %10:_(s1) = G_USUBE %4:_, %6:_, %8:_ (in function: test_sub_i64)
-# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %19:_(s32), %20:_(s1) = G_USUBE %8:_, %12:_, %18:_ (in function: test_sub_i128)
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %11:_(s32), %12:_(s1) = G_USUBO %7:_, %9:_ (in function: test_sub_i42)
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %7:_(s32), %8:_(s1) = G_USUBO %3:_, %5:_ (in function: test_sub_i64)
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %13:_(s32), %14:_(s1) = G_USUBO %5:_, %9:_ (in function: test_sub_i128)
 
 --- |