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