[llvm] be4a1df - [PowerPC] Extend GlobalISel implementation to emit and/or/xor.

Kai Nacke via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 21 12:08:42 PST 2022


Author: Kai Nacke
Date: 2022-11-21T20:08:20Z
New Revision: be4a1dfbf93dcb837e06bb619b934ed8cf9fd224

URL: https://github.com/llvm/llvm-project/commit/be4a1dfbf93dcb837e06bb619b934ed8cf9fd224
DIFF: https://github.com/llvm/llvm-project/commit/be4a1dfbf93dcb837e06bb619b934ed8cf9fd224.diff

LOG: [PowerPC] Extend GlobalISel implementation to emit and/or/xor.

Adds some more code to GlobalISel to enable instruction selection for and/or/xor.

- Makes G_IMPLICIT_DEF, G_CONSTANT, G_AND, G_OR, G_XOR legal for 64bit register size.
- Implement lowerReturn in CallLowering
- Provides mapping of the operands to register banks.
- Adds register info to G_COPY operands.

The utility functions are all only implemented so far to support this use case.
Especially the functions in PPCGenRegisterBankInfo.def are too simple for
general use.

Reviewed By: nemanjai, shchenz, amyk

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

Added: 
    llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def
    llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll

Modified: 
    llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp
    llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
    llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
    llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
    llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
    llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp b/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp
index b71d59ed79edd..3913ede3dc186 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "PPCCallLowering.h"
+#include "PPCCallingConv.h"
 #include "PPCISelLowering.h"
 #include "PPCSubtarget.h"
 #include "PPCTargetMachine.h"
@@ -27,6 +28,45 @@
 
 using namespace llvm;
 
+namespace {
+
+struct OutgoingArgHandler : public CallLowering::OutgoingValueHandler {
+  OutgoingArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+                     MachineInstrBuilder MIB)
+      : OutgoingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
+
+  void assignValueToReg(Register ValVReg, Register PhysReg,
+                        CCValAssign VA) override;
+  void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
+                            MachinePointerInfo &MPO, CCValAssign &VA) override;
+  Register getStackAddress(uint64_t Size, int64_t Offset,
+                           MachinePointerInfo &MPO,
+                           ISD::ArgFlagsTy Flags) override;
+
+  MachineInstrBuilder MIB;
+};
+} // namespace
+
+void OutgoingArgHandler::assignValueToReg(Register ValVReg, Register PhysReg,
+                                          CCValAssign VA) {
+  MIB.addUse(PhysReg, RegState::Implicit);
+  Register ExtReg = extendRegister(ValVReg, VA);
+  MIRBuilder.buildCopy(PhysReg, ExtReg);
+}
+
+void OutgoingArgHandler::assignValueToAddress(Register ValVReg, Register Addr,
+                                              LLT MemTy,
+                                              MachinePointerInfo &MPO,
+                                              CCValAssign &VA) {
+  llvm_unreachable("unimplemented");
+}
+
+Register OutgoingArgHandler::getStackAddress(uint64_t Size, int64_t Offset,
+                                             MachinePointerInfo &MPO,
+                                             ISD::ArgFlagsTy Flags) {
+  llvm_unreachable("unimplemented");
+}
+
 PPCCallLowering::PPCCallLowering(const PPCTargetLowering &TLI)
     : CallLowering(&TLI) {}
 
@@ -34,13 +74,35 @@ bool PPCCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
                                   const Value *Val, ArrayRef<Register> VRegs,
                                   FunctionLoweringInfo &FLI,
                                   Register SwiftErrorVReg) const {
-  assert(((Val && !VRegs.empty()) || (!Val && VRegs.empty())) &&
-         "Return value without a vreg");
-  if (VRegs.size() > 0)
-    return false;
+  auto MIB = MIRBuilder.buildInstrNoInsert(PPC::BLR8);
+  bool Success = true;
+  MachineFunction &MF = MIRBuilder.getMF();
+  const Function &F = MF.getFunction();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+  auto &DL = F.getParent()->getDataLayout();
+  if (!VRegs.empty()) {
+    // Setup the information about the return value.
+    ArgInfo OrigArg{VRegs, Val->getType(), 0};
+    setArgFlags(OrigArg, AttributeList::ReturnIndex, DL, F);
+
+    // Split the return value into consecutive registers if needed.
+    SmallVector<ArgInfo, 8> SplitArgs;
+    splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv());
 
-  MIRBuilder.buildInstr(PPC::BLR8);
-  return true;
+    // Use the calling convention callback to determine type and location of
+    // return value.
+    OutgoingValueAssigner ArgAssigner(RetCC_PPC);
+
+    // Handler to move the return value into the correct location.
+    OutgoingArgHandler ArgHandler(MIRBuilder, MRI, MIB);
+
+    // Iterate over all return values, and move them to the assigned location.
+    Success = determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgs,
+                                            MIRBuilder, F.getCallingConv(),
+                                            F.isVarArg());
+  }
+  MIRBuilder.insertInstr(MIB);
+  return Success;
 }
 
 bool PPCCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,

