[llvm] [GlobalISel][ARM] Support missing case for G_CONSTANT (PR #79022)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 22 09:46:27 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel

@llvm/pr-subscribers-backend-arm

Author: Serge Pavlov (spavloff)

<details>
<summary>Changes</summary>

The instruction:

    %0:gprb(s32) = G_CONSTANT i32 -1

now cannot be selected on ARM. In DAG selector the similar instruction is selected with the help of `mod_imm_not`, which is a PatLeaf node. This node is specified with a transformation helper (imm_not_XFORM), that creates a new SDValue. Such rules are not processed by TableGen now and the generated match table does not contain records that could be used to select such instruction.

This change implements selection for this case.

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


2 Files Affected:

- (modified) llvm/lib/Target/ARM/ARMInstructionSelector.cpp (+49-22) 
- (added) llvm/test/CodeGen/ARM/GlobalISel/select-imm.mir (+25) 


``````````diff
diff --git a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp
index f391058a70514c..f4c5513d857b58 100644
--- a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp
+++ b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp
@@ -60,6 +60,7 @@ class ARMInstructionSelector : public InstructionSelector {
   bool selectGlobal(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const;
   bool selectSelect(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const;
   bool selectShift(unsigned ShiftOpc, MachineInstrBuilder &MIB) const;
+  bool selectConstant(MachineInstrBuilder &MIB) const;
 
   // Check if the types match and both operands have the expected size and
   // register bank.
@@ -810,6 +811,31 @@ bool ARMInstructionSelector::selectShift(unsigned ShiftOpc,
   return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
 }
 
+bool ARMInstructionSelector::selectConstant(MachineInstrBuilder &MIB) const {
+  MachineInstr &MI = *MIB;
+  assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && "Expected G_CONSTANT");
+
+  auto &Val = MI.getOperand(1);
+  uint32_t ImmValue;
+  if (Val.isImm())
+    ImmValue = Val.getImm();
+  else if (Val.isCImm())
+    ImmValue = Val.getCImm()->getZExtValue();
+  else
+    return false;
+
+  // Process nodes didn't handled by TableGen-based selector.
+  if (!STI.isThumb()) {
+    if (int Imm12 = ARM_AM::getSOImmVal(~ImmValue); Imm12 != -1) {
+      MI.setDesc(TII.get(ARM::MVNi));
+      Val.ChangeToImmediate(Imm12);
+      MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
+      return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
+    }
+  }
+  return false;
+}
+
 void ARMInstructionSelector::renderVFPF32Imm(
   MachineInstrBuilder &NewInstBuilder, const MachineInstr &OldInst,
   int OpIdx) const {
@@ -958,33 +984,34 @@ bool ARMInstructionSelector::select(MachineInstr &I) {
     I.setDesc(TII.get(COPY));
     return selectCopy(I, TII, MRI, TRI, RBI);
   }
-  case G_CONSTANT: {
-    if (!MRI.getType(I.getOperand(0).getReg()).isPointer()) {
-      // Non-pointer constants should be handled by TableGen.
-      LLVM_DEBUG(dbgs() << "Unsupported constant type\n");
-      return false;
-    }
-
-    auto &Val = I.getOperand(1);
-    if (Val.isCImm()) {
-      if (!Val.getCImm()->isZero()) {
-        LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");
+  case G_CONSTANT:
+    if (!selectConstant(MIB)) {
+      auto &Val = MIB->getOperand(1);
+      if (!MRI.getType(I.getOperand(0).getReg()).isPointer()) {
+        // Non-pointer constants should be handled by TableGen.
+        LLVM_DEBUG(dbgs() << "Unsupported constant type\n");
         return false;
       }
-      Val.ChangeToImmediate(0);
-    } else {
-      assert(Val.isImm() && "Unexpected operand for G_CONSTANT");
-      if (Val.getImm() != 0) {
-        LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");
-        return false;
+
+      if (Val.isCImm()) {
+        if (!Val.getCImm()->isZero()) {
+          LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");
+          return false;
+        }
+        Val.ChangeToImmediate(0);
+      } else {
+        assert(Val.isImm() && "Unexpected operand for G_CONSTANT");
+        if (Val.getImm() != 0) {
+          LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");
+          return false;
+        }
       }
-    }
 
-    assert(!STI.isThumb() && "Unsupported subtarget");
-    I.setDesc(TII.get(ARM::MOVi));
-    MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
+      assert(!STI.isThumb() && "Unsupported subtarget");
+      I.setDesc(TII.get(ARM::MOVi));
+      MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
+    }
     break;
-  }
   case G_FCONSTANT: {
     // Load from constant pool
     unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits() / 8;
diff --git a/llvm/test/CodeGen/ARM/GlobalISel/select-imm.mir b/llvm/test/CodeGen/ARM/GlobalISel/select-imm.mir
new file mode 100644
index 00000000000000..59e983bb8c46b9
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/GlobalISel/select-imm.mir
@@ -0,0 +1,25 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 4
+# RUN: llc -mtriple arm-- -mattr=+v6 -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
+
+---
+name:            get_const_01
+legalized:       true
+regBankSelected: true
+selected:        false
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gprb }
+body:             |
+  bb.0:
+    liveins: $r0
+    ; CHECK-LABEL: name: get_const_01
+    ; CHECK: liveins: $r0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[MVNi:%[0-9]+]]:gpr = MVNi 0, 14 /* CC::al */, $noreg, $noreg
+    ; CHECK-NEXT: $r0 = COPY [[MVNi]]
+    ; CHECK-NEXT: MOVPCLR 14 /* CC::al */, $noreg, implicit $r0
+    %0:gprb(s32) = G_CONSTANT i32 -1
+    $r0 = COPY %0(s32)
+    MOVPCLR 14 /* CC::al */, $noreg, implicit $r0
+
+...

``````````

</details>


https://github.com/llvm/llvm-project/pull/79022


More information about the llvm-commits mailing list