xref: /llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp (revision bd9145c8c21334e099d51b3e66f49d51d24931ee)
1f7bebc19SJanek van Oirschot //===- AMDGPUMCExpr.cpp - AMDGPU specific MC expression classes -----------===//
2f7bebc19SJanek van Oirschot //
3f7bebc19SJanek van Oirschot // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f7bebc19SJanek van Oirschot // See https://llvm.org/LICENSE.txt for license information.
5f7bebc19SJanek van Oirschot // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f7bebc19SJanek van Oirschot //
7f7bebc19SJanek van Oirschot //===----------------------------------------------------------------------===//
8f7bebc19SJanek van Oirschot 
9f7bebc19SJanek van Oirschot #include "AMDGPUMCExpr.h"
10d86b68afSJanek van Oirschot #include "GCNSubtarget.h"
11d86b68afSJanek van Oirschot #include "Utils/AMDGPUBaseInfo.h"
12d86b68afSJanek van Oirschot #include "llvm/IR/Function.h"
13bfce1aaeSJanek van Oirschot #include "llvm/MC/MCAsmInfo.h"
14f22af401SFangrui Song #include "llvm/MC/MCAssembler.h"
15f7bebc19SJanek van Oirschot #include "llvm/MC/MCContext.h"
16f7bebc19SJanek van Oirschot #include "llvm/MC/MCStreamer.h"
17f7bebc19SJanek van Oirschot #include "llvm/MC/MCSymbol.h"
18f7bebc19SJanek van Oirschot #include "llvm/MC/MCValue.h"
19bfce1aaeSJanek van Oirschot #include "llvm/Support/KnownBits.h"
20f7bebc19SJanek van Oirschot #include "llvm/Support/raw_ostream.h"
21f7bebc19SJanek van Oirschot #include <optional>
22f7bebc19SJanek van Oirschot 
23f7bebc19SJanek van Oirschot using namespace llvm;
24d86b68afSJanek van Oirschot using namespace llvm::AMDGPU;
25f7bebc19SJanek van Oirschot 
2613ed349cSIvan Kosarev AMDGPUMCExpr::AMDGPUMCExpr(VariantKind Kind, ArrayRef<const MCExpr *> Args,
27f7bebc19SJanek van Oirschot                            MCContext &Ctx)
28f7bebc19SJanek van Oirschot     : Kind(Kind), Ctx(Ctx) {
29f7bebc19SJanek van Oirschot   assert(Args.size() >= 1 && "Needs a minimum of one expression.");
3013ed349cSIvan Kosarev   assert(Kind != AGVK_None && "Cannot construct AMDGPUMCExpr of kind none.");
31f7bebc19SJanek van Oirschot 
32f7bebc19SJanek van Oirschot   // Allocating the variadic arguments through the same allocation mechanism
33f7bebc19SJanek van Oirschot   // that the object itself is allocated with so they end up in the same memory.
34f7bebc19SJanek van Oirschot   //
35f7bebc19SJanek van Oirschot   // Will result in an asan failure if allocated on the heap through standard
36f7bebc19SJanek van Oirschot   // allocation (e.g., through SmallVector's grow).
37f7bebc19SJanek van Oirschot   RawArgs = static_cast<const MCExpr **>(
38f7bebc19SJanek van Oirschot       Ctx.allocate(sizeof(const MCExpr *) * Args.size()));
39f7bebc19SJanek van Oirschot   std::uninitialized_copy(Args.begin(), Args.end(), RawArgs);
40f7bebc19SJanek van Oirschot   this->Args = ArrayRef<const MCExpr *>(RawArgs, Args.size());
41f7bebc19SJanek van Oirschot }
42f7bebc19SJanek van Oirschot 
4313ed349cSIvan Kosarev AMDGPUMCExpr::~AMDGPUMCExpr() { Ctx.deallocate(RawArgs); }
44f7bebc19SJanek van Oirschot 
4513ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::create(VariantKind Kind,
4613ed349cSIvan Kosarev                                          ArrayRef<const MCExpr *> Args,
47f7bebc19SJanek van Oirschot                                          MCContext &Ctx) {
4813ed349cSIvan Kosarev   return new (Ctx) AMDGPUMCExpr(Kind, Args, Ctx);
49f7bebc19SJanek van Oirschot }
50f7bebc19SJanek van Oirschot 
5113ed349cSIvan Kosarev const MCExpr *AMDGPUMCExpr::getSubExpr(size_t Index) const {
5213ed349cSIvan Kosarev   assert(Index < Args.size() && "Indexing out of bounds AMDGPUMCExpr sub-expr");
53f7bebc19SJanek van Oirschot   return Args[Index];
54f7bebc19SJanek van Oirschot }
55f7bebc19SJanek van Oirschot 
5613ed349cSIvan Kosarev void AMDGPUMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
57f7bebc19SJanek van Oirschot   switch (Kind) {
58f7bebc19SJanek van Oirschot   default:
5913ed349cSIvan Kosarev     llvm_unreachable("Unknown AMDGPUMCExpr kind.");
60f7bebc19SJanek van Oirschot   case AGVK_Or:
61f7bebc19SJanek van Oirschot     OS << "or(";
62f7bebc19SJanek van Oirschot     break;
63f7bebc19SJanek van Oirschot   case AGVK_Max:
64f7bebc19SJanek van Oirschot     OS << "max(";
65f7bebc19SJanek van Oirschot     break;
66d86b68afSJanek van Oirschot   case AGVK_ExtraSGPRs:
67d86b68afSJanek van Oirschot     OS << "extrasgprs(";
68d86b68afSJanek van Oirschot     break;
69d86b68afSJanek van Oirschot   case AGVK_TotalNumVGPRs:
70d86b68afSJanek van Oirschot     OS << "totalnumvgprs(";
71d86b68afSJanek van Oirschot     break;
72d86b68afSJanek van Oirschot   case AGVK_AlignTo:
73d86b68afSJanek van Oirschot     OS << "alignto(";
74d86b68afSJanek van Oirschot     break;
75d86b68afSJanek van Oirschot   case AGVK_Occupancy:
76d86b68afSJanek van Oirschot     OS << "occupancy(";
77d86b68afSJanek van Oirschot     break;
78f7bebc19SJanek van Oirschot   }
798d13e7b8SJay Foad   for (const auto *It = Args.begin(); It != Args.end(); ++It) {
80f7bebc19SJanek van Oirschot     (*It)->print(OS, MAI, /*InParens=*/false);
81f7bebc19SJanek van Oirschot     if ((It + 1) != Args.end())
82f7bebc19SJanek van Oirschot       OS << ", ";
83f7bebc19SJanek van Oirschot   }
84f7bebc19SJanek van Oirschot   OS << ')';
85f7bebc19SJanek van Oirschot }
86f7bebc19SJanek van Oirschot 
8713ed349cSIvan Kosarev static int64_t op(AMDGPUMCExpr::VariantKind Kind, int64_t Arg1, int64_t Arg2) {
88f7bebc19SJanek van Oirschot   switch (Kind) {
89f7bebc19SJanek van Oirschot   default:
9013ed349cSIvan Kosarev     llvm_unreachable("Unknown AMDGPUMCExpr kind.");
9113ed349cSIvan Kosarev   case AMDGPUMCExpr::AGVK_Max:
92f7bebc19SJanek van Oirschot     return std::max(Arg1, Arg2);
9313ed349cSIvan Kosarev   case AMDGPUMCExpr::AGVK_Or:
94f7bebc19SJanek van Oirschot     return Arg1 | Arg2;
95f7bebc19SJanek van Oirschot   }
96f7bebc19SJanek van Oirschot }
97f7bebc19SJanek van Oirschot 
98f22af401SFangrui Song bool AMDGPUMCExpr::evaluateExtraSGPRs(MCValue &Res, const MCAssembler *Asm,
99d86b68afSJanek van Oirschot                                       const MCFixup *Fixup) const {
100d86b68afSJanek van Oirschot   auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) {
101d86b68afSJanek van Oirschot     MCValue MCVal;
102e25e8003SFangrui Song     if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute())
103d86b68afSJanek van Oirschot       return false;
104d86b68afSJanek van Oirschot 
105d86b68afSJanek van Oirschot     ConstantValue = MCVal.getConstant();
106d86b68afSJanek van Oirschot     return true;
107d86b68afSJanek van Oirschot   };
108d86b68afSJanek van Oirschot 
109d86b68afSJanek van Oirschot   assert(Args.size() == 3 &&
11013ed349cSIvan Kosarev          "AMDGPUMCExpr Argument count incorrect for ExtraSGPRs");
111d86b68afSJanek van Oirschot   const MCSubtargetInfo *STI = Ctx.getSubtargetInfo();
112d86b68afSJanek van Oirschot   uint64_t VCCUsed = 0, FlatScrUsed = 0, XNACKUsed = 0;
113d86b68afSJanek van Oirschot 
114d86b68afSJanek van Oirschot   bool Success = TryGetMCExprValue(Args[2], XNACKUsed);
115d86b68afSJanek van Oirschot 
116d86b68afSJanek van Oirschot   assert(Success && "Arguments 3 for ExtraSGPRs should be a known constant");
117d86b68afSJanek van Oirschot   if (!Success || !TryGetMCExprValue(Args[0], VCCUsed) ||
118d86b68afSJanek van Oirschot       !TryGetMCExprValue(Args[1], FlatScrUsed))
119d86b68afSJanek van Oirschot     return false;
120d86b68afSJanek van Oirschot 
121d86b68afSJanek van Oirschot   uint64_t ExtraSGPRs = IsaInfo::getNumExtraSGPRs(
122d86b68afSJanek van Oirschot       STI, (bool)VCCUsed, (bool)FlatScrUsed, (bool)XNACKUsed);
123d86b68afSJanek van Oirschot   Res = MCValue::get(ExtraSGPRs);
124d86b68afSJanek van Oirschot   return true;
125d86b68afSJanek van Oirschot }
126d86b68afSJanek van Oirschot 
127f22af401SFangrui Song bool AMDGPUMCExpr::evaluateTotalNumVGPR(MCValue &Res, const MCAssembler *Asm,
128d86b68afSJanek van Oirschot                                         const MCFixup *Fixup) const {
129d86b68afSJanek van Oirschot   auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) {
130d86b68afSJanek van Oirschot     MCValue MCVal;
131e25e8003SFangrui Song     if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute())
132d86b68afSJanek van Oirschot       return false;
133d86b68afSJanek van Oirschot 
134d86b68afSJanek van Oirschot     ConstantValue = MCVal.getConstant();
135d86b68afSJanek van Oirschot     return true;
136d86b68afSJanek van Oirschot   };
137d86b68afSJanek van Oirschot   assert(Args.size() == 2 &&
13813ed349cSIvan Kosarev          "AMDGPUMCExpr Argument count incorrect for TotalNumVGPRs");
139d86b68afSJanek van Oirschot   const MCSubtargetInfo *STI = Ctx.getSubtargetInfo();
140d86b68afSJanek van Oirschot   uint64_t NumAGPR = 0, NumVGPR = 0;
141d86b68afSJanek van Oirschot 
142d86b68afSJanek van Oirschot   bool Has90AInsts = AMDGPU::isGFX90A(*STI);
143d86b68afSJanek van Oirschot 
144d86b68afSJanek van Oirschot   if (!TryGetMCExprValue(Args[0], NumAGPR) ||
145d86b68afSJanek van Oirschot       !TryGetMCExprValue(Args[1], NumVGPR))
146d86b68afSJanek van Oirschot     return false;
147d86b68afSJanek van Oirschot 
148d86b68afSJanek van Oirschot   uint64_t TotalNum = Has90AInsts && NumAGPR ? alignTo(NumVGPR, 4) + NumAGPR
149d86b68afSJanek van Oirschot                                              : std::max(NumVGPR, NumAGPR);
150d86b68afSJanek van Oirschot   Res = MCValue::get(TotalNum);
151d86b68afSJanek van Oirschot   return true;
152d86b68afSJanek van Oirschot }
153d86b68afSJanek van Oirschot 
154f22af401SFangrui Song bool AMDGPUMCExpr::evaluateAlignTo(MCValue &Res, const MCAssembler *Asm,
155d86b68afSJanek van Oirschot                                    const MCFixup *Fixup) const {
156d86b68afSJanek van Oirschot   auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) {
157d86b68afSJanek van Oirschot     MCValue MCVal;
158e25e8003SFangrui Song     if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute())
159d86b68afSJanek van Oirschot       return false;
160d86b68afSJanek van Oirschot 
161d86b68afSJanek van Oirschot     ConstantValue = MCVal.getConstant();
162d86b68afSJanek van Oirschot     return true;
163d86b68afSJanek van Oirschot   };
164d86b68afSJanek van Oirschot 
165d86b68afSJanek van Oirschot   assert(Args.size() == 2 &&
16613ed349cSIvan Kosarev          "AMDGPUMCExpr Argument count incorrect for AlignTo");
167d86b68afSJanek van Oirschot   uint64_t Value = 0, Align = 0;
168d86b68afSJanek van Oirschot   if (!TryGetMCExprValue(Args[0], Value) || !TryGetMCExprValue(Args[1], Align))
169d86b68afSJanek van Oirschot     return false;
170d86b68afSJanek van Oirschot 
171d86b68afSJanek van Oirschot   Res = MCValue::get(alignTo(Value, Align));
172d86b68afSJanek van Oirschot   return true;
173d86b68afSJanek van Oirschot }
174d86b68afSJanek van Oirschot 
175f22af401SFangrui Song bool AMDGPUMCExpr::evaluateOccupancy(MCValue &Res, const MCAssembler *Asm,
176d86b68afSJanek van Oirschot                                      const MCFixup *Fixup) const {
177d86b68afSJanek van Oirschot   auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) {
178d86b68afSJanek van Oirschot     MCValue MCVal;
179e25e8003SFangrui Song     if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute())
180d86b68afSJanek van Oirschot       return false;
181d86b68afSJanek van Oirschot 
182d86b68afSJanek van Oirschot     ConstantValue = MCVal.getConstant();
183d86b68afSJanek van Oirschot     return true;
184d86b68afSJanek van Oirschot   };
185d86b68afSJanek van Oirschot   assert(Args.size() == 7 &&
18613ed349cSIvan Kosarev          "AMDGPUMCExpr Argument count incorrect for Occupancy");
187d86b68afSJanek van Oirschot   uint64_t InitOccupancy, MaxWaves, Granule, TargetTotalNumVGPRs, Generation,
188d86b68afSJanek van Oirschot       NumSGPRs, NumVGPRs;
189d86b68afSJanek van Oirschot 
190d86b68afSJanek van Oirschot   bool Success = true;
191d86b68afSJanek van Oirschot   Success &= TryGetMCExprValue(Args[0], MaxWaves);
192d86b68afSJanek van Oirschot   Success &= TryGetMCExprValue(Args[1], Granule);
193d86b68afSJanek van Oirschot   Success &= TryGetMCExprValue(Args[2], TargetTotalNumVGPRs);
194d86b68afSJanek van Oirschot   Success &= TryGetMCExprValue(Args[3], Generation);
195d86b68afSJanek van Oirschot   Success &= TryGetMCExprValue(Args[4], InitOccupancy);
196d86b68afSJanek van Oirschot 
197d86b68afSJanek van Oirschot   assert(Success && "Arguments 1 to 5 for Occupancy should be known constants");
198d86b68afSJanek van Oirschot 
199d86b68afSJanek van Oirschot   if (!Success || !TryGetMCExprValue(Args[5], NumSGPRs) ||
200d86b68afSJanek van Oirschot       !TryGetMCExprValue(Args[6], NumVGPRs))
201d86b68afSJanek van Oirschot     return false;
202d86b68afSJanek van Oirschot 
203d86b68afSJanek van Oirschot   unsigned Occupancy = InitOccupancy;
204d86b68afSJanek van Oirschot   if (NumSGPRs)
205d86b68afSJanek van Oirschot     Occupancy = std::min(
206d86b68afSJanek van Oirschot         Occupancy, IsaInfo::getOccupancyWithNumSGPRs(
207d86b68afSJanek van Oirschot                        NumSGPRs, MaxWaves,
208d86b68afSJanek van Oirschot                        static_cast<AMDGPUSubtarget::Generation>(Generation)));
209d86b68afSJanek van Oirschot   if (NumVGPRs)
210d86b68afSJanek van Oirschot     Occupancy = std::min(Occupancy,
211d86b68afSJanek van Oirschot                          IsaInfo::getNumWavesPerEUWithNumVGPRs(
212d86b68afSJanek van Oirschot                              NumVGPRs, Granule, MaxWaves, TargetTotalNumVGPRs));
213d86b68afSJanek van Oirschot 
214d86b68afSJanek van Oirschot   Res = MCValue::get(Occupancy);
215d86b68afSJanek van Oirschot   return true;
216d86b68afSJanek van Oirschot }
217d86b68afSJanek van Oirschot 
21813ed349cSIvan Kosarev bool AMDGPUMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
219e25e8003SFangrui Song                                              const MCAssembler *Asm,
22013ed349cSIvan Kosarev                                              const MCFixup *Fixup) const {
221f7bebc19SJanek van Oirschot   std::optional<int64_t> Total;
222d86b68afSJanek van Oirschot   switch (Kind) {
223d86b68afSJanek van Oirschot   default:
224d86b68afSJanek van Oirschot     break;
225d86b68afSJanek van Oirschot   case AGVK_ExtraSGPRs:
226f22af401SFangrui Song     return evaluateExtraSGPRs(Res, Asm, Fixup);
227d86b68afSJanek van Oirschot   case AGVK_AlignTo:
228f22af401SFangrui Song     return evaluateAlignTo(Res, Asm, Fixup);
229d86b68afSJanek van Oirschot   case AGVK_TotalNumVGPRs:
230f22af401SFangrui Song     return evaluateTotalNumVGPR(Res, Asm, Fixup);
231d86b68afSJanek van Oirschot   case AGVK_Occupancy:
232f22af401SFangrui Song     return evaluateOccupancy(Res, Asm, Fixup);
233d86b68afSJanek van Oirschot   }
234d86b68afSJanek van Oirschot 
235f7bebc19SJanek van Oirschot   for (const MCExpr *Arg : Args) {
236f7bebc19SJanek van Oirschot     MCValue ArgRes;
237e25e8003SFangrui Song     if (!Arg->evaluateAsRelocatable(ArgRes, Asm, Fixup) || !ArgRes.isAbsolute())
238f7bebc19SJanek van Oirschot       return false;
239f7bebc19SJanek van Oirschot 
240f7bebc19SJanek van Oirschot     if (!Total.has_value())
241f7bebc19SJanek van Oirschot       Total = ArgRes.getConstant();
242f7bebc19SJanek van Oirschot     Total = op(Kind, *Total, ArgRes.getConstant());
243f7bebc19SJanek van Oirschot   }
244f7bebc19SJanek van Oirschot 
245f7bebc19SJanek van Oirschot   Res = MCValue::get(*Total);
246f7bebc19SJanek van Oirschot   return true;
247f7bebc19SJanek van Oirschot }
248f7bebc19SJanek van Oirschot 
24913ed349cSIvan Kosarev void AMDGPUMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
250f7bebc19SJanek van Oirschot   for (const MCExpr *Arg : Args)
251f7bebc19SJanek van Oirschot     Streamer.visitUsedExpr(*Arg);
252f7bebc19SJanek van Oirschot }
253f7bebc19SJanek van Oirschot 
25413ed349cSIvan Kosarev MCFragment *AMDGPUMCExpr::findAssociatedFragment() const {
255f7bebc19SJanek van Oirschot   for (const MCExpr *Arg : Args) {
256f7bebc19SJanek van Oirschot     if (Arg->findAssociatedFragment())
257f7bebc19SJanek van Oirschot       return Arg->findAssociatedFragment();
258f7bebc19SJanek van Oirschot   }
259f7bebc19SJanek van Oirschot   return nullptr;
260f7bebc19SJanek van Oirschot }
261d86b68afSJanek van Oirschot 
262d86b68afSJanek van Oirschot /// Allow delayed MCExpr resolve of ExtraSGPRs (in case VCCUsed or FlatScrUsed
263d86b68afSJanek van Oirschot /// are unresolvable but needed for further MCExprs). Derived from
264d86b68afSJanek van Oirschot /// implementation of IsaInfo::getNumExtraSGPRs in AMDGPUBaseInfo.cpp.
265d86b68afSJanek van Oirschot ///
26613ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::createExtraSGPRs(const MCExpr *VCCUsed,
267d86b68afSJanek van Oirschot                                                    const MCExpr *FlatScrUsed,
26813ed349cSIvan Kosarev                                                    bool XNACKUsed,
26913ed349cSIvan Kosarev                                                    MCContext &Ctx) {
270d86b68afSJanek van Oirschot 
271d86b68afSJanek van Oirschot   return create(AGVK_ExtraSGPRs,
272d86b68afSJanek van Oirschot                 {VCCUsed, FlatScrUsed, MCConstantExpr::create(XNACKUsed, Ctx)},
273d86b68afSJanek van Oirschot                 Ctx);
274d86b68afSJanek van Oirschot }
275d86b68afSJanek van Oirschot 
27613ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::createTotalNumVGPR(const MCExpr *NumAGPR,
27713ed349cSIvan Kosarev                                                      const MCExpr *NumVGPR,
27813ed349cSIvan Kosarev                                                      MCContext &Ctx) {
279d86b68afSJanek van Oirschot   return create(AGVK_TotalNumVGPRs, {NumAGPR, NumVGPR}, Ctx);
280d86b68afSJanek van Oirschot }
281d86b68afSJanek van Oirschot 
282d86b68afSJanek van Oirschot /// Mimics GCNSubtarget::computeOccupancy for MCExpr.
283d86b68afSJanek van Oirschot ///
284d86b68afSJanek van Oirschot /// Remove dependency on GCNSubtarget and depend only only the necessary values
285d86b68afSJanek van Oirschot /// for said occupancy computation. Should match computeOccupancy implementation
286d86b68afSJanek van Oirschot /// without passing \p STM on.
28713ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::createOccupancy(unsigned InitOcc,
28813ed349cSIvan Kosarev                                                   const MCExpr *NumSGPRs,
289d86b68afSJanek van Oirschot                                                   const MCExpr *NumVGPRs,
29013ed349cSIvan Kosarev                                                   const GCNSubtarget &STM,
29113ed349cSIvan Kosarev                                                   MCContext &Ctx) {
292d86b68afSJanek van Oirschot   unsigned MaxWaves = IsaInfo::getMaxWavesPerEU(&STM);
293d86b68afSJanek van Oirschot   unsigned Granule = IsaInfo::getVGPRAllocGranule(&STM);
294d86b68afSJanek van Oirschot   unsigned TargetTotalNumVGPRs = IsaInfo::getTotalNumVGPRs(&STM);
295d86b68afSJanek van Oirschot   unsigned Generation = STM.getGeneration();
296d86b68afSJanek van Oirschot 
297d86b68afSJanek van Oirschot   auto CreateExpr = [&Ctx](unsigned Value) {
298d86b68afSJanek van Oirschot     return MCConstantExpr::create(Value, Ctx);
299d86b68afSJanek van Oirschot   };
300d86b68afSJanek van Oirschot 
301d86b68afSJanek van Oirschot   return create(AGVK_Occupancy,
302d86b68afSJanek van Oirschot                 {CreateExpr(MaxWaves), CreateExpr(Granule),
303d86b68afSJanek van Oirschot                  CreateExpr(TargetTotalNumVGPRs), CreateExpr(Generation),
304d86b68afSJanek van Oirschot                  CreateExpr(InitOcc), NumSGPRs, NumVGPRs},
305d86b68afSJanek van Oirschot                 Ctx);
306d86b68afSJanek van Oirschot }
307bfce1aaeSJanek van Oirschot 
308*bd9145c8SJanek van Oirschot bool AMDGPUMCExpr::isSymbolUsedInExpression(const MCSymbol *Sym) const {
309*bd9145c8SJanek van Oirschot   for (const MCExpr *E : getArgs()) {
310*bd9145c8SJanek van Oirschot     if (E->isSymbolUsedInExpression(Sym))
311*bd9145c8SJanek van Oirschot       return true;
312*bd9145c8SJanek van Oirschot   }
313*bd9145c8SJanek van Oirschot   return false;
314*bd9145c8SJanek van Oirschot }
315*bd9145c8SJanek van Oirschot 
316bfce1aaeSJanek van Oirschot static KnownBits fromOptionalToKnownBits(std::optional<bool> CompareResult) {
317bfce1aaeSJanek van Oirschot   static constexpr unsigned BitWidth = 64;
318bfce1aaeSJanek van Oirschot   const APInt True(BitWidth, 1);
319bfce1aaeSJanek van Oirschot   const APInt False(BitWidth, 0);
320bfce1aaeSJanek van Oirschot   if (CompareResult) {
321bfce1aaeSJanek van Oirschot     return *CompareResult ? KnownBits::makeConstant(True)
322bfce1aaeSJanek van Oirschot                           : KnownBits::makeConstant(False);
323bfce1aaeSJanek van Oirschot   }
324bfce1aaeSJanek van Oirschot 
325bfce1aaeSJanek van Oirschot   KnownBits UnknownBool(/*BitWidth=*/1);
326bfce1aaeSJanek van Oirschot   return UnknownBool.zext(BitWidth);
327bfce1aaeSJanek van Oirschot }
328bfce1aaeSJanek van Oirschot 
329bfce1aaeSJanek van Oirschot using KnownBitsMap = DenseMap<const MCExpr *, KnownBits>;
330bfce1aaeSJanek van Oirschot static void knownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM,
331bfce1aaeSJanek van Oirschot                                unsigned Depth = 0);
332bfce1aaeSJanek van Oirschot 
333bfce1aaeSJanek van Oirschot static void binaryOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM,
334bfce1aaeSJanek van Oirschot                                        unsigned Depth) {
335bfce1aaeSJanek van Oirschot   static constexpr unsigned BitWidth = 64;
336bfce1aaeSJanek van Oirschot   const MCBinaryExpr *BExpr = cast<MCBinaryExpr>(Expr);
337bfce1aaeSJanek van Oirschot   const MCExpr *LHS = BExpr->getLHS();
338bfce1aaeSJanek van Oirschot   const MCExpr *RHS = BExpr->getRHS();
339bfce1aaeSJanek van Oirschot 
340bfce1aaeSJanek van Oirschot   knownBitsMapHelper(LHS, KBM, Depth + 1);
341bfce1aaeSJanek van Oirschot   knownBitsMapHelper(RHS, KBM, Depth + 1);
342bfce1aaeSJanek van Oirschot   KnownBits LHSKnown = KBM[LHS];
343bfce1aaeSJanek van Oirschot   KnownBits RHSKnown = KBM[RHS];
344bfce1aaeSJanek van Oirschot 
345bfce1aaeSJanek van Oirschot   switch (BExpr->getOpcode()) {
346bfce1aaeSJanek van Oirschot   default:
347bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits(BitWidth);
348bfce1aaeSJanek van Oirschot     return;
349bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Add:
350bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::add(LHSKnown, RHSKnown);
351bfce1aaeSJanek van Oirschot     return;
352bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::And:
353bfce1aaeSJanek van Oirschot     KBM[Expr] = LHSKnown & RHSKnown;
354bfce1aaeSJanek van Oirschot     return;
355bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Div:
356bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::sdiv(LHSKnown, RHSKnown);
357bfce1aaeSJanek van Oirschot     return;
358bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::EQ: {
359bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes = KnownBits::eq(LHSKnown, RHSKnown);
360bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
361bfce1aaeSJanek van Oirschot     return;
362bfce1aaeSJanek van Oirschot   }
363bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::NE: {
364bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes = KnownBits::ne(LHSKnown, RHSKnown);
365bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
366bfce1aaeSJanek van Oirschot     return;
367bfce1aaeSJanek van Oirschot   }
368bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::GT: {
369bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes = KnownBits::sgt(LHSKnown, RHSKnown);
370bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
371bfce1aaeSJanek van Oirschot     return;
372bfce1aaeSJanek van Oirschot   }
373bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::GTE: {
374bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes = KnownBits::sge(LHSKnown, RHSKnown);
375bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
376bfce1aaeSJanek van Oirschot     return;
377bfce1aaeSJanek van Oirschot   }
378bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::LAnd: {
379bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes;
380bfce1aaeSJanek van Oirschot     const APInt False(BitWidth, 0);
381bfce1aaeSJanek van Oirschot     std::optional<bool> LHSBool =
382bfce1aaeSJanek van Oirschot         KnownBits::ne(LHSKnown, KnownBits::makeConstant(False));
383bfce1aaeSJanek van Oirschot     std::optional<bool> RHSBool =
384bfce1aaeSJanek van Oirschot         KnownBits::ne(RHSKnown, KnownBits::makeConstant(False));
385bfce1aaeSJanek van Oirschot     if (LHSBool && RHSBool)
386bfce1aaeSJanek van Oirschot       CompareRes = *LHSBool && *RHSBool;
387bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
388bfce1aaeSJanek van Oirschot     return;
389bfce1aaeSJanek van Oirschot   }
390bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::LOr: {
391bfce1aaeSJanek van Oirschot     const APInt False(BitWidth, 0);
392bfce1aaeSJanek van Oirschot     KnownBits Bits = LHSKnown | RHSKnown;
393bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes =
394bfce1aaeSJanek van Oirschot         KnownBits::ne(Bits, KnownBits::makeConstant(False));
395bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
396bfce1aaeSJanek van Oirschot     return;
397bfce1aaeSJanek van Oirschot   }
398bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::LT: {
399bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes = KnownBits::slt(LHSKnown, RHSKnown);
400bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
401bfce1aaeSJanek van Oirschot     return;
402bfce1aaeSJanek van Oirschot   }
403bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::LTE: {
404bfce1aaeSJanek van Oirschot     std::optional<bool> CompareRes = KnownBits::sle(LHSKnown, RHSKnown);
405bfce1aaeSJanek van Oirschot     KBM[Expr] = fromOptionalToKnownBits(CompareRes);
406bfce1aaeSJanek van Oirschot     return;
407bfce1aaeSJanek van Oirschot   }
408bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Mod:
409bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::srem(LHSKnown, RHSKnown);
410bfce1aaeSJanek van Oirschot     return;
411bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Mul:
412bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::mul(LHSKnown, RHSKnown);
413bfce1aaeSJanek van Oirschot     return;
414bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Or:
415bfce1aaeSJanek van Oirschot     KBM[Expr] = LHSKnown | RHSKnown;
416bfce1aaeSJanek van Oirschot     return;
417bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Shl:
418bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::shl(LHSKnown, RHSKnown);
419bfce1aaeSJanek van Oirschot     return;
420bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::AShr:
421bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::ashr(LHSKnown, RHSKnown);
422bfce1aaeSJanek van Oirschot     return;
423bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::LShr:
424bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::lshr(LHSKnown, RHSKnown);
425bfce1aaeSJanek van Oirschot     return;
426bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Sub:
427bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::sub(LHSKnown, RHSKnown);
428bfce1aaeSJanek van Oirschot     return;
429bfce1aaeSJanek van Oirschot   case MCBinaryExpr::Opcode::Xor:
430bfce1aaeSJanek van Oirschot     KBM[Expr] = LHSKnown ^ RHSKnown;
431bfce1aaeSJanek van Oirschot     return;
432bfce1aaeSJanek van Oirschot   }
433bfce1aaeSJanek van Oirschot }
434bfce1aaeSJanek van Oirschot 
435bfce1aaeSJanek van Oirschot static void unaryOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM,
436bfce1aaeSJanek van Oirschot                                       unsigned Depth) {
437bfce1aaeSJanek van Oirschot   static constexpr unsigned BitWidth = 64;
438bfce1aaeSJanek van Oirschot   const MCUnaryExpr *UExpr = cast<MCUnaryExpr>(Expr);
439bfce1aaeSJanek van Oirschot   knownBitsMapHelper(UExpr->getSubExpr(), KBM, Depth + 1);
440bfce1aaeSJanek van Oirschot   KnownBits KB = KBM[UExpr->getSubExpr()];
441bfce1aaeSJanek van Oirschot 
442bfce1aaeSJanek van Oirschot   switch (UExpr->getOpcode()) {
443bfce1aaeSJanek van Oirschot   default:
444bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits(BitWidth);
445bfce1aaeSJanek van Oirschot     return;
446bfce1aaeSJanek van Oirschot   case MCUnaryExpr::Opcode::Minus: {
447bfce1aaeSJanek van Oirschot     KB.makeNegative();
448bfce1aaeSJanek van Oirschot     KBM[Expr] = KB;
449bfce1aaeSJanek van Oirschot     return;
450bfce1aaeSJanek van Oirschot   }
451bfce1aaeSJanek van Oirschot   case MCUnaryExpr::Opcode::Not: {
452bfce1aaeSJanek van Oirschot     KnownBits AllOnes(BitWidth);
453bfce1aaeSJanek van Oirschot     AllOnes.setAllOnes();
454bfce1aaeSJanek van Oirschot     KBM[Expr] = KB ^ AllOnes;
455bfce1aaeSJanek van Oirschot     return;
456bfce1aaeSJanek van Oirschot   }
457bfce1aaeSJanek van Oirschot   case MCUnaryExpr::Opcode::Plus: {
458bfce1aaeSJanek van Oirschot     KB.makeNonNegative();
459bfce1aaeSJanek van Oirschot     KBM[Expr] = KB;
460bfce1aaeSJanek van Oirschot     return;
461bfce1aaeSJanek van Oirschot   }
462bfce1aaeSJanek van Oirschot   }
463bfce1aaeSJanek van Oirschot }
464bfce1aaeSJanek van Oirschot 
465bfce1aaeSJanek van Oirschot static void targetOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM,
466bfce1aaeSJanek van Oirschot                                        unsigned Depth) {
467bfce1aaeSJanek van Oirschot   static constexpr unsigned BitWidth = 64;
468bfce1aaeSJanek van Oirschot   const AMDGPUMCExpr *AGVK = cast<AMDGPUMCExpr>(Expr);
469bfce1aaeSJanek van Oirschot 
470bfce1aaeSJanek van Oirschot   switch (AGVK->getKind()) {
471bfce1aaeSJanek van Oirschot   default:
472bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits(BitWidth);
473bfce1aaeSJanek van Oirschot     return;
474bfce1aaeSJanek van Oirschot   case AMDGPUMCExpr::VariantKind::AGVK_Or: {
475bfce1aaeSJanek van Oirschot     knownBitsMapHelper(AGVK->getSubExpr(0), KBM, Depth + 1);
476bfce1aaeSJanek van Oirschot     KnownBits KB = KBM[AGVK->getSubExpr(0)];
477bfce1aaeSJanek van Oirschot     for (const MCExpr *Arg : AGVK->getArgs()) {
478bfce1aaeSJanek van Oirschot       knownBitsMapHelper(Arg, KBM, Depth + 1);
479bfce1aaeSJanek van Oirschot       KB |= KBM[Arg];
480bfce1aaeSJanek van Oirschot     }
481bfce1aaeSJanek van Oirschot     KBM[Expr] = KB;
482bfce1aaeSJanek van Oirschot     return;
483bfce1aaeSJanek van Oirschot   }
484bfce1aaeSJanek van Oirschot   case AMDGPUMCExpr::VariantKind::AGVK_Max: {
485bfce1aaeSJanek van Oirschot     knownBitsMapHelper(AGVK->getSubExpr(0), KBM, Depth + 1);
486bfce1aaeSJanek van Oirschot     KnownBits KB = KBM[AGVK->getSubExpr(0)];
487bfce1aaeSJanek van Oirschot     for (const MCExpr *Arg : AGVK->getArgs()) {
488bfce1aaeSJanek van Oirschot       knownBitsMapHelper(Arg, KBM, Depth + 1);
489bfce1aaeSJanek van Oirschot       KB = KnownBits::umax(KB, KBM[Arg]);
490bfce1aaeSJanek van Oirschot     }
491bfce1aaeSJanek van Oirschot     KBM[Expr] = KB;
492bfce1aaeSJanek van Oirschot     return;
493bfce1aaeSJanek van Oirschot   }
494bfce1aaeSJanek van Oirschot   case AMDGPUMCExpr::VariantKind::AGVK_ExtraSGPRs:
495bfce1aaeSJanek van Oirschot   case AMDGPUMCExpr::VariantKind::AGVK_TotalNumVGPRs:
496bfce1aaeSJanek van Oirschot   case AMDGPUMCExpr::VariantKind::AGVK_AlignTo:
497bfce1aaeSJanek van Oirschot   case AMDGPUMCExpr::VariantKind::AGVK_Occupancy: {
498bfce1aaeSJanek van Oirschot     int64_t Val;
499bfce1aaeSJanek van Oirschot     if (AGVK->evaluateAsAbsolute(Val)) {
500bfce1aaeSJanek van Oirschot       APInt APValue(BitWidth, Val);
501bfce1aaeSJanek van Oirschot       KBM[Expr] = KnownBits::makeConstant(APValue);
502bfce1aaeSJanek van Oirschot       return;
503bfce1aaeSJanek van Oirschot     }
504bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits(BitWidth);
505bfce1aaeSJanek van Oirschot     return;
506bfce1aaeSJanek van Oirschot   }
507bfce1aaeSJanek van Oirschot   }
508bfce1aaeSJanek van Oirschot }
509bfce1aaeSJanek van Oirschot 
510bfce1aaeSJanek van Oirschot static void knownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM,
511bfce1aaeSJanek van Oirschot                                unsigned Depth) {
512bfce1aaeSJanek van Oirschot   static constexpr unsigned BitWidth = 64;
513bfce1aaeSJanek van Oirschot 
514bfce1aaeSJanek van Oirschot   int64_t Val;
515bfce1aaeSJanek van Oirschot   if (Expr->evaluateAsAbsolute(Val)) {
516bfce1aaeSJanek van Oirschot     APInt APValue(BitWidth, Val, /*isSigned=*/true);
517bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::makeConstant(APValue);
518bfce1aaeSJanek van Oirschot     return;
519bfce1aaeSJanek van Oirschot   }
520bfce1aaeSJanek van Oirschot 
521bfce1aaeSJanek van Oirschot   if (Depth == 16) {
522bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits(BitWidth);
523bfce1aaeSJanek van Oirschot     return;
524bfce1aaeSJanek van Oirschot   }
525bfce1aaeSJanek van Oirschot 
526bfce1aaeSJanek van Oirschot   switch (Expr->getKind()) {
527bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::Binary: {
528bfce1aaeSJanek van Oirschot     binaryOpKnownBitsMapHelper(Expr, KBM, Depth);
529bfce1aaeSJanek van Oirschot     return;
530bfce1aaeSJanek van Oirschot   }
531bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::Constant: {
532bfce1aaeSJanek van Oirschot     const MCConstantExpr *CE = cast<MCConstantExpr>(Expr);
533bfce1aaeSJanek van Oirschot     APInt APValue(BitWidth, CE->getValue(), /*isSigned=*/true);
534bfce1aaeSJanek van Oirschot     KBM[Expr] = KnownBits::makeConstant(APValue);
535bfce1aaeSJanek van Oirschot     return;
536bfce1aaeSJanek van Oirschot   }
537bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::SymbolRef: {
538bfce1aaeSJanek van Oirschot     const MCSymbolRefExpr *RExpr = cast<MCSymbolRefExpr>(Expr);
539bfce1aaeSJanek van Oirschot     const MCSymbol &Sym = RExpr->getSymbol();
540bfce1aaeSJanek van Oirschot     if (!Sym.isVariable()) {
541bfce1aaeSJanek van Oirschot       KBM[Expr] = KnownBits(BitWidth);
542bfce1aaeSJanek van Oirschot       return;
543bfce1aaeSJanek van Oirschot     }
544bfce1aaeSJanek van Oirschot 
545bfce1aaeSJanek van Oirschot     // Variable value retrieval is not for actual use but only for knownbits
546bfce1aaeSJanek van Oirschot     // analysis.
547a18826d7SJanek van Oirschot     const MCExpr *SymVal = Sym.getVariableValue(/*setUsed=*/false);
548a18826d7SJanek van Oirschot     knownBitsMapHelper(SymVal, KBM, Depth + 1);
549a18826d7SJanek van Oirschot 
550a18826d7SJanek van Oirschot     // Explicitly copy-construct so that there exists a local KnownBits in case
551a18826d7SJanek van Oirschot     // KBM[SymVal] gets invalidated after a potential growth through KBM[Expr].
552a18826d7SJanek van Oirschot     KBM[Expr] = KnownBits(KBM[SymVal]);
553bfce1aaeSJanek van Oirschot     return;
554bfce1aaeSJanek van Oirschot   }
555bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::Unary: {
556bfce1aaeSJanek van Oirschot     unaryOpKnownBitsMapHelper(Expr, KBM, Depth);
557bfce1aaeSJanek van Oirschot     return;
558bfce1aaeSJanek van Oirschot   }
559bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::Target: {
560bfce1aaeSJanek van Oirschot     targetOpKnownBitsMapHelper(Expr, KBM, Depth);
561bfce1aaeSJanek van Oirschot     return;
562bfce1aaeSJanek van Oirschot   }
563bfce1aaeSJanek van Oirschot   }
564bfce1aaeSJanek van Oirschot }
565bfce1aaeSJanek van Oirschot 
566bfce1aaeSJanek van Oirschot static const MCExpr *tryFoldHelper(const MCExpr *Expr, KnownBitsMap &KBM,
567bfce1aaeSJanek van Oirschot                                    MCContext &Ctx) {
568bfce1aaeSJanek van Oirschot   if (!KBM.count(Expr))
569bfce1aaeSJanek van Oirschot     return Expr;
570bfce1aaeSJanek van Oirschot 
571bfce1aaeSJanek van Oirschot   auto ValueCheckKnownBits = [](KnownBits &KB, unsigned Value) -> bool {
572bfce1aaeSJanek van Oirschot     if (!KB.isConstant())
573bfce1aaeSJanek van Oirschot       return false;
574bfce1aaeSJanek van Oirschot 
575bfce1aaeSJanek van Oirschot     return Value == KB.getConstant();
576bfce1aaeSJanek van Oirschot   };
577bfce1aaeSJanek van Oirschot 
578bfce1aaeSJanek van Oirschot   if (Expr->getKind() == MCExpr::ExprKind::Constant)
579bfce1aaeSJanek van Oirschot     return Expr;
580bfce1aaeSJanek van Oirschot 
581bfce1aaeSJanek van Oirschot   // Resolving unary operations to constants may make the value more ambiguous.
582bfce1aaeSJanek van Oirschot   // For example, `~62` becomes `-63`; however, to me it's more ambiguous if a
583bfce1aaeSJanek van Oirschot   // bit mask value is represented through a negative number.
584bfce1aaeSJanek van Oirschot   if (Expr->getKind() != MCExpr::ExprKind::Unary) {
585bfce1aaeSJanek van Oirschot     if (KBM[Expr].isConstant()) {
586bfce1aaeSJanek van Oirschot       APInt ConstVal = KBM[Expr].getConstant();
587bfce1aaeSJanek van Oirschot       return MCConstantExpr::create(ConstVal.getSExtValue(), Ctx);
588bfce1aaeSJanek van Oirschot     }
589bfce1aaeSJanek van Oirschot 
590bfce1aaeSJanek van Oirschot     int64_t EvalValue;
591bfce1aaeSJanek van Oirschot     if (Expr->evaluateAsAbsolute(EvalValue))
592bfce1aaeSJanek van Oirschot       return MCConstantExpr::create(EvalValue, Ctx);
593bfce1aaeSJanek van Oirschot   }
594bfce1aaeSJanek van Oirschot 
595bfce1aaeSJanek van Oirschot   switch (Expr->getKind()) {
596bfce1aaeSJanek van Oirschot   default:
597bfce1aaeSJanek van Oirschot     return Expr;
598bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::Binary: {
599bfce1aaeSJanek van Oirschot     const MCBinaryExpr *BExpr = cast<MCBinaryExpr>(Expr);
600bfce1aaeSJanek van Oirschot     const MCExpr *LHS = BExpr->getLHS();
601bfce1aaeSJanek van Oirschot     const MCExpr *RHS = BExpr->getRHS();
602bfce1aaeSJanek van Oirschot 
603bfce1aaeSJanek van Oirschot     switch (BExpr->getOpcode()) {
604bfce1aaeSJanek van Oirschot     default:
605bfce1aaeSJanek van Oirschot       return Expr;
606bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::Sub: {
607bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[RHS], 0))
608bfce1aaeSJanek van Oirschot         return tryFoldHelper(LHS, KBM, Ctx);
609bfce1aaeSJanek van Oirschot       break;
610bfce1aaeSJanek van Oirschot     }
611bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::Add:
612bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::Or: {
613bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[LHS], 0))
614bfce1aaeSJanek van Oirschot         return tryFoldHelper(RHS, KBM, Ctx);
615bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[RHS], 0))
616bfce1aaeSJanek van Oirschot         return tryFoldHelper(LHS, KBM, Ctx);
617bfce1aaeSJanek van Oirschot       break;
618bfce1aaeSJanek van Oirschot     }
619bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::Mul: {
620bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[LHS], 1))
621bfce1aaeSJanek van Oirschot         return tryFoldHelper(RHS, KBM, Ctx);
622bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[RHS], 1))
623bfce1aaeSJanek van Oirschot         return tryFoldHelper(LHS, KBM, Ctx);
624bfce1aaeSJanek van Oirschot       break;
625bfce1aaeSJanek van Oirschot     }
626bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::Shl:
627bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::AShr:
628bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::LShr: {
629bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[RHS], 0))
630bfce1aaeSJanek van Oirschot         return tryFoldHelper(LHS, KBM, Ctx);
631bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[LHS], 0))
632bfce1aaeSJanek van Oirschot         return MCConstantExpr::create(0, Ctx);
633bfce1aaeSJanek van Oirschot       break;
634bfce1aaeSJanek van Oirschot     }
635bfce1aaeSJanek van Oirschot     case MCBinaryExpr::Opcode::And: {
636bfce1aaeSJanek van Oirschot       if (ValueCheckKnownBits(KBM[LHS], 0) || ValueCheckKnownBits(KBM[RHS], 0))
637bfce1aaeSJanek van Oirschot         return MCConstantExpr::create(0, Ctx);
638bfce1aaeSJanek van Oirschot       break;
639bfce1aaeSJanek van Oirschot     }
640bfce1aaeSJanek van Oirschot     }
641bfce1aaeSJanek van Oirschot     const MCExpr *NewLHS = tryFoldHelper(LHS, KBM, Ctx);
642bfce1aaeSJanek van Oirschot     const MCExpr *NewRHS = tryFoldHelper(RHS, KBM, Ctx);
643bfce1aaeSJanek van Oirschot     if (NewLHS != LHS || NewRHS != RHS)
644bfce1aaeSJanek van Oirschot       return MCBinaryExpr::create(BExpr->getOpcode(), NewLHS, NewRHS, Ctx,
645bfce1aaeSJanek van Oirschot                                   BExpr->getLoc());
646bfce1aaeSJanek van Oirschot     return Expr;
647bfce1aaeSJanek van Oirschot   }
648bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::Unary: {
649bfce1aaeSJanek van Oirschot     const MCUnaryExpr *UExpr = cast<MCUnaryExpr>(Expr);
650bfce1aaeSJanek van Oirschot     const MCExpr *SubExpr = UExpr->getSubExpr();
651bfce1aaeSJanek van Oirschot     const MCExpr *NewSubExpr = tryFoldHelper(SubExpr, KBM, Ctx);
652bfce1aaeSJanek van Oirschot     if (SubExpr != NewSubExpr)
653bfce1aaeSJanek van Oirschot       return MCUnaryExpr::create(UExpr->getOpcode(), NewSubExpr, Ctx,
654bfce1aaeSJanek van Oirschot                                  UExpr->getLoc());
655bfce1aaeSJanek van Oirschot     return Expr;
656bfce1aaeSJanek van Oirschot   }
657bfce1aaeSJanek van Oirschot   case MCExpr::ExprKind::Target: {
658bfce1aaeSJanek van Oirschot     const AMDGPUMCExpr *AGVK = cast<AMDGPUMCExpr>(Expr);
659bfce1aaeSJanek van Oirschot     SmallVector<const MCExpr *, 8> NewArgs;
660bfce1aaeSJanek van Oirschot     bool Changed = false;
661bfce1aaeSJanek van Oirschot     for (const MCExpr *Arg : AGVK->getArgs()) {
662bfce1aaeSJanek van Oirschot       const MCExpr *NewArg = tryFoldHelper(Arg, KBM, Ctx);
663bfce1aaeSJanek van Oirschot       NewArgs.push_back(NewArg);
664bfce1aaeSJanek van Oirschot       Changed |= Arg != NewArg;
665bfce1aaeSJanek van Oirschot     }
666bfce1aaeSJanek van Oirschot     return Changed ? AMDGPUMCExpr::create(AGVK->getKind(), NewArgs, Ctx) : Expr;
667bfce1aaeSJanek van Oirschot   }
668bfce1aaeSJanek van Oirschot   }
669bfce1aaeSJanek van Oirschot   return Expr;
670bfce1aaeSJanek van Oirschot }
671bfce1aaeSJanek van Oirschot 
672bfce1aaeSJanek van Oirschot const MCExpr *llvm::AMDGPU::foldAMDGPUMCExpr(const MCExpr *Expr,
673bfce1aaeSJanek van Oirschot                                              MCContext &Ctx) {
674bfce1aaeSJanek van Oirschot   KnownBitsMap KBM;
675bfce1aaeSJanek van Oirschot   knownBitsMapHelper(Expr, KBM);
676bfce1aaeSJanek van Oirschot   const MCExpr *NewExpr = tryFoldHelper(Expr, KBM, Ctx);
677bfce1aaeSJanek van Oirschot 
678bfce1aaeSJanek van Oirschot   return Expr != NewExpr ? NewExpr : Expr;
679bfce1aaeSJanek van Oirschot }
680bfce1aaeSJanek van Oirschot 
681bfce1aaeSJanek van Oirschot void llvm::AMDGPU::printAMDGPUMCExpr(const MCExpr *Expr, raw_ostream &OS,
682bfce1aaeSJanek van Oirschot                                      const MCAsmInfo *MAI) {
683bfce1aaeSJanek van Oirschot   int64_t Val;
684bfce1aaeSJanek van Oirschot   if (Expr->evaluateAsAbsolute(Val)) {
685bfce1aaeSJanek van Oirschot     OS << Val;
686bfce1aaeSJanek van Oirschot     return;
687bfce1aaeSJanek van Oirschot   }
688bfce1aaeSJanek van Oirschot 
689bfce1aaeSJanek van Oirschot   Expr->print(OS, MAI);
690bfce1aaeSJanek van Oirschot }
691