1480093f4SDimitry Andric //===- AMDGPUGlobalISelUtils.cpp ---------------------------------*- C++ -*-==//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric
9480093f4SDimitry Andric #include "AMDGPUGlobalISelUtils.h"
1081ad6265SDimitry Andric #include "GCNSubtarget.h"
11bdd1243dSDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
12480093f4SDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
13fe013be4SDimitry Andric #include "llvm/CodeGen/LowLevelType.h"
14480093f4SDimitry Andric #include "llvm/IR/Constants.h"
15480093f4SDimitry Andric
16480093f4SDimitry Andric using namespace llvm;
17480093f4SDimitry Andric using namespace MIPatternMatch;
18480093f4SDimitry Andric
19e8d8bef9SDimitry Andric std::pair<Register, unsigned>
getBaseWithConstantOffset(MachineRegisterInfo & MRI,Register Reg,GISelKnownBits * KnownBits,bool CheckNUW)20bdd1243dSDimitry Andric AMDGPU::getBaseWithConstantOffset(MachineRegisterInfo &MRI, Register Reg,
21*c9157d92SDimitry Andric GISelKnownBits *KnownBits, bool CheckNUW) {
22480093f4SDimitry Andric MachineInstr *Def = getDefIgnoringCopies(Reg, MRI);
23480093f4SDimitry Andric if (Def->getOpcode() == TargetOpcode::G_CONSTANT) {
24480093f4SDimitry Andric unsigned Offset;
25480093f4SDimitry Andric const MachineOperand &Op = Def->getOperand(1);
26480093f4SDimitry Andric if (Op.isImm())
27480093f4SDimitry Andric Offset = Op.getImm();
28480093f4SDimitry Andric else
29480093f4SDimitry Andric Offset = Op.getCImm()->getZExtValue();
30480093f4SDimitry Andric
31bdd1243dSDimitry Andric return std::pair(Register(), Offset);
32480093f4SDimitry Andric }
33480093f4SDimitry Andric
34480093f4SDimitry Andric int64_t Offset;
35480093f4SDimitry Andric if (Def->getOpcode() == TargetOpcode::G_ADD) {
36*c9157d92SDimitry Andric // A 32-bit (address + offset) should not cause unsigned 32-bit integer
37*c9157d92SDimitry Andric // wraparound, because s_load instructions perform the addition in 64 bits.
38*c9157d92SDimitry Andric if (CheckNUW && !Def->getFlag(MachineInstr::NoUWrap)) {
39*c9157d92SDimitry Andric assert(MRI.getType(Reg).getScalarSizeInBits() == 32);
40*c9157d92SDimitry Andric return std::pair(Reg, 0);
41*c9157d92SDimitry Andric }
42480093f4SDimitry Andric // TODO: Handle G_OR used for add case
43480093f4SDimitry Andric if (mi_match(Def->getOperand(2).getReg(), MRI, m_ICst(Offset)))
44bdd1243dSDimitry Andric return std::pair(Def->getOperand(1).getReg(), Offset);
45480093f4SDimitry Andric
46480093f4SDimitry Andric // FIXME: matcher should ignore copies
47480093f4SDimitry Andric if (mi_match(Def->getOperand(2).getReg(), MRI, m_Copy(m_ICst(Offset))))
48bdd1243dSDimitry Andric return std::pair(Def->getOperand(1).getReg(), Offset);
49480093f4SDimitry Andric }
50480093f4SDimitry Andric
51bdd1243dSDimitry Andric Register Base;
52bdd1243dSDimitry Andric if (KnownBits && mi_match(Reg, MRI, m_GOr(m_Reg(Base), m_ICst(Offset))) &&
53bdd1243dSDimitry Andric KnownBits->maskedValueIsZero(Base, APInt(32, Offset)))
54bdd1243dSDimitry Andric return std::pair(Base, Offset);
55bdd1243dSDimitry Andric
56fe6060f1SDimitry Andric // Handle G_PTRTOINT (G_PTR_ADD base, const) case
57fe6060f1SDimitry Andric if (Def->getOpcode() == TargetOpcode::G_PTRTOINT) {
58fe6060f1SDimitry Andric MachineInstr *Base;
59fe6060f1SDimitry Andric if (mi_match(Def->getOperand(1).getReg(), MRI,
60fe6060f1SDimitry Andric m_GPtrAdd(m_MInstr(Base), m_ICst(Offset)))) {
61fe6060f1SDimitry Andric // If Base was int converted to pointer, simply return int and offset.
62fe6060f1SDimitry Andric if (Base->getOpcode() == TargetOpcode::G_INTTOPTR)
63bdd1243dSDimitry Andric return std::pair(Base->getOperand(1).getReg(), Offset);
64fe6060f1SDimitry Andric
65fe6060f1SDimitry Andric // Register returned here will be of pointer type.
66bdd1243dSDimitry Andric return std::pair(Base->getOperand(0).getReg(), Offset);
67fe6060f1SDimitry Andric }
68fe6060f1SDimitry Andric }
69fe6060f1SDimitry Andric
70bdd1243dSDimitry Andric return std::pair(Reg, 0);
715ffd83dbSDimitry Andric }
7281ad6265SDimitry Andric
hasAtomicFaddRtnForTy(const GCNSubtarget & Subtarget,const LLT & Ty)7381ad6265SDimitry Andric bool AMDGPU::hasAtomicFaddRtnForTy(const GCNSubtarget &Subtarget,
7481ad6265SDimitry Andric const LLT &Ty) {
7581ad6265SDimitry Andric if (Ty == LLT::scalar(32))
7681ad6265SDimitry Andric return Subtarget.hasAtomicFaddRtnInsts();
7781ad6265SDimitry Andric if (Ty == LLT::fixed_vector(2, 16) || Ty == LLT::scalar(64))
7881ad6265SDimitry Andric return Subtarget.hasGFX90AInsts();
7981ad6265SDimitry Andric return false;
8081ad6265SDimitry Andric }
81