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