[llvm] r294247 - GlobalISel: legalize G_INSERT instructions

Tim Northover via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 6 13:56:48 PST 2017


Author: tnorthover
Date: Mon Feb  6 15:56:47 2017
New Revision: 294247

URL: http://llvm.org/viewvc/llvm-project?rev=294247&view=rev
Log:
GlobalISel: legalize G_INSERT instructions

We don't handle all cases yet (see arm64-fallback.ll for an example), but this
is enough to cover most common C++ code so it's a good place to start.

Added:
    llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir
Modified:
    llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
    llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
    llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
    llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp
    llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll

Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h?rev=294247&r1=294246&r2=294247&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h Mon Feb  6 15:56:47 2017
@@ -95,6 +95,15 @@ private:
   void extractParts(unsigned Reg, LLT Ty, int NumParts,
                     SmallVectorImpl<unsigned> &Ops);
 
+  /// Set \p CurOp and \p EndOp to the range of G_INSERT operands that fall
+  /// inside the bit-range specified by \DstStart and \p DstEnd. Assumes \p
+  /// CurOp is initially pointing at one of the (Reg, Offset) pairs in \p MI (or
+  /// at the end), which should be a G_INSERT instruction.
+  void findInsertionsForRange(int64_t DstStart, int64_t DstEnd,
+                              MachineInstr::mop_iterator &CurOp,
+                              MachineInstr::mop_iterator &EndOp,
+                              MachineInstr &MI);
+
   MachineIRBuilder MIRBuilder;
   MachineRegisterInfo &MRI;
 };

Modified: llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp?rev=294247&r1=294246&r2=294247&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp Mon Feb  6 15:56:47 2017
@@ -119,6 +119,17 @@ LegalizerHelper::libcall(MachineInstr &M
   }
 }
 
+void LegalizerHelper::findInsertionsForRange(
+    int64_t DstStart, int64_t DstEnd, MachineInstr::mop_iterator &CurOp,
+    MachineInstr::mop_iterator &EndOp, MachineInstr &MI) {
+  while (CurOp != MI.operands_end() && std::next(CurOp)->getImm() < DstStart)
+    CurOp += 2;
+
+  EndOp = CurOp;
+  while (EndOp != MI.operands_end() && std::next(EndOp)->getImm() < DstEnd)
+    EndOp += 2;
+}
+
 LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
                                                               unsigned TypeIdx,
                                                               LLT NarrowTy) {
@@ -161,6 +172,65 @@ LegalizerHelper::LegalizeResult Legalize
     MI.eraseFromParent();
     return Legalized;
   }