diff  --git a/llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def b/llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def
new file mode 100644
index 0000000000000..471af5d13d80d
--- /dev/null
+++ b/llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def
@@ -0,0 +1,62 @@
+//===- PPCGenRegisterBankInfo.def -------------------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file defines all the static objects used by PPCRegisterBankInfo.
+/// \todo This should be generated by TableGen, because the logic here can be
+///  derived from register bank definition. Not yet implemented.
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+RegisterBankInfo::PartialMapping PPCGenRegisterBankInfo::PartMappings[]{
+    /* StartIdx, Length, RegBank */
+    // 0: GPR 64-bit value.
+    {0, 64, PPC::GPRRegBank},
+};
+
+// ValueMappings.
+// Pointers to the entries in this array are returned by getValueMapping() and
+// getCopyMapping().
+//
+// The array has the following structure:
+// - At index 0 is the invalid entry.
+// - After that, the mappings for the register types from PartialMappingIdx
+//   follow. Each mapping consists of 3 entries, which is needed to cover
+//   3-operands instructions.
+// - Last, mappings for cross-register bank moves follow. Since COPY has only
+//   2 operands, a mapping consists of 2 entries.
+RegisterBankInfo::ValueMapping PPCGenRegisterBankInfo::ValMappings[]{
+    /* BreakDown, NumBreakDowns */
+    // 0: invalid
+    {nullptr, 0},
+    // 1: GPR 64-bit value.
+    {&PPCGenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
+    {&PPCGenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
+    {&PPCGenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
+};
+
+// TODO Too simple!
+const RegisterBankInfo::ValueMapping *
+PPCGenRegisterBankInfo::getValueMapping(PartialMappingIdx RBIdx) {
+  assert(RBIdx != PartialMappingIdx::PMI_None && "No mapping needed for that");
+
+  unsigned ValMappingIdx = RBIdx - PMI_Min;
+
+  return &ValMappings[1 + 3 * ValMappingIdx];
+}
+
+// TODO Too simple!
+const RegisterBankInfo::ValueMapping *
+PPCGenRegisterBankInfo::getCopyMapping(unsigned DstBankID, unsigned SrcBankID,
+                                       unsigned Size) {
+  assert(DstBankID < PPC::NumRegisterBanks && "Invalid bank ID");
+  assert(SrcBankID < PPC::NumRegisterBanks && "Invalid bank ID");
+
+  return &ValMappings[1];
+}
+
+} // namespace llvm

diff  --git a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
index 0cd8350e3fdda..93bbb9c107577 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
@@ -75,7 +75,51 @@ PPCInstructionSelector::PPCInstructionSelector(const PPCTargetMachine &TM,
 {
 }
 
+static const TargetRegisterClass *getRegClass(LLT Ty, const RegisterBank *RB) {
+  if (RB->getID() == PPC::GPRRegBankID) {
+    if (Ty.getSizeInBits() == 64)
+      return &PPC::G8RCRegClass;
+  }
+
+  llvm_unreachable("Unknown RegBank!");
+}
+
+static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
+                       MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
+                       const RegisterBankInfo &RBI) {
+  Register DstReg = I.getOperand(0).getReg();
+
+  if (DstReg.isPhysical())
+    return true;
+
+  const RegisterBank *DstRegBank = RBI.getRegBank(DstReg, MRI, TRI);
+  const TargetRegisterClass *DstRC =
+      getRegClass(MRI.getType(DstReg), DstRegBank);
+
+  // No need to constrain SrcReg. It will get constrained when we hit another of
+  // its use or its defs.
+  // Copies do not have constraints.
+  if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {
+    LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
+                      << " operand\n");
+    return false;
+  }
+
+  return true;
+}
+
 bool PPCInstructionSelector::select(MachineInstr &I) {
+  auto &MBB = *I.getParent();
+  auto &MF = *MBB.getParent();
+  auto &MRI = MF.getRegInfo();
+
+  if (!isPreISelGenericOpcode(I.getOpcode())) {
+    if (I.isCopy())
+      return selectCopy(I, TII, MRI, TRI, RBI);
+
+    return true;
+  }
+
   if (selectImpl(I, *CoverageInfo))
     return true;
   return false;

diff  --git a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
index 5d196df80d50c..be56b6fe49589 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
@@ -18,5 +18,14 @@ using namespace llvm;
 using namespace LegalizeActions;
 
 PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) {
+  using namespace TargetOpcode;
+  const LLT S64 = LLT::scalar(64);
+  getActionDefinitionsBuilder(G_IMPLICIT_DEF).legalFor({S64});
+  getActionDefinitionsBuilder(G_CONSTANT)
+      .legalFor({S64})
+      .clampScalar(0, S64, S64);
+  getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
+      .legalFor({S64})
+      .clampScalar(0, S64, S64);
   getLegacyLegalizerInfo().computeTables();
 }

diff  --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
index 58165fcaac03f..2eb9ec2c2b085 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
@@ -21,6 +21,65 @@
 #define GET_TARGET_REGBANK_IMPL
 #include "PPCGenRegisterBank.inc"
 
+// This file will be TableGen'ed at some point.
+#include "PPCGenRegisterBankInfo.def"
+
 using namespace llvm;
 
 PPCRegisterBankInfo::PPCRegisterBankInfo(const TargetRegisterInfo &TRI) {}
+
+const RegisterBank &
+PPCRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
+                                            LLT Ty) const {
+  switch (RC.getID()) {
+  case PPC::G8RCRegClassID:
+  case PPC::G8RC_NOX0RegClassID:
+  case PPC::G8RC_and_G8RC_NOX0RegClassID:
+    return getRegBank(PPC::GPRRegBankID);
+  default:
+    llvm_unreachable("Unexpected register class");
+  }
+}
+
+const RegisterBankInfo::InstructionMapping &
+PPCRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
+  const unsigned Opc = MI.getOpcode();
+
+  // Try the default logic for non-generic instructions that are either copies
+  // or already have some operands assigned to banks.
+  if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
+    const RegisterBankInfo::InstructionMapping &Mapping =
+        getInstrMappingImpl(MI);
+    if (Mapping.isValid())
+      return Mapping;
+  }
+
+  unsigned NumOperands = MI.getNumOperands();
+  const ValueMapping *OperandsMapping = nullptr;
+  unsigned Cost = 1;
+  unsigned MappingID = DefaultMappingID;
+
+  switch (Opc) {
+    // Bitwise ops.
+  case TargetOpcode::G_AND:
+  case TargetOpcode::G_OR:
+  case TargetOpcode::G_XOR:
+    assert(NumOperands <= 3 &&
+           "This code is for instructions with 3 or less operands");
+    OperandsMapping = getValueMapping(PMI_GPR64);
+    break;
+  case TargetOpcode::G_CONSTANT:
+    OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr});
+    break;
+  default:
+    return getInvalidInstructionMapping();
+  }
+
+  return getInstructionMapping(MappingID, Cost, OperandsMapping, NumOperands);
+}
+
+RegisterBankInfo::InstructionMappings
+PPCRegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
+  // TODO Implement.
+  return RegisterBankInfo::getInstrAlternativeMappings(MI);
+}

