[llvm-branch-commits] [llvm] [5/7][PISA] Add PISAInstructionSelector (PR #214378)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Aug 5 17:49:19 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel
Author: Michal Paszkowski (michalpaszkowski)
<details>
<summary>Changes</summary>
Add the PISAInstructionSelector, the final Subtarget/TargetMachine wiring, and selection tests.
---
Patch is 81.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/214378.diff
9 Files Affected:
- (modified) llvm/lib/Target/PISA/CMakeLists.txt (+1)
- (added) llvm/lib/Target/PISA/PISAInstructionSelector.cpp (+1794)
- (modified) llvm/lib/Target/PISA/PISASubtarget.cpp (+2-1)
- (modified) llvm/lib/Target/PISA/PISATargetMachine.cpp (+8-2)
- (added) llvm/test/CodeGen/PISA/GlobalISel/inst-select-build-vector-v64.mir (+24)
- (added) llvm/test/CodeGen/PISA/GlobalISel/inst-select-constant-float-type.mir (+36)
- (added) llvm/test/CodeGen/PISA/GlobalISel/inst-select-ctlz.mir (+103)
- (added) llvm/test/CodeGen/PISA/GlobalISel/inst-select-cttz.mir (+103)
- (added) llvm/test/CodeGen/PISA/GlobalISel/inst-select-debug-trace.mir (+41)
``````````diff
diff --git a/llvm/lib/Target/PISA/CMakeLists.txt b/llvm/lib/Target/PISA/CMakeLists.txt
index 0a666058c14d2..a51c8cfafc728 100644
--- a/llvm/lib/Target/PISA/CMakeLists.txt
+++ b/llvm/lib/Target/PISA/CMakeLists.txt
@@ -21,6 +21,7 @@ add_llvm_target(PISACodeGen
PISACallLowering.cpp
PISAISelLowering.cpp
PISAInstrInfo.cpp
+ PISAInstructionSelector.cpp
PISALegalizerInfo.cpp
PISAMCInstLower.cpp
PISAMachineFunctionInfo.cpp
diff --git a/llvm/lib/Target/PISA/PISAInstructionSelector.cpp b/llvm/lib/Target/PISA/PISAInstructionSelector.cpp
new file mode 100644
index 0000000000000..178d24ff75fe3
--- /dev/null
+++ b/llvm/lib/Target/PISA/PISAInstructionSelector.cpp
@@ -0,0 +1,1794 @@
+//===-- PISAInstructionSelector.cpp ---------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/PISAEnum.h"
+#include "PISA.h"
+#include "PISAGenInstrInfo.inc"
+#include "PISAInstrInfo.h"
+#include "PISARegisterBankInfo.h"
+#include "PISARegisterInfo.h"
+#include "PISATargetMachine.h"
+#include "PISAUtils.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/FloatingPointMode.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringTable.h"
+#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
+#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
+#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/IntrinsicsPISA.h"
+#include "llvm/IR/PISAIntrinsicUtils.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/PISAAddrSpace.h"
+
+namespace llvm {
+namespace PISA {
+struct Name2InstrEntry {
+ StringTable::Offset Name;
+ unsigned Opcode;
+};
+
+#define GET_Name2InstrOpTable_DECL
+#define GET_Name2InstrOpTable_IMPL
+#include "PISAGenSearchableTables.inc"
+
+} // namespace PISA
+} // namespace llvm
+
+#define DEBUG_TYPE "pisa-isel"
+
+using namespace llvm;
+using namespace MIPatternMatch;
+
+namespace {
+
+struct SyncScopeInfo {
+ static const StringMap<unsigned> Name2Opcode;
+ DenseMap<llvm::SyncScope::ID, unsigned> ID2Opcode;
+ SyncScope::ID SystemGenericID = SyncScope::System;
+
+ SyncScopeInfo() {}
+ SyncScopeInfo(llvm::LLVMContext &Context) {
+ for (const auto &[Name, Opcode] : Name2Opcode) {
+ auto ID = Context.getOrInsertSyncScopeID(Name);
+ ID2Opcode.emplace_or_assign(ID, Opcode);
+ }
+ ID2Opcode.emplace_or_assign(SyncScope::SingleThread, PISA::fence_subgroup);
+ ID2Opcode.emplace_or_assign(SyncScope::System, PISA::fence_global_system);
+ SystemGenericID = Context.getOrInsertSyncScopeID("system-generic");
+ }
+};
+
+const StringMap<unsigned> SyncScopeInfo::Name2Opcode = {
+ {"workitem", PISA::fence_subgroup},
+ {"workitem-shared", PISA::fence_subgroup},
+ {"workitem-global", PISA::fence_subgroup},
+ {"workitem-generic", PISA::fence_subgroup},
+ {"subgroup", PISA::fence_subgroup},
+ {"subgroup-shared", PISA::fence_subgroup},
+ {"subgroup-global", PISA::fence_subgroup},
+ {"subgroup-generic", PISA::fence_subgroup},
+ {"workgroup", PISA::fence_generic_workgroup},
+ {"workgroup-shared", PISA::fence_shared_workgroup},
+ {"workgroup-global", PISA::fence_global_workgroup},
+ {"workgroup-generic", PISA::fence_generic_workgroup},
+ {"gpu", PISA::fence_generic_gpu},
+ {"gpu-shared", PISA::fence_shared_gpu},
+ {"gpu-global", PISA::fence_global_gpu},
+ {"gpu-generic", PISA::fence_generic_gpu},
+ {"system", PISA::fence_global_system},
+ {"system-shared", PISA::fence_shared_gpu},
+ {"system-global", PISA::fence_global_system},
+};
+
+#define GET_GLOBALISEL_PREDICATE_BITSET
+#include "PISAGenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATE_BITSET
+
+class PISAInstructionSelector : public InstructionSelector {
+ const PISASubtarget &STI;
+ const PISAInstrInfo &TII;
+ const PISARegisterInfo &TRI;
+ const RegisterBankInfo &RBI;
+ MachineRegisterInfo *MRI = nullptr;
+ SyncScopeInfo SSI;
+ MachineFrameInfo *MFI = nullptr;
+
+public:
+ PISAInstructionSelector(const PISATargetMachine &TM, const PISASubtarget &ST,
+ const RegisterBankInfo &RBI);
+ void setupMF(MachineFunction &MF, GISelValueTracking *KB,
+ CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
+ BlockFrequencyInfo *BFI) override;
+ bool select(MachineInstr &I) override;
+ static const char *getName() { return DEBUG_TYPE; }
+
+#define GET_GLOBALISEL_PREDICATES_DECL
+#include "PISAGenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATES_DECL
+
+#define GET_GLOBALISEL_TEMPORARIES_DECL
+#include "PISAGenGlobalISel.inc"
+#undef GET_GLOBALISEL_TEMPORARIES_DECL
+
+private:
+ // tblgen-erated 'select' implementation, used as the initial selector for
+ // the patterns that don't require complex C++.
+ bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
+ bool selectFrameIndex(MachineInstr &I) const;
+ bool selectGlobalValue(MachineInstr &I) const;
+ bool selectPhiOrImplicitDef(MachineInstr &I) const;
+ bool selectAddSubWithOverflow(MachineInstr &I) const;
+ bool selectSignedAddSubWithOverflow(MachineInstr &I) const;
+ bool selectBitcast(MachineInstr &I) const;
+ // NOLINTBEGIN(readability-identifier-naming)
+ bool selectG_BUILD_VECTOR(MachineInstr &I) const;
+ bool selectConvPtrInt(MachineInstr &I) const;
+ bool selectCopy(MachineInstr &I) const;
+ bool selectG_INTRINSIC(MachineInstr &I) const;
+ bool selectG_INTRINSIC_WITH_SIDEFFECTS(MachineInstr &I) const;
+ bool selectDbgValue(MachineInstr &I) const;
+ bool selectG_FCANONICALIZE(MachineInstr &I) const;
+ bool selectG_LROUND(MachineInstr &I) const;
+ bool selectG_MERGE_VALUES(MachineInstr &MI) const;
+ bool selectG_UNMERGE_VALUES(MachineInstr &MI) const;
+ bool selectG_BFX(MachineInstr &I, bool Signed) const;
+ bool selectG_CONSTANT(MachineInstr &I) const;
+ bool selectG_FENCE(MachineInstr &I) const;
+ bool selectG_INSERT_SUBVECTOR(MachineInstr &MI) const;
+ bool selectG_EXTRACT_SUBVECTOR(MachineInstr &MI) const;
+ bool selectG_INSERT_VECTOR_ELT(MachineInstr &MI) const;
+ bool selectG_EXTRACT_VECTOR_ELT(MachineInstr &MI) const;
+ bool selectG_ADDRSPACE_CAST(llvm::MachineInstr &I) const;
+ MachineInstr *findPtrBaseDefinition(MachineInstr *StartDef,
+ const MachineRegisterInfo &MRI) const;
+
+ InstructionSelector::ComplexRendererFns
+ SelectAddr_rr(MachineOperand &Root) const;
+ InstructionSelector::ComplexRendererFns
+ SelectAddr_ri(MachineOperand &Root) const;
+ InstructionSelector::ComplexRendererFns
+ selectParamSlot_ii(MachineOperand &Root) const;
+ InstructionSelector::ComplexRendererFns
+ selectParamSlot_ir(MachineOperand &Root) const;
+
+ // NOLINTEND(readability-identifier-naming)
+
+ bool emitBuildVector(MachineInstr &InsertPt, Register DstReg,
+ ArrayRef<Register> Srcs) const;
+
+ bool useFastFP(const MachineInstr &I) const {
+ return I.getFlag(MachineInstr::MIFlag::FmAfn);
+ }
+};
+
+} // namespace
+
+#define GET_GLOBALISEL_IMPL
+#include "PISAGenGlobalISel.inc"
+#undef GET_GLOBALISEL_IMPL
+
+PISAInstructionSelector::PISAInstructionSelector(const PISATargetMachine &TM,
+ const PISASubtarget &ST,
+ const RegisterBankInfo &RBI)
+ : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
+ TRI(*ST.getRegisterInfo()), RBI(RBI),
+#define GET_GLOBALISEL_PREDICATES_INIT
+#include "PISAGenGlobalISel.inc"
+#undef GET_GLOBALISEL_PREDICATES_INIT
+#define GET_GLOBALISEL_TEMPORARIES_INIT
+#include "PISAGenGlobalISel.inc"
+#undef GET_GLOBALISEL_TEMPORARIES_INIT
+{
+}
+
+void PISAInstructionSelector::setupMF(MachineFunction &MF,
+ GISelValueTracking *KB,
+ CodeGenCoverage *CoverageInfo,
+ ProfileSummaryInfo *PSI,
+ BlockFrequencyInfo *BFI) {
+ constexpr unsigned SharedAS = unsigned(PISAAS::AddressSpace::SHARED);
+
+ SSI = SyncScopeInfo(MF.getFunction().getContext());
+ InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
+ MRI = &MF.getRegInfo();
+ MFI = &MF.getFrameInfo();
+ // Setup the correct stack ID.
+ for (int Idx = MFI->getObjectIndexBegin(), EndIdx = MFI->getObjectIndexEnd();
+ Idx != EndIdx; ++Idx) {
+ if (auto *AI = MFI->getObjectAllocation(Idx)) {
+ const auto AS = AI->getAddressSpace();
+ Type *AllocatedTy = AI->getAllocatedType();
+ if (auto *ATy = dyn_cast<ArrayType>(AllocatedTy))
+ AllocatedTy = ATy->getElementType();
+
+ auto *TExtTy = dyn_cast<TargetExtType>(AllocatedTy);
+
+ if (AS == SharedAS) {
+ assert(MF.getFunction().getCallingConv() == CallingConv::PISA_KERNEL &&
+ "shared variables are not supported in functions!");
+ unsigned StackID = TargetStackID::PISAShared;
+ if (TExtTy)
+ StackID = llvm::StringSwitch<unsigned>(TExtTy->getName())
+ .Default(TargetStackID::PISAShared);
+ MFI->setStackID(Idx, StackID);
+ }
+ }
+ }
+}
+
+bool PISAInstructionSelector::select(MachineInstr &I) {
+ assert(I.getParent() && "Instruction should be in a basic block!");
+ assert(I.getParent()->getParent() && "Instruction should be in a function!");
+
+ unsigned Opcode = I.getOpcode();
+
+ // If it's not a GMIR instruction, we've selected it already.
+ if (!I.isPreISelOpcode() && Opcode != TargetOpcode::DBG_VALUE) {
+ if (I.isCopy())
+ return selectCopy(I);
+ constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ return true;
+ }
+
+ switch (Opcode) {
+ default:
+ break;
+ case TargetOpcode::G_ADDRSPACE_CAST:
+ if (selectG_ADDRSPACE_CAST(I))
+ return true;
+ break;
+ }
+
+ if (selectImpl(I, *CoverageInfo))
+ return true;
+
+ if (I.getNumOperands() != I.getNumExplicitOperands()) {
+ LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
+ return false;
+ }
+
+ switch (Opcode) {
+ case TargetOpcode::G_FRAME_INDEX:
+ return selectFrameIndex(I);
+ case TargetOpcode::G_GLOBAL_VALUE:
+ return selectGlobalValue(I);
+ case TargetOpcode::G_PHI:
+ case TargetOpcode::G_IMPLICIT_DEF:
+ return selectPhiOrImplicitDef(I);
+ case TargetOpcode::G_UADDO:
+ case TargetOpcode::G_USUBO:
+ case TargetOpcode::G_UADDE:
+ case TargetOpcode::G_USUBE:
+ return selectAddSubWithOverflow(I);
+ case TargetOpcode::G_SADDO:
+ case TargetOpcode::G_SSUBO:
+ case TargetOpcode::G_SADDE:
+ case TargetOpcode::G_SSUBE:
+ return selectSignedAddSubWithOverflow(I);
+ case TargetOpcode::G_BITCAST:
+ return selectBitcast(I);
+ case TargetOpcode::G_UNMERGE_VALUES:
+ return selectG_UNMERGE_VALUES(I);
+ case TargetOpcode::G_CONCAT_VECTORS:
+ case TargetOpcode::G_MERGE_VALUES:
+ return selectG_MERGE_VALUES(I);
+ case TargetOpcode::G_BUILD_VECTOR:
+ return selectG_BUILD_VECTOR(I);
+ case TargetOpcode::G_PTRTOINT:
+ case TargetOpcode::G_INTTOPTR:
+ return selectConvPtrInt(I);
+ case TargetOpcode::G_FREEZE:
+ return selectCopy(I);
+ case TargetOpcode::G_INTRINSIC:
+ case TargetOpcode::G_INTRINSIC_CONVERGENT:
+ return selectG_INTRINSIC(I);
+ case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
+ case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
+ return selectG_INTRINSIC_WITH_SIDEFFECTS(I);
+ case TargetOpcode::DBG_VALUE:
+ return selectDbgValue(I);
+ case TargetOpcode::G_FCANONICALIZE:
+ return selectG_FCANONICALIZE(I);
+ case TargetOpcode::G_LROUND:
+ case TargetOpcode::G_LLROUND:
+ return selectG_LROUND(I);
+ case TargetOpcode::G_UBFX:
+ return selectG_BFX(I, false);
+ case TargetOpcode::G_SBFX:
+ return selectG_BFX(I, true);
+ case TargetOpcode::G_CONSTANT:
+ return selectG_CONSTANT(I);
+ case TargetOpcode::G_FENCE:
+ return selectG_FENCE(I);
+ case TargetOpcode::G_INSERT_SUBVECTOR:
+ return selectG_INSERT_SUBVECTOR(I);
+ case TargetOpcode::G_EXTRACT_SUBVECTOR:
+ return selectG_EXTRACT_SUBVECTOR(I);
+ case TargetOpcode::G_INSERT_VECTOR_ELT:
+ return selectG_INSERT_VECTOR_ELT(I);
+ case TargetOpcode::G_EXTRACT_VECTOR_ELT:
+ return selectG_EXTRACT_VECTOR_ELT(I);
+ default:
+ return false;
+ }
+}
+
+MachineInstr *PISAInstructionSelector::findPtrBaseDefinition(
+ MachineInstr *StartDef, const MachineRegisterInfo &MRI) const {
+ if (!StartDef)
+ return nullptr;
+
+ SmallVector<MachineInstr *, 8> WorkList;
+ SmallPtrSet<MachineInstr *, 8> Visited;
+ MachineInstr *DefMI = StartDef;
+ WorkList.push_back(DefMI);
+
+ while (!WorkList.empty()) {
+ DefMI = WorkList.pop_back_val();
+ if (!Visited.insert(DefMI).second)
+ continue;
+
+ auto Opcode = DefMI->getOpcode();
+ switch (Opcode) {
+ default:
+ // If we see an instruction that we don't recognize, stop looking and try
+ // to select the G_ADDRSPACE_CAST as is.
+ WorkList.clear();
+ break;
+ case TargetOpcode::G_PTR_ADD: {
+ MachineInstr *BaseDef =
+ getDefIgnoringCopies(DefMI->getOperand(1).getReg(), MRI);
+ if (BaseDef)
+ WorkList.push_back(BaseDef);
+ } break;
+ case TargetOpcode::G_PHI:
+ for (unsigned I = 1, E = DefMI->getNumOperands(); I < E; I += 2) {
+ MachineInstr *PhiDef =
+ getDefIgnoringCopies(DefMI->getOperand(I).getReg(), MRI);
+ if (PhiDef)
+ WorkList.push_back(PhiDef);
+ }
+ break;
+ case TargetOpcode::G_SELECT:
+ for (unsigned I = 2, E = DefMI->getNumOperands(); I < E; I++) {
+ MachineInstr *SelectDef =
+ getDefIgnoringCopies(DefMI->getOperand(I).getReg(), MRI);
+ if (SelectDef)
+ WorkList.push_back(SelectDef);
+ }
+ break;
+ }
+ }
+
+ return DefMI;
+}
+
+bool PISAInstructionSelector::selectG_ADDRSPACE_CAST(
+ llvm::MachineInstr &I) const {
+ constexpr unsigned GenericAS =
+ static_cast<unsigned>(PISAAS::AddressSpace::GENERIC);
+ [[maybe_unused]] constexpr unsigned SharedAS =
+ static_cast<unsigned>(PISAAS::AddressSpace::SHARED);
+ [[maybe_unused]] constexpr unsigned PrivateAS =
+ static_cast<unsigned>(PISAAS::AddressSpace::PRIVATE);
+
+ auto [Dst, DstTy, Src, SrcTy] = I.getFirst2RegLLTs();
+ const unsigned DstAS = DstTy.getAddressSpace();
+ [[maybe_unused]] const unsigned SrcAS = SrcTy.getAddressSpace();
+
+ if (DstAS != GenericAS)
+ return false;
+
+ MachineInstr *DefMI =
+ findPtrBaseDefinition(getDefIgnoringCopies(Src, *MRI), *MRI);
+
+ if (!DefMI || DefMI->getOpcode() != TargetOpcode::G_FRAME_INDEX)
+ return false;
+
+ int FI = DefMI->getOperand(1).getIndex();
+ switch (MFI->getStackID(FI)) {
+ default: // No custom selection needed
+ break;
+ }
+
+ return false;
+}
+
+bool PISAInstructionSelector::selectG_INTRINSIC(MachineInstr &I) const {
+ // While we want to select special reg intrinsics in tablegen using
+ // SpecialRegPat<>, there is an issue in llvm that prevents us from doing
+ // so when the output value is a pointer. It fails in:
+ // GlobalISelEmitter::createAndImportSelDAGMatcher()
+ // because isOutOperandAPointer() will always return false for G_INTRINSIC
+ // as its OutOperandList = (outs). This then causes addTypeCheckPredicate()
+ // to not generate a pointer matcher, so tablegen fails saying that we have
+ // an unsupported type (even though it is an iPTR). Until this is fixed,
+ // manually select these cases here.
+
+ switch (cast<GIntrinsic>(I).getIntrinsicID()) {
+ default:
+ return false;
+ }
+}
+
+bool PISAInstructionSelector::selectG_INTRINSIC_WITH_SIDEFFECTS(
+ MachineInstr &I) const {
+ // Find the intrinsic ID.
+ unsigned IntrinID = cast<GIntrinsic>(I).getIntrinsicID();
+ switch (IntrinID) {
+ default:
+ return false;
+ }
+}
+
+bool PISAInstructionSelector::selectFrameIndex(MachineInstr &I) const {
+ I.setDesc(TII.get(PISA::addrof_32b));
+ // need to set dst reg-class
+ const Register DefReg = I.getOperand(0).getReg();
+ const LLT DefTy = MRI->getType(DefReg);
+
+ const RegClassOrRegBank &RegClassOrBank = MRI->getRegClassOrRegBank(DefReg);
+ const TargetRegisterClass *DefRC =
+ RegClassOrBank.dyn_cast<const TargetRegisterClass *>();
+ if (!DefRC)
+ DefRC = TRI.getRegClassFromLLT(DefTy);
+ return RBI.constrainGenericRegister(DefReg, *DefRC, *MRI);
+}
+
+bool PISAInstructionSelector::selectGlobalValue(MachineInstr &I) const {
+ I.setDesc(TII.get(PISA::addrof_64b));
+
+ Register DefReg = I.getOperand(0).getReg();
+ const LLT DefTy = MRI->getType(DefReg);
+
+ const RegClassOrRegBank &RegClassOrBank = MRI->getRegClassOrRegBank(DefReg);
+ const TargetRegisterClass *DefRC =
+ RegClassOrBank.dyn_cast<const TargetRegisterClass *>();
+ if (!DefRC)
+ DefRC = TRI.getRegClassFromLLT(DefTy);
+
+ return RBI.constrainGenericRegister(DefReg, *DefRC, *MRI);
+}
+
+bool PISAInstructionSelector::selectPhiOrImplicitDef(MachineInstr &I) const {
+ MachineBasicBlock *BB = I.getParent();
+ MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
+
+ const Register DefReg = I.getOperand(0).getReg();
+ const LLT DefTy = MRI.getType(DefReg);
+
+ const RegClassOrRegBank &RegClassOrBank = MRI.getRegClassOrRegBank(DefReg);
+
+ const TargetRegisterClass *DefRC =
+ RegClassOrBank.dyn_cast<const TargetRegisterClass *>();
+
+ if (!DefRC)
+ DefRC = TRI.getRegClassFromLLT(DefTy);
+
+ unsigned Opcode = (I.getOpcode() == TargetOpcode::G_PHI)
+ ? TargetOpcode::PHI
+ : TargetOpcode::IMPLICIT_DEF;
+ I.setDesc(TII.get(Opcode));
+
+ return RBI.constrainGenericRegister(DefReg, *DefRC, MRI);
+}
+
+bool PISAInstructionSelector::selectAddSubWithOverflow(MachineInstr &I) const {
+ MachineBasicBlock *BB = I.getParent();
+ const DebugLoc &DL = I.getDebugLoc();
+
+ const bool IsAdd = I.getOpcode() == TargetOpcode::G_UADDO ||
+ I.getOpcode() == TargetOpcode::G_UADDE;
+ const bool HasCarryIn = I.getOpcode() == TargetOpcode::G_UADDE ||
+ I.getOpcode() == TargetOpcode::G_USUBE;
+
+ auto [DstReg, CarryOutReg, Src0Reg, Src1Reg] = I.getFirst4Regs();
+ const auto *DstRC = TRI.getRegClassFromLLT(MRI->getType(DstReg));
+ const auto *PredRC = &PISA::PredRegClass;
+
+ // Is there any reason to support 16b addc/subb?
+ assert(DstRC == &PISA::Reg32bRegClass);
+
+ auto Src0C = getIConstantVRegValWithLookThrough(Src0Reg, *MRI);
+ auto Src1C = getIConstantVRegValWithLookThrough(Src1Reg, *MRI);
+ unsigned RegReg = Src0C ? 0 : (Src1C ? 1 : 2);
+
+ const bool HasCarryOut = !HasCarryIn || !MRI->use_nodbg_empty(CarryOutReg);
+
+ unsigned PISAOps[] = {PISA::uaddc_co_32b_ir, PISA::uaddc_co_32b_ri,
+ PISA::uaddc_co_32b_rr, PISA::usubb_co_32b_ir,
+ PISA::usubb_co_32b_ri, PISA::usubb_co_32b_rr,
+ PISA::uaddc_ci_32b_ir, PISA::uaddc_ci_32b_ri,
+ PISA::uaddc_ci_32b_rr, PISA::usubb_ci_32b_ir,
+ PISA::usubb_ci_32b_ri, PISA::usubb_ci_32b_rr,
+ PISA::uaddc_ci_co_32b_ir, PISA::uaddc_ci_co_32b_ri,
+ PISA::uaddc_ci_co_32b_rr, PISA::usubb_ci_co_32b_ir,
+ PISA::usubb_ci_co_32b_ri, PISA::usubb_ci_co_32b_rr};
+
+ unsigned CarryOutOpc = PISAOps[(IsAdd ? 0 : 3) + RegReg];
+ unsigned CarryInOpc = PISAOps[6 + (IsAdd ? 0 : 3) + RegReg];
+ unsigned CarryInOutOpc = PISAOps[12 + (IsAdd ? 0 : 3) + RegReg];
+
+ unsigned Opc = (HasCarryIn && HasCarryOut)
+ ? CarryInOutOpc
+ : (HasCarryOut ? CarryOutOpc : CarryInOpc);
+
+ auto MIB = BuildMI(*BB, &I, DL, TII.get(Opc), DstReg);
+ if (HasCarryOut)
+ MIB.addDef(CarryOutReg);
+ if (Src0C)
+ MIB.addImm(Src0C->Value.getSExtValue());
+ else
+ MIB.add(I.getOperand(2));
+ if (Src1C && !Src0C)
+ MIB.addImm(Src1C->Value.getSExtValue());
+ else
+ MIB.add(I.getOperand(3...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/214378
More information about the llvm-branch-commits
mailing list