]> granicus.if.org Git - llvm/commitdiff
[GlobalISel][Utils] Add a getConstantVRegVal variant that looks through instrs
authorQuentin Colombet <quentin.colombet@gmail.com>
Thu, 14 Mar 2019 01:37:13 +0000 (01:37 +0000)
committerQuentin Colombet <quentin.colombet@gmail.com>
Thu, 14 Mar 2019 01:37:13 +0000 (01:37 +0000)
getConstantVRegVal used to only look for G_CONSTANT when looking at
unboxing the value of a vreg. However, constants are sometimes not
directly used and are hidden behind trunc, s|zext or copy chain of
computation.

In particular this may be introduced by the legalization process that
doesn't want to simplify these patterns because it can lead to infine
loop when legalizing a constant.

To circumvent that problem, add a new variant of getConstantVRegVal,
named getConstantVRegValWithLookThrough, that allow to look through
extensions.

Differential Revision: https://reviews.llvm.org/D59227

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356116 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/GlobalISel/Utils.h
lib/CodeGen/GlobalISel/InstructionSelector.cpp
lib/CodeGen/GlobalISel/Utils.cpp
test/CodeGen/Mips/GlobalISel/llvm-ir/select.ll
test/CodeGen/X86/GlobalISel/ashr-scalar.ll
test/CodeGen/X86/GlobalISel/lshr-scalar.ll
test/CodeGen/X86/GlobalISel/shl-scalar.ll

index dd14a0cf87ee32fcd4647e145911ad41175965f4..4e3a24c7b111a30b5854f1736863135bc1eb5a03 100644 (file)
@@ -89,8 +89,25 @@ void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
                         const char *PassName, StringRef Msg,
                         const MachineInstr &MI);
 
+/// If \p VReg is defined by a G_CONSTANT fits in int64_t
+/// returns it.
 Optional<int64_t> getConstantVRegVal(unsigned VReg,
                                      const MachineRegisterInfo &MRI);
+/// Simple struct used to hold a constant integer value and a virtual
+/// register.
+struct ValueAndVReg {
+  int64_t Value;
+  unsigned VReg;
+};
+/// If \p VReg is defined by a statically evaluable chain of
+/// instructions rooted on a G_CONSTANT (\p LookThroughInstrs == true)
+/// and that constant fits in int64_t, returns its value as well as
+/// the virtual register defined by this G_CONSTANT.
+/// When \p LookThroughInstrs == false, this function behaves like
+/// getConstantVRegVal.
+Optional<ValueAndVReg>
+getConstantVRegValWithLookThrough(unsigned VReg, const MachineRegisterInfo &MRI,
+                                  bool LookThroughInstrs = true);
 const ConstantFP* getConstantFPVRegVal(unsigned VReg,
                                        const MachineRegisterInfo &MRI);
 
index d8cd71f64b9c0d803d31996689a70ee04f184b3a..a449e9dec41be67b16d52be3836d70090ec09b78 100644 (file)
@@ -49,8 +49,8 @@ bool InstructionSelector::isOperandImmEqual(
     const MachineOperand &MO, int64_t Value,
     const MachineRegisterInfo &MRI) const {
   if (MO.isReg() && MO.getReg())
-    if (auto VRegVal = getConstantVRegVal(MO.getReg(), MRI))
-      return *VRegVal == Value;
+    if (auto VRegVal = getConstantVRegValWithLookThrough(MO.getReg(), MRI))
+      return VRegVal->Value == Value;
   return false;
 }
 