diff  --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
index 31a4c528751f5..11bdd98cd3b52 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
+++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
@@ -26,6 +26,32 @@ class TargetRegisterInfo;
 
 class PPCGenRegisterBankInfo : public RegisterBankInfo {
 protected:
+  enum PartialMappingIdx {
+    PMI_None = -1,
+    PMI_GPR64 = 1,
+    PMI_Min = PMI_GPR64,
+  };
+
+  static RegisterBankInfo::PartialMapping PartMappings[];
+  static RegisterBankInfo::ValueMapping ValMappings[];
+  static PartialMappingIdx BankIDToCopyMapIdx[];
+
+  /// Get the pointer to the ValueMapping representing the RegisterBank
+  /// at \p RBIdx.
+  ///
+  /// The returned mapping works for instructions with the same kind of
+  /// operands for up to 3 operands.
+  ///
+  /// \pre \p RBIdx != PartialMappingIdx::None
+  static const RegisterBankInfo::ValueMapping *
+  getValueMapping(PartialMappingIdx RBIdx);
+
+  /// Get the pointer to the ValueMapping of the operands of a copy
+  /// instruction from the \p SrcBankID register bank to the \p DstBankID
+  /// register bank with a size of \p Size.
+  static const RegisterBankInfo::ValueMapping *
+  getCopyMapping(unsigned DstBankID, unsigned SrcBankID, unsigned Size);
+
 #define GET_TARGET_REGBANK_CLASS
 #include "PPCGenRegisterBank.inc"
 };
