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 "llvm/MC/MCContext.h" |
11 | #include "llvm/MC/MCStreamer.h" |
12 | #include "llvm/MC/MCSymbol.h" |
13 | #include "llvm/MC/MCValue.h" |
14 | #include "llvm/Support/Allocator.h" |
15 | #include "llvm/Support/raw_ostream.h" |
16 | #include <optional> |
17 | |
18 | using namespace llvm; |
19 | |
20 | AMDGPUVariadicMCExpr::AMDGPUVariadicMCExpr(VariadicKind Kind, |
21 | ArrayRef<const MCExpr *> Args, |
22 | MCContext &Ctx) |
23 | : Kind(Kind), Ctx(Ctx) { |
24 | assert(Args.size() >= 1 && "Needs a minimum of one expression." ); |
25 | assert(Kind != AGVK_None && |
26 | "Cannot construct AMDGPUVariadicMCExpr of kind none." ); |
27 | |
28 | // Allocating the variadic arguments through the same allocation mechanism |
29 | // that the object itself is allocated with so they end up in the same memory. |
30 | // |
31 | // Will result in an asan failure if allocated on the heap through standard |
32 | // allocation (e.g., through SmallVector's grow). |
33 | RawArgs = static_cast<const MCExpr **>( |
34 | Ctx.allocate(Size: sizeof(const MCExpr *) * Args.size())); |
35 | std::uninitialized_copy(first: Args.begin(), last: Args.end(), result: RawArgs); |
36 | this->Args = ArrayRef<const MCExpr *>(RawArgs, Args.size()); |
37 | } |
38 | |
39 | AMDGPUVariadicMCExpr::~AMDGPUVariadicMCExpr() { Ctx.deallocate(Ptr: RawArgs); } |
40 | |
41 | const AMDGPUVariadicMCExpr * |
42 | AMDGPUVariadicMCExpr::create(VariadicKind Kind, ArrayRef<const MCExpr *> Args, |
43 | MCContext &Ctx) { |
44 | return new (Ctx) AMDGPUVariadicMCExpr(Kind, Args, Ctx); |
45 | } |
46 | |
47 | const MCExpr *AMDGPUVariadicMCExpr::getSubExpr(size_t Index) const { |
48 | assert(Index < Args.size() && |
49 | "Indexing out of bounds AMDGPUVariadicMCExpr sub-expr" ); |
50 | return Args[Index]; |
51 | } |
52 | |
53 | void AMDGPUVariadicMCExpr::printImpl(raw_ostream &OS, |
54 | const MCAsmInfo *MAI) const { |
55 | switch (Kind) { |
56 | default: |
57 | llvm_unreachable("Unknown AMDGPUVariadicMCExpr kind." ); |
58 | case AGVK_Or: |
59 | OS << "or(" ; |
60 | break; |
61 | case AGVK_Max: |
62 | OS << "max(" ; |
63 | break; |
64 | } |
65 | for (auto It = Args.begin(); It != Args.end(); ++It) { |
66 | (*It)->print(OS, MAI, /*InParens=*/false); |
67 | if ((It + 1) != Args.end()) |
68 | OS << ", " ; |
69 | } |
70 | OS << ')'; |
71 | } |
72 | |
73 | static int64_t op(AMDGPUVariadicMCExpr::VariadicKind Kind, int64_t Arg1, |
74 | int64_t Arg2) { |
75 | switch (Kind) { |
76 | default: |
77 | llvm_unreachable("Unknown AMDGPUVariadicMCExpr kind." ); |
78 | case AMDGPUVariadicMCExpr::AGVK_Max: |
79 | return std::max(a: Arg1, b: Arg2); |
80 | case AMDGPUVariadicMCExpr::AGVK_Or: |
81 | return Arg1 | Arg2; |
82 | } |
83 | } |
84 | |
85 | bool AMDGPUVariadicMCExpr::evaluateAsRelocatableImpl( |
86 | MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { |
87 | std::optional<int64_t> Total; |
88 | |
89 | for (const MCExpr *Arg : Args) { |
90 | MCValue ArgRes; |
91 | if (!Arg->evaluateAsRelocatable(Res&: ArgRes, Layout, Fixup) || |
92 | !ArgRes.isAbsolute()) |
93 | return false; |
94 | |
95 | if (!Total.has_value()) |
96 | Total = ArgRes.getConstant(); |
97 | Total = op(Kind, Arg1: *Total, Arg2: ArgRes.getConstant()); |
98 | } |
99 | |
100 | Res = MCValue::get(Val: *Total); |
101 | return true; |
102 | } |
103 | |
104 | void AMDGPUVariadicMCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
105 | for (const MCExpr *Arg : Args) |
106 | Streamer.visitUsedExpr(Expr: *Arg); |
107 | } |
108 | |
109 | MCFragment *AMDGPUVariadicMCExpr::findAssociatedFragment() const { |
110 | for (const MCExpr *Arg : Args) { |
111 | if (Arg->findAssociatedFragment()) |
112 | return Arg->findAssociatedFragment(); |
113 | } |
114 | return nullptr; |
115 | } |
116 | |