index 237d892c7f70cb4e5d24026adf3d01b7a7d2615e..d65328be39c0b477e99963814505cd84af3e3e99 100644 (file)
@@ -183,18 +183,68 @@ void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
 
 Optional<int64_t> llvm::getConstantVRegVal(unsigned VReg,
                                            const MachineRegisterInfo &MRI) {
-  MachineInstr *MI = MRI.getVRegDef(VReg);
-  if (MI->getOpcode() != TargetOpcode::G_CONSTANT)
+  Optional<ValueAndVReg> ValAndVReg =
+      getConstantVRegValWithLookThrough(VReg, MRI, /*LookThroughInstrs*/ false);
+  assert((!ValAndVReg || ValAndVReg->VReg == VReg) &&
+         "Value found while looking through instrs");
+  if (!ValAndVReg)
+    return None;
+  return ValAndVReg->Value;
+}
+
+Optional<ValueAndVReg> llvm::getConstantVRegValWithLookThrough(
+    unsigned VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) {
+  SmallVector<std::pair<unsigned, unsigned>, 4> SeenOpcodes;
+  MachineInstr *MI;
+  while ((MI = MRI.getVRegDef(VReg)) &&
+         MI->getOpcode() != TargetOpcode::G_CONSTANT && LookThroughInstrs) {
+    switch (MI->getOpcode()) {
+    case TargetOpcode::G_TRUNC:
+    case TargetOpcode::G_SEXT:
+    case TargetOpcode::G_ZEXT:
+      SeenOpcodes.push_back(std::make_pair(
+          MI->getOpcode(),
+          MRI.getType(MI->getOperand(0).getReg()).getSizeInBits()));
+      VReg = MI->getOperand(1).getReg();
+      break;
+    case TargetOpcode::COPY:
+      VReg = MI->getOperand(1).getReg();
+      if (TargetRegisterInfo::isPhysicalRegister(VReg))
+        return None;
+      break;
+    default:
+      return None;
+    }
+  }
+  if (!MI || MI->getOpcode() != TargetOpcode::G_CONSTANT ||
+      (!MI->getOperand(1).isImm() && !MI->getOperand(1).isCImm()))
     return None;
 
-  if (MI->getOperand(1).isImm())
-    return MI->getOperand(1).getImm();
+  const MachineOperand &CstVal = MI->getOperand(1);
+  unsigned BitWidth = MRI.getType(MI->getOperand(0).getReg()).getSizeInBits();
+  APInt Val = CstVal.isImm() ? APInt(BitWidth, CstVal.getImm())
+                             : CstVal.getCImm()->getValue();
+  assert(Val.getBitWidth() == BitWidth &&
+         "Value bitwidth doesn't match definition type");
+  while (!SeenOpcodes.empty()) {
+    std::pair<unsigned, unsigned> OpcodeAndSize = SeenOpcodes.pop_back_val();
+    switch (OpcodeAndSize.first) {
+    case TargetOpcode::G_TRUNC:
+      Val = Val.trunc(OpcodeAndSize.second);
+      break;
+    case TargetOpcode::G_SEXT:
+      Val = Val.sext(OpcodeAndSize.second);
+      break;
+    case TargetOpcode::G_ZEXT:
+      Val = Val.zext(OpcodeAndSize.second);
+      break;
+    }
+  }
 
-  if (MI->getOperand(1).isCImm() &&
-      MI->getOperand(1).getCImm()->getBitWidth() <= 64)
-    return MI->getOperand(1).getCImm()->getSExtValue();
+  if (Val.getBitWidth() > 64)
+    return None;
 
-  return None;
+  return ValueAndVReg{Val.getSExtValue(), VReg};
 }
 
 const llvm::ConstantFP* llvm::getConstantFPVRegVal(unsigned VReg,
index f15977cf6b78bdfea3565e354b7af0f353029db0..2753fe157a532c4a6c666d69132a1cd1ec0f2445 100644 (file)
@@ -64,14 +64,12 @@ entry:
 define i32 @select_with_negation(i32 %a, i32 %b, i32 %x, i32 %y) {
 ; MIPS32-LABEL: select_with_negation:
 ; MIPS32:       # %bb.0: # %entry
-; MIPS32-NEXT:    lui $1, 65535
-; MIPS32-NEXT:    ori $1, $1, 65535
 ; MIPS32-NEXT:    slt $4, $4, $5
-; MIPS32-NEXT:    xor $1, $4, $1
-; MIPS32-NEXT:    lui $4, 0
-; MIPS32-NEXT:    ori $4, $4, 1
-; MIPS32-NEXT:    and $1, $1, $4
-; MIPS32-NEXT:    movn $7, $6, $1
+; MIPS32-NEXT:    not $4, $4
+; MIPS32-NEXT:    lui $5, 0
+; MIPS32-NEXT:    ori $5, $5, 1
+; MIPS32-NEXT:    and $4, $4, $5
+; MIPS32-NEXT:    movn $7, $6, $4
 ; MIPS32-NEXT:    move $2, $7
 ; MIPS32-NEXT:    jr $ra
 ; MIPS32-NEXT:    nop
index a8496bf02cfaf1dde91901c9b8334a2d0835a4b0..9db8b8e347905b20325810e9fdde7f07201fc4a9 100644 (file)
@@ -28,8 +28,7 @@ define i64 @test_ashr_i64_imm1(i64 %arg1) {
 ; X64-LABEL: test_ashr_i64_imm1:
 ; X64:       # %bb.0:
 ; X64-NEXT:    movq %rdi, %rax
-; X64-NEXT:    movq $1, %rcx
-; X64-NEXT:    sarq %cl, %rax
+; X64-NEXT:    sarq %rax
 ; X64-NEXT:    retq
   %res = ashr i64 %arg1, 1
   ret i64 %res
@@ -62,8 +61,7 @@ define i32 @test_ashr_i32_imm1(i32 %arg1) {
 ; X64-LABEL: test_ashr_i32_imm1:
 ; X64:       # %bb.0:
 ; X64-NEXT:    movl %edi, %eax
-; X64-NEXT:    movl $1, %ecx
-; X64-NEXT:    sarl %cl, %eax
+; X64-NEXT:    sarl %eax
 ; X64-NEXT:    retq
   %res = ashr i32 %arg1, 1
   ret i32 %res
@@ -101,8 +99,7 @@ define i16 @test_ashr_i16_imm1(i32 %arg1) {
 ; X64-LABEL: test_ashr_i16_imm1:
 ; X64:       # %bb.0:
 ; X64-NEXT:    movl %edi, %eax
-; X64-NEXT:    movw $1, %cx
-; X64-NEXT:    sarw %cl, %ax
+; X64-NEXT:    sarw %ax
 ; X64-NEXT:    # kill: def $ax killed $ax killed $eax
 ; X64-NEXT:    retq
   %a = trunc i32 %arg1 to i16
index 9df4c1a4e800e1ed92f8ac9c831c0210947270ca..ef51cb8cbffee73d9c592a3ed9c697593600101c 100644 (file)
@@ -28,8 +28,7 @@ define i64 @test_lshr_i64_imm1(i64 %arg1) {
 ; X64-LABEL: test_lshr_i64_imm1:
 ; X64:       # %bb.0:
 ; X64-NEXT:    movq %rdi, %rax
-; X64-NEXT:    movq $1, %rcx
-; X64-NEXT:    shrq %cl, %rax
+; X64-NEXT:    shrq %rax
 ; X64-NEXT:    retq
   %res = lshr i64 %arg1, 1
   ret i64 %res
@@ -62,8 +61,7 @@ define i32 @test_lshr_i32_imm1(i32 %arg1) {
 ; X64-LABEL: test_lshr_i32_imm1:
 ; X64:       # %bb.0:
 ; X64-NEXT:    movl %edi, %eax
-; X64-NEXT:    movl $1, %ecx
-; X64-NEXT:    shrl %cl, %eax
+; X64-NEXT:    shrl %eax
 ; X64-NEXT:    retq
   %res = lshr i32 %arg1, 1
   ret i32 %res
@@ -101,8 +99,7 @@ define i16 @test_lshr_i16_imm1(i32 %arg1) {
 ; X64-LABEL: test_lshr_i16_imm1:
 ; X64:       # %bb.0:
 ; X64-NEXT:    movl %edi, %eax
-; X64-NEXT:    movw $1, %cx
-; X64-NEXT:    shrw %cl, %ax
+; X64-NEXT:    shrw %ax
 ; X64-NEXT:    # kill: def $ax killed $ax killed $eax
 ; X64-NEXT:    retq
   %a = trunc i32 %arg1 to i16
index e6625c9226e658d92159441f7c8a2bc5f1e7ab96..e7e134ba2cc23cfbc33a39b3657439332d114e09 100644 (file)
@@ -27,9 +27,7 @@ define i64 @test_shl_i64_imm(i64 %arg1) {
 define i64 @test_shl_i64_imm1(i64 %arg1) {
 ; X64-LABEL: test_shl_i64_imm1:
 ; X64:       # %bb.0:
-; X64-NEXT:    movq %rdi, %rax
-; X64-NEXT:    movq $1, %rcx
-; X64-NEXT:    shlq %cl, %rax
+; X64-NEXT:    leaq (%rdi,%rdi), %rax
 ; X64-NEXT:    retq
   %res = shl i64 %arg1, 1
   ret i64 %res
@@ -61,9 +59,8 @@ define i32 @test_shl_i32_imm(i32 %arg1) {
 define i32 @test_shl_i32_imm1(i32 %arg1) {
 ; X64-LABEL: test_shl_i32_imm1:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl %edi, %eax
-; X64-NEXT:    movl $1, %ecx
-; X64-NEXT:    shll %cl, %eax
+; X64-NEXT:    # kill: def $edi killed $edi def $rdi
+; X64-NEXT:    leal (%rdi,%rdi), %eax
 ; X64-NEXT:    retq
   %res = shl i32 %arg1, 1
   ret i32 %res
@@ -100,9 +97,8 @@ define i16 @test_shl_i16_imm(i32 %arg1) {
 define i16 @test_shl_i16_imm1(i32 %arg1) {
 ; X64-LABEL: test_shl_i16_imm1:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl %edi, %eax
-; X64-NEXT:    movw $1, %cx
-; X64-NEXT:    shlw %cl, %ax
+; X64-NEXT:    # kill: def $edi killed $edi def $rdi
+; X64-NEXT:    leal (%rdi,%rdi), %eax
 ; X64-NEXT:    # kill: def $ax killed $ax killed $eax
 ; X64-NEXT:    retq
   %a = trunc i32 %arg1 to i16