@@ -33,6 +59,14 @@ class PPCGenRegisterBankInfo : public RegisterBankInfo {
 class PPCRegisterBankInfo final : public PPCGenRegisterBankInfo {
 public:
   PPCRegisterBankInfo(const TargetRegisterInfo &TRI);
+
+  const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC,
+                                             LLT Ty) const override;
+  const InstructionMapping &
+  getInstrMapping(const MachineInstr &MI) const override;
+
+  InstructionMappings
+  getInstrAlternativeMappings(const MachineInstr &MI) const override;
 };
 } // namespace llvm
 

diff  --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td
index 0e8a4b7061c5a..771d33e9f3a38 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td
+++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td
@@ -12,4 +12,4 @@
 //===----------------------------------------------------------------------===//
 
 /// General Purpose Registers
-def GPRRegBank : RegisterBank<"GPR", [G8RC]>;
+def GPRRegBank : RegisterBank<"GPR", [G8RC, G8RC_NOX0]>;

diff  --git a/llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll
new file mode 100644
index 0000000000000..f133592d6ef54
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll
@@ -0,0 +1,70 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple ppc64le-linux -ppc-asm-full-reg-names -global-isel -o - < %s \
+; RUN:     | FileCheck %s
+
+define i64 @test_andi64(i64 %a, i64 %b) {
+; CHECK-LABEL: test_andi64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    and r3, r3, r4
+; CHECK-NEXT:    blr
+  %res = and i64 %a, %b
+  ret i64 %res
+}
+
+define i64 @test_nandi64(i64 %a, i64 %b) {
+; CHECK-LABEL: test_nandi64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    nand r3, r3, r4
+; CHECK-NEXT:    blr
+  %and = and i64 %a, %b
+  %neg = xor i64 %and, -1
+  ret i64 %neg
+}
+
+define i64 @test_andci64(i64 %a, i64 %b) {
+; CHECK-LABEL: test_andci64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    andc r3, r3, r4
+; CHECK-NEXT:    blr
+  %neg = xor i64 %b, -1
+  %and = and i64 %a, %neg
+  ret i64 %and
+}
+
+define i64 @test_ori64(i64 %a, i64 %b) {
+; CHECK-LABEL: test_ori64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    or r3, r3, r4
+; CHECK-NEXT:    blr
+  %res = or i64 %a, %b
+  ret i64 %res
+}
+
+define i64 @test_orci64(i64 %a, i64 %b) {
+; CHECK-LABEL: test_orci64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    orc r3, r3, r4
+; CHECK-NEXT:    blr
+  %neg = xor i64 %b, -1
+  %or = or i64 %a, %neg
+  ret i64 %or
+}
+
+define i64 @test_nori64(i64 %a, i64 %b) {
+; CHECK-LABEL: test_nori64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    nor r3, r3, r4
+; CHECK-NEXT:    blr
+  %or = or i64 %a, %b
+  %neg = xor i64 %or, -1
+  ret i64 %neg
+}
+
+define i64 @test_xori64(i64 %a, i64 %b) {
+; CHECK-LABEL: test_xori64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    xor r3, r3, r4
+; CHECK-NEXT:    blr
+  %res = xor i64 %a, %b
+  ret i64 %res
+}


        


More information about the llvm-commits mailing list