+  case TargetOpcode::G_INSERT: {
+    if (TypeIdx != 0)
+      return UnableToLegalize;
+
+    unsigned NarrowSize = NarrowTy.getSizeInBits();
+    int NumParts =
+        MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize;
+
+    SmallVector<unsigned, 2> SrcRegs, DstRegs;
+    SmallVector<uint64_t, 2> Indexes;
+    extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
+
+    MachineInstr::mop_iterator CurOp = MI.operands_begin() + 2, EndOp;
+    for (int i = 0; i < NumParts; ++i) {
+      unsigned DstStart = i * NarrowSize;
+      unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
+      Indexes.push_back(DstStart);
+
+      findInsertionsForRange(DstStart, DstStart + NarrowSize, CurOp, EndOp, MI);
+
+      if (CurOp == EndOp) {
+        // No part of the insert affects this subregister, forward the original.
+        DstRegs.push_back(SrcRegs[i]);
+        continue;
+      } else if (MRI.getType(CurOp->getReg()) == NarrowTy &&
+                 std::next(CurOp)->getImm() == DstStart) {
+        // The entire subregister is defined by this insert, forward the new
+        // value.
+        DstRegs.push_back(CurOp->getReg());
+        continue;
+      }
+
+      auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_INSERT)
+        .addDef(DstReg)
+        .addUse(SrcRegs[i]);
+
+      for (; CurOp != EndOp; CurOp += 2) {
+        unsigned Reg = CurOp->getReg();
+        uint64_t Offset = std::next(CurOp)->getImm() - DstStart;
+
+        // Make sure we don't have a cross-register insert.
+        if (Offset + MRI.getType(Reg).getSizeInBits() > NarrowSize) {
+          // FIXME: we should handle this case, though it's unlikely to be
+          // common given ABI-related layout restrictions.
+          return UnableToLegalize;
+        }
+
+        MIB.addUse(Reg);
+        MIB.addImm(Offset);
+      }
+
+      DstRegs.push_back(DstReg);
+    }
+
+    assert(DstRegs.size() == (unsigned)NumParts && "not all parts covered");
+    MIRBuilder.buildSequence(MI.getOperand(0).getReg(), DstRegs, Indexes);
+    MI.eraseFromParent();
+    return Legalized;
+  }
   case TargetOpcode::G_LOAD: {
     unsigned NarrowSize = NarrowTy.getSizeInBits();
     int NumParts =
@@ -309,6 +379,26 @@ LegalizerHelper::widenScalar(MachineInst
     MI.eraseFromParent();
     return Legalized;
   }
+  case TargetOpcode::G_INSERT: {
+    if (TypeIdx != 0)
+      return UnableToLegalize;
+
+    unsigned Src = MI.getOperand(1).getReg();
+    unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
+    MIRBuilder.buildAnyExt(SrcExt, Src);
+
+    unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
+    auto MIB = MIRBuilder.buildInsert(DstExt, SrcExt, MI.getOperand(2).getReg(),
+                                      MI.getOperand(3).getImm());
+    for (unsigned OpNum = 4; OpNum < MI.getNumOperands(); OpNum += 2) {
+      MIB.addReg(MI.getOperand(OpNum).getReg());
+      MIB.addImm(MI.getOperand(OpNum + 1).getImm());
+    }
+
+    MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
+    MI.eraseFromParent();
+    return Legalized;
+  }
   case TargetOpcode::G_LOAD: {
     assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) ==
                WideTy.getSizeInBits() &&

Modified: llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp?rev=294247&r1=294246&r2=294247&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp Mon Feb  6 15:56:47 2017
@@ -41,6 +41,7 @@ LegalizerInfo::LegalizerInfo() : TablesI
   DefaultActions[TargetOpcode::G_STORE] = NarrowScalar;
 
   DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar;
+  DefaultActions[TargetOpcode::G_INSERT] = NarrowScalar;
 }
 
 void LegalizerInfo::computeTables() {

Modified: llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp?rev=294247&r1=294246&r2=294247&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp Mon Feb  6 15:56:47 2017
@@ -78,6 +78,18 @@ AArch64LegalizerInfo::AArch64LegalizerIn
   setAction({G_FREM, s32}, Libcall);
   setAction({G_FREM, s64}, Libcall);
 
+  // FIXME: what should we do about G_INSERTs with more than one source value?
+  // For now the default of not specifying means we'll fall back.
+  for (auto Ty : {s32, s64}) {
+    setAction({G_INSERT, Ty}, Legal);
+    setAction({G_INSERT, 1, Ty}, Legal);
+  }
+  for (auto Ty : {s1, s8, s16}) {
+    setAction({G_INSERT, Ty}, WidenScalar);
+    // FIXME: Can't widen the sources because that violates the constraints on
+    // G_INSERT (It seems entirely reasonable that inputs shouldn't overlap).
+  }
+
   for (unsigned MemOp : {G_LOAD, G_STORE}) {
     for (auto Ty : {s8, s16, s32, s64, p0, v2s32})
       setAction({MemOp, Ty}, Legal);

Modified: llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll?rev=294247&r1=294246&r2=294247&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll (original)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll Mon Feb  6 15:56:47 2017
@@ -78,7 +78,7 @@ define void @sequence_mapping([2 x i64]
   ; Legalizer was asserting when it enountered an unexpected default action.
 ; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for legal_default
 ; FALLBACK-WITH-REPORT-LABEL: legal_default:
-define void @legal_default(i64 %in) {
-  insertvalue [2 x i64] undef, i64 %in, 0
+define void @legal_default([8 x i8] %in) {
+  insertvalue { [4 x i8], [8 x i8], [4 x i8] } undef, [8 x i8] %in, 1
   ret void
 }

Added: llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir?rev=294247&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir (added)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir Mon Feb  6 15:56:47 2017
@@ -0,0 +1,100 @@
+# RUN: llc -O0 -run-pass=legalizer -global-isel %s -o - 2>&1 | FileCheck %s
+
+--- |
+  target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+  target triple = "aarch64--"
+  define void @test_inserts_1() { ret void }
+  define void @test_inserts_2() { ret void }
+  define void @test_inserts_3() { ret void }
+  define void @test_inserts_4() { ret void }
+...
+
+---
+name:            test_inserts_1
+body: |
+  bb.0:
+    liveins: %w0
+
+      ; Low part of insertion wipes out the old register entirely, so %0 gets
+      ; forwarded to the G_STORE. Hi part is unchanged so (split) G_LOAD gets
+      ; forwarded.
+    ; CHECK-LABEL: name: test_inserts_1
+    ; CHECK: [[LO:%[0-9]+]](s64) = G_LOAD
+    ; CHECK: [[HI:%[0-9]+]](s64) = G_LOAD
+    ; CHECK: G_STORE %0(s64)
+    ; CHECK: G_STORE [[HI]]
+    %0:_(s64) = COPY %x0
+    %1:_(s32) = COPY %w1
+    %2:_(p0) = COPY %x2
+    %3:_(s128) = G_LOAD %2(p0) :: (load 16)
+    %4:_(s128) = G_INSERT %3(s128), %0(s64), 0
+    G_STORE %4(s128), %2(p0) :: (store 16)
+    RET_ReallyLR
+...
+
+---
+name:            test_inserts_2
+body: |
+  bb.0:
+    liveins: %w0
+
+      ; Low insertion wipes out the old register entirely, so %0 gets forwarded
+      ; to the G_STORE again. Second insertion is real.
+    ; CHECK-LABEL: name: test_inserts_2
+    ; CHECK: [[LO:%[0-9]+]](s64) = G_LOAD
+    ; CHECK: [[HI:%[0-9]+]](s64) = G_LOAD
+    ; CHECK: [[NEWHI:%[0-9]+]](s64) = G_INSERT [[HI]](s64), %1(s32), 0
+    ; CHECK: G_STORE %0(s64)
+    ; CHECK: G_STORE [[NEWHI]]
+    %0:_(s64) = COPY %x0
+    %1:_(s32) = COPY %w1
+    %2:_(p0) = COPY %x2
+    %3:_(s128) = G_LOAD %2(p0) :: (load 16)
+    %4:_(s128) = G_INSERT %3(s128), %0(s64), 0
+    %5:_(s128) = G_INSERT %4(s128), %1(s32), 64
+    G_STORE %5(s128), %2(p0) :: (store 16)
+    RET_ReallyLR
+...
+
+---
+name:            test_inserts_3
+body: |
+  bb.0:
+    liveins: %w0
+
+      ; I'm not entirely convinced inserting a p0 into an s64 is valid, but it's
+      ; certainly better than the alternative of directly forwarding the value
+      ; which would cause a nasty type mismatch.
+    ; CHECK-LABEL: name: test_inserts_3
+    ; CHECK: [[LO:%[0-9]+]](s64) = G_LOAD
+    ; CHECK: [[HI:%[0-9]+]](s64) = G_LOAD
+    ; CHECK: [[NEWLO:%[0-9]+]](s64) = G_INSERT [[LO]](s64), %0(p0), 0
+    ; CHECK: G_STORE [[NEWLO]](s64)
+    ; CHECK: G_STORE [[HI]]
+    %0:_(p0) = COPY %x0
+    %1:_(s32) = COPY %w1
+    %2:_(p0) = COPY %x2
+    %3:_(s128) = G_LOAD %2(p0) :: (load 16)
+    %4:_(s128) = G_INSERT %3(s128), %0(p0), 0
+    G_STORE %4(s128), %2(p0) :: (store 16)
+    RET_ReallyLR
+...
+
+---
+name:            test_inserts_4
+body: |
+  bb.0:
+    liveins: %w0
+
+      ; A narrow insert gets surrounded by a G_ANYEXT/G_TRUNC pair.
+    ; CHECK-LABEL: name: test_inserts_4
+    ; CHECK: [[VALEXT:%[0-9]+]](s32) = G_ANYEXT %1(s8)
+    ; CHECK: [[VAL:%[0-9]+]](s32) = G_INSERT [[VALEXT]](s32), %0(s1), 0
+    ; CHECK: %3(s8) = G_TRUNC [[VAL]](s32)
+    %0:_(s1) = COPY %w0
+    %1:_(s8) = COPY %w1
+    %2:_(p0) = COPY %x2
+    %3:_(s8) = G_INSERT %1(s8), %0(s1), 0
+    G_STORE %3(s8), %2(p0) :: (store 1)
+    RET_ReallyLR
+...




More information about the llvm-commits mailing list