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 | |
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(Size: sizeof(const MCExpr *) * Args.size())); |
39 | llvm::uninitialized_copy(Src&: Args, Dst: RawArgs); |
40 | this->Args = ArrayRef<const MCExpr *>(RawArgs, Args.size()); |
41 | } |
42 | |
43 | AMDGPUMCExpr::~AMDGPUMCExpr() { Ctx.deallocate(Ptr: RawArgs); } |
44 | |
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 | |
51 | 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 | |
56 | 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 | |
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(a: Arg1, b: Arg2); |
93 | case AMDGPUMCExpr::AGVK_Or: |
94 | return Arg1 | Arg2; |
95 | } |
96 | } |
97 | |
98 | bool AMDGPUMCExpr::(MCValue &Res, |
99 | const MCAssembler *Asm) const { |
100 | auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { |
101 | MCValue MCVal; |
102 | if (!Arg->evaluateAsRelocatable(Res&: 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 = IsaInfo::getNumExtraSGPRs( |
122 | STI, VCCUsed: (bool)VCCUsed, FlatScrUsed: (bool)FlatScrUsed, XNACKUsed: (bool)XNACKUsed); |
123 | Res = MCValue::get(Val: ExtraSGPRs); |
124 | return true; |
125 | } |
126 | |
127 | 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(Res&: 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: *STI); |
143 | |
144 | if (!TryGetMCExprValue(Args[0], NumAGPR) || |
145 | !TryGetMCExprValue(Args[1], NumVGPR)) |
146 | return false; |
147 | |
148 | uint64_t TotalNum = Has90AInsts && NumAGPR ? alignTo(Value: NumVGPR, Align: 4) + NumAGPR |
149 | : std::max(a: NumVGPR, b: NumAGPR); |
150 | Res = MCValue::get(Val: TotalNum); |
151 | return true; |
152 | } |
153 | |
154 | 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(Res&: 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(Val: alignTo(Value, Align)); |
171 | return true; |
172 | } |
173 | |
174 | 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(Res&: 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 | a: Occupancy, b: IsaInfo::getOccupancyWithNumSGPRs( |
206 | SGPRs: NumSGPRs, MaxWaves, |
207 | Gen: static_cast<AMDGPUSubtarget::Generation>(Generation))); |
208 | if (NumVGPRs) |
209 | Occupancy = std::min(a: Occupancy, |
210 | b: IsaInfo::getNumWavesPerEUWithNumVGPRs( |
211 | NumVGPRs, Granule, MaxWaves, TotalNumVGPRs: TargetTotalNumVGPRs)); |
212 | |
213 | Res = MCValue::get(Val: Occupancy); |
214 | return true; |
215 | } |
216 | |
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, E: static_cast<const MCUnaryExpr *>(E)->getSubExpr()); |
225 | case MCExpr::Binary: { |
226 | const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(E); |
227 | return isSymbolUsedInExpression(Sym, E: BE->getLHS()) || |
228 | isSymbolUsedInExpression(Sym, E: 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, E: 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 | |
248 | 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(Res&: ArgRes, Asm) || !ArgRes.isAbsolute()) |
267 | return false; |
268 | |
269 | if (!Total.has_value()) |
270 | Total = ArgRes.getConstant(); |
271 | Total = op(Kind, Arg1: *Total, Arg2: ArgRes.getConstant()); |
272 | } |
273 | |
274 | Res = MCValue::get(Val: *Total); |
275 | return true; |
276 | } |
277 | |
278 | void AMDGPUMCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
279 | for (const MCExpr *Arg : Args) |
280 | Streamer.visitUsedExpr(Expr: *Arg); |
281 | } |
282 | |
283 | 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 | /// |
295 | const AMDGPUMCExpr *AMDGPUMCExpr::(const MCExpr *VCCUsed, |
296 | const MCExpr *FlatScrUsed, |
297 | bool XNACKUsed, |
298 | MCContext &Ctx) { |
299 | |
300 | return create(Kind: AGVK_ExtraSGPRs, |
301 | Args: {VCCUsed, FlatScrUsed, MCConstantExpr::create(Value: XNACKUsed, Ctx)}, |
302 | Ctx); |
303 | } |
304 | |
305 | const AMDGPUMCExpr *AMDGPUMCExpr::createTotalNumVGPR(const MCExpr *NumAGPR, |
306 | const MCExpr *NumVGPR, |
307 | MCContext &Ctx) { |
308 | return create(Kind: AGVK_TotalNumVGPRs, Args: {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. |
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(STI: &STM); |
320 | unsigned Granule = IsaInfo::getVGPRAllocGranule(STI: &STM, DynamicVGPRBlockSize); |
321 | unsigned TargetTotalNumVGPRs = IsaInfo::getTotalNumVGPRs(STI: &STM); |
322 | unsigned Generation = STM.getGeneration(); |
323 | |
324 | auto CreateExpr = [&Ctx](unsigned Value) { |
325 | return MCConstantExpr::create(Value, Ctx); |
326 | }; |
327 | |
328 | return create(Kind: AGVK_Occupancy, |
329 | Args: {CreateExpr(MaxWaves), CreateExpr(Granule), |
330 | CreateExpr(TargetTotalNumVGPRs), CreateExpr(Generation), |
331 | CreateExpr(InitOcc), NumSGPRs, NumVGPRs}, |
332 | Ctx); |
333 | } |
334 | |
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(C: True) |
341 | : KnownBits::makeConstant(C: 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 | |
352 | static void binaryOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, |
353 | unsigned Depth) { |
354 | static constexpr unsigned BitWidth = 64; |
355 | const MCBinaryExpr *BExpr = cast<MCBinaryExpr>(Val: Expr); |
356 | const MCExpr *LHS = BExpr->getLHS(); |
357 | const MCExpr *RHS = BExpr->getRHS(); |
358 | |
359 | knownBitsMapHelper(Expr: LHS, KBM, Depth: Depth + 1); |
360 | knownBitsMapHelper(Expr: RHS, KBM, Depth: 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(LHS: LHSKnown, RHS: 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(LHS: LHSKnown, RHS: RHSKnown); |
376 | return; |
377 | case MCBinaryExpr::Opcode::EQ: { |
378 | std::optional<bool> CompareRes = KnownBits::eq(LHS: LHSKnown, RHS: RHSKnown); |
379 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: CompareRes); |
380 | return; |
381 | } |
382 | case MCBinaryExpr::Opcode::NE: { |
383 | std::optional<bool> CompareRes = KnownBits::ne(LHS: LHSKnown, RHS: RHSKnown); |
384 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: CompareRes); |
385 | return; |
386 | } |
387 | case MCBinaryExpr::Opcode::GT: { |
388 | std::optional<bool> CompareRes = KnownBits::sgt(LHS: LHSKnown, RHS: RHSKnown); |
389 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: CompareRes); |
390 | return; |
391 | } |
392 | case MCBinaryExpr::Opcode::GTE: { |
393 | std::optional<bool> CompareRes = KnownBits::sge(LHS: LHSKnown, RHS: RHSKnown); |
394 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: 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(LHS: LHSKnown, RHS: KnownBits::makeConstant(C: False)); |
402 | std::optional<bool> RHSBool = |
403 | KnownBits::ne(LHS: RHSKnown, RHS: KnownBits::makeConstant(C: False)); |
404 | if (LHSBool && RHSBool) |
405 | CompareRes = *LHSBool && *RHSBool; |
406 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: 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(LHS: Bits, RHS: KnownBits::makeConstant(C: False)); |
414 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: CompareRes); |
415 | return; |
416 | } |
417 | case MCBinaryExpr::Opcode::LT: { |
418 | std::optional<bool> CompareRes = KnownBits::slt(LHS: LHSKnown, RHS: RHSKnown); |
419 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: CompareRes); |
420 | return; |
421 | } |
422 | case MCBinaryExpr::Opcode::LTE: { |
423 | std::optional<bool> CompareRes = KnownBits::sle(LHS: LHSKnown, RHS: RHSKnown); |
424 | KBM[Expr] = fromOptionalToKnownBits(CompareResult: CompareRes); |
425 | return; |
426 | } |
427 | case MCBinaryExpr::Opcode::Mod: |
428 | KBM[Expr] = KnownBits::srem(LHS: LHSKnown, RHS: RHSKnown); |
429 | return; |
430 | case MCBinaryExpr::Opcode::Mul: |
431 | KBM[Expr] = KnownBits::mul(LHS: LHSKnown, RHS: 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(LHS: LHSKnown, RHS: RHSKnown); |
438 | return; |
439 | case MCBinaryExpr::Opcode::AShr: |
440 | KBM[Expr] = KnownBits::ashr(LHS: LHSKnown, RHS: RHSKnown); |
441 | return; |
442 | case MCBinaryExpr::Opcode::LShr: |
443 | KBM[Expr] = KnownBits::lshr(LHS: LHSKnown, RHS: RHSKnown); |
444 | return; |
445 | case MCBinaryExpr::Opcode::Sub: |
446 | KBM[Expr] = KnownBits::sub(LHS: LHSKnown, RHS: RHSKnown); |
447 | return; |
448 | case MCBinaryExpr::Opcode::Xor: |
449 | KBM[Expr] = LHSKnown ^ RHSKnown; |
450 | return; |
451 | } |
452 | } |
453 | |
454 | static void unaryOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, |
455 | unsigned Depth) { |
456 | static constexpr unsigned BitWidth = 64; |
457 | const MCUnaryExpr *UExpr = cast<MCUnaryExpr>(Val: Expr); |
458 | knownBitsMapHelper(Expr: UExpr->getSubExpr(), KBM, Depth: 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 | |
484 | static void targetOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, |
485 | unsigned Depth) { |
486 | static constexpr unsigned BitWidth = 64; |
487 | const AMDGPUMCExpr *AGVK = cast<AMDGPUMCExpr>(Val: Expr); |
488 | |
489 | switch (AGVK->getKind()) { |
490 | default: |
491 | KBM[Expr] = KnownBits(BitWidth); |
492 | return; |
493 | case AMDGPUMCExpr::VariantKind::AGVK_Or: { |
494 | knownBitsMapHelper(Expr: AGVK->getSubExpr(Index: 0), KBM, Depth: Depth + 1); |
495 | KnownBits KB = KBM[AGVK->getSubExpr(Index: 0)]; |
496 | for (const MCExpr *Arg : AGVK->getArgs()) { |
497 | knownBitsMapHelper(Expr: Arg, KBM, Depth: Depth + 1); |
498 | KB |= KBM[Arg]; |
499 | } |
500 | KBM[Expr] = KB; |
501 | return; |
502 | } |
503 | case AMDGPUMCExpr::VariantKind::AGVK_Max: { |
504 | knownBitsMapHelper(Expr: AGVK->getSubExpr(Index: 0), KBM, Depth: Depth + 1); |
505 | KnownBits KB = KBM[AGVK->getSubExpr(Index: 0)]; |
506 | for (const MCExpr *Arg : AGVK->getArgs()) { |
507 | knownBitsMapHelper(Expr: Arg, KBM, Depth: Depth + 1); |
508 | KB = KnownBits::umax(LHS: KB, RHS: 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(Res&: Val)) { |
519 | APInt APValue(BitWidth, Val); |
520 | KBM[Expr] = KnownBits::makeConstant(C: APValue); |
521 | return; |
522 | } |
523 | KBM[Expr] = KnownBits(BitWidth); |
524 | return; |
525 | } |
526 | } |
527 | } |
528 | |
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(Res&: Val)) { |
535 | APInt APValue(BitWidth, Val, /*isSigned=*/true); |
536 | KBM[Expr] = KnownBits::makeConstant(C: 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>(Val: Expr); |
552 | APInt APValue(BitWidth, CE->getValue(), /*isSigned=*/true); |
553 | KBM[Expr] = KnownBits::makeConstant(C: APValue); |
554 | return; |
555 | } |
556 | case MCExpr::ExprKind::SymbolRef: { |
557 | const MCSymbolRefExpr *RExpr = cast<MCSymbolRefExpr>(Val: 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(Expr: SymVal, KBM, Depth: 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 | |
587 | static const MCExpr *tryFoldHelper(const MCExpr *Expr, KnownBitsMap &KBM, |
588 | MCContext &Ctx) { |
589 | if (!KBM.count(Val: 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(Value: ConstVal.getSExtValue(), Ctx); |
609 | } |
610 | |
611 | int64_t EvalValue; |
612 | if (Expr->evaluateAsAbsolute(Res&: EvalValue)) |
613 | return MCConstantExpr::create(Value: EvalValue, Ctx); |
614 | } |
615 | |
616 | switch (Expr->getKind()) { |
617 | default: |
618 | return Expr; |
619 | case MCExpr::ExprKind::Binary: { |
620 | const MCBinaryExpr *BExpr = cast<MCBinaryExpr>(Val: 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(Expr: 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(Expr: RHS, KBM, Ctx); |
636 | if (ValueCheckKnownBits(KBM[RHS], 0)) |
637 | return tryFoldHelper(Expr: LHS, KBM, Ctx); |
638 | break; |
639 | } |
640 | case MCBinaryExpr::Opcode::Mul: { |
641 | if (ValueCheckKnownBits(KBM[LHS], 1)) |
642 | return tryFoldHelper(Expr: RHS, KBM, Ctx); |
643 | if (ValueCheckKnownBits(KBM[RHS], 1)) |
644 | return tryFoldHelper(Expr: 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(Expr: LHS, KBM, Ctx); |
652 | if (ValueCheckKnownBits(KBM[LHS], 0)) |
653 | return MCConstantExpr::create(Value: 0, Ctx); |
654 | break; |
655 | } |
656 | case MCBinaryExpr::Opcode::And: { |
657 | if (ValueCheckKnownBits(KBM[LHS], 0) || ValueCheckKnownBits(KBM[RHS], 0)) |
658 | return MCConstantExpr::create(Value: 0, Ctx); |
659 | break; |
660 | } |
661 | } |
662 | const MCExpr *NewLHS = tryFoldHelper(Expr: LHS, KBM, Ctx); |
663 | const MCExpr *NewRHS = tryFoldHelper(Expr: RHS, KBM, Ctx); |
664 | if (NewLHS != LHS || NewRHS != RHS) |
665 | return MCBinaryExpr::create(Op: BExpr->getOpcode(), LHS: NewLHS, RHS: NewRHS, Ctx, |
666 | Loc: BExpr->getLoc()); |
667 | return Expr; |
668 | } |
669 | case MCExpr::ExprKind::Unary: { |
670 | const MCUnaryExpr *UExpr = cast<MCUnaryExpr>(Val: Expr); |
671 | const MCExpr *SubExpr = UExpr->getSubExpr(); |
672 | const MCExpr *NewSubExpr = tryFoldHelper(Expr: SubExpr, KBM, Ctx); |
673 | if (SubExpr != NewSubExpr) |
674 | return MCUnaryExpr::create(Op: UExpr->getOpcode(), Expr: NewSubExpr, Ctx, |
675 | Loc: UExpr->getLoc()); |
676 | return Expr; |
677 | } |
678 | case MCExpr::ExprKind::Target: { |
679 | const AMDGPUMCExpr *AGVK = cast<AMDGPUMCExpr>(Val: Expr); |
680 | SmallVector<const MCExpr *, 8> NewArgs; |
681 | bool Changed = false; |
682 | for (const MCExpr *Arg : AGVK->getArgs()) { |
683 | const MCExpr *NewArg = tryFoldHelper(Expr: Arg, KBM, Ctx); |
684 | NewArgs.push_back(Elt: NewArg); |
685 | Changed |= Arg != NewArg; |
686 | } |
687 | return Changed ? AMDGPUMCExpr::create(Kind: AGVK->getKind(), Args: NewArgs, Ctx) : Expr; |
688 | } |
689 | } |
690 | return Expr; |
691 | } |
692 | |
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 | |
702 | void llvm::AMDGPU::printAMDGPUMCExpr(const MCExpr *Expr, raw_ostream &OS, |
703 | const MCAsmInfo *MAI) { |
704 | int64_t Val; |
705 | if (Expr->evaluateAsAbsolute(Res&: Val)) { |
706 | OS << Val; |
707 | return; |
708 | } |
709 | |
710 | MAI->printExpr(OS, *Expr); |
711 | } |
712 | |