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