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