Index: llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCCallLowering.cpp +++ 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,35 @@ 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 { + MIB.addUse(PhysReg, RegState::Implicit); + Register ExtReg = extendRegister(ValVReg, VA); + MIRBuilder.buildCopy(PhysReg, ExtReg); + } + + void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, + MachinePointerInfo &MPO, CCValAssign &VA) override { + llvm_unreachable("unimplemented"); + } + + Register getStackAddress(uint64_t Size, int64_t Offset, + MachinePointerInfo &MPO, + ISD::ArgFlagsTy Flags) override { + llvm_unreachable("unimplemented"); + } + + MachineInstrBuilder MIB; +}; +} + PPCCallLowering::PPCCallLowering(const PPCTargetLowering &TLI) : CallLowering(&TLI) {} @@ -34,13 +64,35 @@ const Value *Val, ArrayRef 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 SplitArgs; + splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv()); + + // Use the calling convention callback to determine type and location of + // return value. + OutgoingValueAssigner ArgAssigner(RetCC_PPC); - MIRBuilder.buildInstr(PPC::BLR8); - return true; + // 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, Index: llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def =================================================================== --- /dev/null +++ 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 Index: llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp @@ -75,7 +75,34 @@ { } +static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, + MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) { + Register DstReg = I.getOperand(0).getReg(); + Register SrcReg = I.getOperand(1).getReg(); + + if (!Register::isPhysicalRegister(DstReg)) + if (!RBI.constrainGenericRegister(DstReg, PPC::G8RCRegClass, MRI)) + return false; + if (!Register::isPhysicalRegister(SrcReg)) + if (!RBI.constrainGenericRegister(SrcReg, PPC::G8RCRegClass, MRI)) + 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; Index: llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp @@ -18,5 +18,14 @@ 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(); } Index: llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h +++ llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h @@ -26,6 +26,32 @@ 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 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 Index: llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp @@ -21,6 +21,88 @@ #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 ((Opc != TargetOpcode::COPY && !isPreISelGenericOpcode(Opc)) || + Opc == TargetOpcode::G_PHI) { + const RegisterBankInfo::InstructionMapping &Mapping = + getInstrMappingImpl(MI); + if (Mapping.isValid()) + return Mapping; + } + + const MachineFunction &MF = *MI.getParent()->getParent(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + const TargetSubtargetInfo &STI = MF.getSubtarget(); + const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); + + 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; + case TargetOpcode::COPY: { + Register DstReg = MI.getOperand(0).getReg(); + Register SrcReg = MI.getOperand(1).getReg(); + const RegisterBank *DstRB = getRegBank(DstReg, MRI, TRI); + const RegisterBank *SrcRB = getRegBank(SrcReg, MRI, TRI); + if (!DstRB) + DstRB = SrcRB; + else if (!SrcRB) + SrcRB = DstRB; + assert(DstRB && SrcRB && "Both RegBank were nullptr"); + unsigned Size = getSizeInBits(DstReg, MRI, TRI); + Cost = copyCost(*DstRB, *SrcRB, Size); + OperandsMapping = getCopyMapping(DstRB->getID(), SrcRB->getID(), Size); + // We only care about the mapping of the destination. + NumOperands = 1; + break; + } + default: + return getInvalidInstructionMapping(); + } + + return getInstructionMapping(MappingID, Cost, OperandsMapping, NumOperands); +} + +RegisterBankInfo::InstructionMappings +PPCRegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const { + // TODO Implement. + return RegisterBankInfo::getInstrAlternativeMappings(MI); +} Index: llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td +++ 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]>; Index: llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll @@ -0,0 +1,61 @@ +; RUN: llc -mtriple ppc64le-linux -global-isel -o - < %s | FileCheck %s -check-prefixes=CHECK,LINUX + +; CHECK-LABEL: test_andi64: +; LINUX: and 3, 3, 4 +; LINUX: blr +define i64 @test_andi64(i64 %a, i64 %b) { + %res = and i64 %a, %b + ret i64 %res +} + +; CHECK-LABEL: test_nandi64: +; LINUX: nand 3, 3, 4 +; LINUX: blr +define i64 @test_nandi64(i64 %a, i64 %b) { + %and = and i64 %a, %b + %neg = xor i64 %and, -1 + ret i64 %neg +} + +; CHECK-LABEL: test_andci64: +; LINUX: andc 3, 3, 4 +; LINUX: blr +define i64 @test_andci64(i64 %a, i64 %b) { + %neg = xor i64 %b, -1 + %and = and i64 %a, %neg + ret i64 %and +} + +; CHECK-LABEL: test_ori64: +; LINUX: or 3, 3, 4 +; LINUX: blr +define i64 @test_ori64(i64 %a, i64 %b) { + %res = or i64 %a, %b + ret i64 %res +} + +; CHECK-LABEL: test_orci64: +; LINUX: orc 3, 3, 4 +; LINUX: blr +define i64 @test_orci64(i64 %a, i64 %b) { + %neg = xor i64 %b, -1 + %or = or i64 %a, %neg + ret i64 %or +} + +; CHECK-LABEL: test_nori64: +; LINUX: nor 3, 3, 4 +; LINUX: blr +define i64 @test_nori64(i64 %a, i64 %b) { + %or = or i64 %a, %b + %neg = xor i64 %or, -1 + ret i64 %neg +} + +; CHECK-LABEL: test_xori64: +; LINUX: xor 3, 3, 4 +; LINUX: blr +define i64 @test_xori64(i64 %a, i64 %b) { + %res = xor i64 %a, %b + ret i64 %res +}