[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