1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "RISCVAsmPrinter.h"
#include "rcc/CodeGen/MachineBasicBlock.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineJumpTableInfo.h"
#include "rcc/CodeGen/MachineMCContext.h"
#include "rcc/CodeGen/TargetConstant.h"
#include "rcc/MC/MCContext.h"
#include "rcc/MC/MCExpr.h"
#include "rcc/MC/MCStreamer.h"
#include "rcc/MC/MCSymbol.h"
#include "rcc/Target/RISCV/RISCVTargetRelocationKinds.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <ranges>
#include <span>
#include <utility>
#include <vector>
namespace rcc::riscv {
namespace {
[[nodiscard]] Expected<std::uint8_t> targetRelocationSize(TargetRelocationKindID Kind) {
if (Kind == targetRelocationKind(RISCVTargetRelocationKind::Absolute32))
return 4;
if (Kind == targetRelocationKind(RISCVTargetRelocationKind::Absolute64))
return 8;
return makeUnexpected(ErrorCode::Unsupported,
"RV64GC target constant has an unknown relocation kind");
}
[[nodiscard]] Expected<mc::MCExprRef> addOffset(mc::MCExprRef Expression, std::int64_t Offset) {
if (Offset == 0)
return Expression;
auto Result = mc::MCExpr::binary(mc::MCBinaryOperator::Add, std::move(Expression),
mc::MCExpr::constant(Offset));
if (!Result)
return std::unexpected(Result.error());
return *Result;
}
[[nodiscard]] Expected<void> emitBytes(std::span<const std::byte> Bytes, mc::MCStreamer &Streamer) {
if (Bytes.empty())
return {};
std::vector<std::uint8_t> Storage;
Storage.reserve(Bytes.size());
for (const std::byte Byte : Bytes)
Storage.push_back(std::to_integer<std::uint8_t>(Byte));
return Streamer.emitBytes(Storage);
}
} // namespace
Expected<void> RISCVAsmPrinter::emitStartOfAsmFile() {
auto Attribute = streamer().emitDirective("attribute", "arch, \"rv64gc\"");
if (!Attribute)
return std::unexpected(Attribute.error());
return streamer().emitDirective("attribute", "stack_align, 16");
}
Expected<void> RISCVAsmPrinter::emitEndOfAsmFile() {
mc::MCSectionDesc Note{
.Name = ".note.GNU-stack",
.Kind = mc::MCSectionKind::Custom,
.Flags = {},
.Alignment = 1,
.EntrySize = 0,
.Group = {},
.UniqueID = std::nullopt,
};
auto Section = machineContext().context().getOrCreateSection(std::move(Note));
if (!Section)
return std::unexpected(Section.error());
return streamer().switchSection(std::move(*Section));
}
Expected<void> RISCVAsmPrinter::emitTargetConstant(const TargetConstant &Constant) {
auto Emission = Constant.emit();
if (!Emission)
return std::unexpected(Emission.error());
auto DeclaredKind = Constant.relocationKind();
if (!DeclaredKind)
return std::unexpected(DeclaredKind.error());
if (Emission->Fixups.empty() != !DeclaredKind->has_value()) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"RV64GC target constant relocation declaration is inconsistent");
}
if (Emission->Fixups.empty())
return emitBytes(Emission->Bytes, streamer());
std::vector<const TargetConstantFixup *> Fixups;
Fixups.reserve(Emission->Fixups.size());
for (const TargetConstantFixup &Fixup : Emission->Fixups) {
if (Fixup.Kind != **DeclaredKind) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"RV64GC target constant contains mixed relocation kinds");
}
Fixups.push_back(&Fixup);
}
std::ranges::sort(Fixups, {}, [](const TargetConstantFixup *Fixup) { return Fixup->Offset; });
std::uint64_t Cursor = 0;
for (const TargetConstantFixup *Fixup : Fixups) {
auto Size = targetRelocationSize(Fixup->Kind);
if (!Size)
return std::unexpected(Size.error());
if (Fixup->Offset < Cursor || Fixup->Offset > Emission->Bytes.size() ||
*Size > Emission->Bytes.size() - static_cast<std::size_t>(Fixup->Offset)) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"RV64GC target constant relocation storage is invalid");
}
auto RawBytes = emitBytes(std::span<const std::byte>(Emission->Bytes)
.subspan(static_cast<std::size_t>(Cursor),
static_cast<std::size_t>(Fixup->Offset - Cursor)),
streamer());
if (!RawBytes)
return std::unexpected(RawBytes.error());
auto Symbol = machineContext().symbol(Fixup->Symbol);
if (!Symbol)
return std::unexpected(Symbol.error());
auto Expression = mc::MCExpr::symbol(std::move(*Symbol));
if (!Expression)
return std::unexpected(Expression.error());
auto WithAddend = addOffset(std::move(*Expression), Fixup->Addend);
if (!WithAddend)
return std::unexpected(WithAddend.error());
auto Value = streamer().emitValue(std::move(*WithAddend), *Size);
if (!Value)
return std::unexpected(Value.error());
Cursor = Fixup->Offset + *Size;
}
return emitBytes(
std::span<const std::byte>(Emission->Bytes).subspan(static_cast<std::size_t>(Cursor)),
streamer());
}
Expected<void> RISCVAsmPrinter::emitTargetJumpTable(const MachineFunction &Function,
const MachineJumpTableEntry &Entry) {
const MachineJumpTableDesc *Description = Entry.description();
if (Description == nullptr)
return makeUnexpected(ErrorCode::InvalidArgument, "jump-table entry is not live");
if (Description->Encoding == JumpTableEntryEncoding::Target) {
return makeUnexpected(ErrorCode::Unsupported,
"RV64GC jump table has an unknown target encoding");
}
mc::MCSymbolRef BaseSymbol;
if (Description->Encoding == JumpTableEntryEncoding::GPRelative32BlockAddress ||
Description->Encoding == JumpTableEntryEncoding::GPRelative64BlockAddress) {
auto GlobalPointer = machineContext().symbol("__global_pointer$");
if (!GlobalPointer)
return std::unexpected(GlobalPointer.error());
BaseSymbol = std::move(*GlobalPointer);
} else if (Description->Encoding == JumpTableEntryEncoding::Custom32) {
BaseSymbol = machineContext().jumpTableSymbol(Function, Entry.index());
}
for (const MachineBasicBlock *TargetBlock : Description->Targets) {
if (TargetBlock == nullptr)
return makeUnexpected(ErrorCode::AssemblyLoweringFailed, "jump table has a null target");
const mc::MCSymbolRef TargetSymbol = machineContext().blockSymbol(*TargetBlock);
if (!TargetSymbol) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"jump-table target has no MC symbol");
}
auto Expression = mc::MCExpr::symbol(TargetSymbol);
if (!Expression)
return std::unexpected(Expression.error());
if (BaseSymbol) {
auto Base = mc::MCExpr::symbol(BaseSymbol);
if (!Base)
return std::unexpected(Base.error());
Expression = mc::MCExpr::binary(mc::MCBinaryOperator::Subtract, std::move(*Expression),
std::move(*Base));
if (!Expression)
return std::unexpected(Expression.error());
}
auto Value = streamer().emitValue(std::move(*Expression), Description->EntrySize);
if (!Value)
return std::unexpected(Value.error());
}
return {};
}
} // namespace rcc::riscv
|