aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/MC/MCFixup.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-09 22:05:14 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-09 22:05:14 +0800
commit3a57627e59ba18b6f9f9aae7bb60c390c0d3575a (patch)
tree736ca062bfffbd68177a512dfe145b06c16d11b1 /backend/lib/MC/MCFixup.cpp
parent379ff50dcc7ccf977379aee68fa9d10f69065d23 (diff)
downloadrcc-project-3a57627e59ba18b6f9f9aae7bb60c390c0d3575a.tar.gz
rcc-project-3a57627e59ba18b6f9f9aae7bb60c390c0d3575a.tar.xz
[MC] Implement RV64GC object emission
Diffstat (limited to 'backend/lib/MC/MCFixup.cpp')
-rw-r--r--backend/lib/MC/MCFixup.cpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/backend/lib/MC/MCFixup.cpp b/backend/lib/MC/MCFixup.cpp
new file mode 100644
index 0000000..8819cd4
--- /dev/null
+++ b/backend/lib/MC/MCFixup.cpp
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/MC/MCFixup.h"
+
+#include <algorithm>
+#include <array>
+#include <cstdint>
+#include <limits>
+#include <utility>
+#include <vector>
+
+namespace rcc::mc {
+namespace {
+
+[[nodiscard]] Expected<std::int64_t> checkedAdd(std::int64_t Left, std::int64_t Right) {
+ std::int64_t Result = 0;
+ if (__builtin_add_overflow(Left, Right, &Result))
+ return makeUnexpected(ErrorCode::RelocationFailed, "MC expression addition overflows");
+ return Result;
+}
+
+[[nodiscard]] Expected<std::int64_t> checkedSubtract(std::int64_t Left, std::int64_t Right) {
+ std::int64_t Result = 0;
+ if (__builtin_sub_overflow(Left, Right, &Result))
+ return makeUnexpected(ErrorCode::RelocationFailed, "MC expression subtraction overflows");
+ return Result;
+}
+
+[[nodiscard]] Expected<MCValue> combineLinearValues(const MCValue &Left, const MCValue &Right,
+ bool SubtractRight) {
+ struct SymbolTerm final {
+ MCSymbolRef Symbol;
+ int Coefficient = 0;
+ };
+ std::vector<SymbolTerm> Terms;
+ const auto AddTerm = [&Terms](const MCSymbolRef &Symbol, int Coefficient) -> Expected<void> {
+ if (!Symbol)
+ return {};
+ const auto Position = std::ranges::find(Terms, Symbol, &SymbolTerm::Symbol);
+ if (Position == Terms.end()) {
+ Terms.push_back(SymbolTerm{.Symbol = Symbol, .Coefficient = Coefficient});
+ return {};
+ }
+ Position->Coefficient += Coefficient;
+ if (Position->Coefficient < -1 || Position->Coefficient > 1) {
+ return makeUnexpected(ErrorCode::RelocationFailed,
+ "MC expression has a symbol coefficient outside -1 to 1");
+ }
+ if (Position->Coefficient == 0)
+ Terms.erase(Position);
+ return {};
+ };
+
+ for (const auto &[Symbol, Coefficient] : std::array<std::pair<MCSymbolRef, int>, 4>{
+ std::pair{Left.AddSymbol, 1},
+ std::pair{Left.SubtractSymbol, -1},
+ std::pair{Right.AddSymbol, SubtractRight ? -1 : 1},
+ std::pair{Right.SubtractSymbol, SubtractRight ? 1 : -1},
+ }) {
+ auto Added = AddTerm(Symbol, Coefficient);
+ if (!Added)
+ return std::unexpected(Added.error());
+ }
+
+ MCValue Result;
+ for (const SymbolTerm &Term : Terms) {
+ MCSymbolRef &Destination = Term.Coefficient > 0 ? Result.AddSymbol : Result.SubtractSymbol;
+ if (Destination) {
+ return makeUnexpected(ErrorCode::RelocationFailed,
+ "MC expression contains more than one symbol with the same sign");
+ }
+ Destination = Term.Symbol;
+ }
+ auto Addend = SubtractRight ? checkedSubtract(Left.Addend, Right.Addend)
+ : checkedAdd(Left.Addend, Right.Addend);
+ if (!Addend)
+ return std::unexpected(Addend.error());
+ Result.Addend = *Addend;
+ return Result;
+}
+
+[[nodiscard]] Expected<MCValue> evaluate(const MCExpr &Expression, std::size_t Depth) {
+ if (Depth > 256)
+ return makeUnexpected(ErrorCode::RelocationFailed, "MC expression exceeds its depth limit");
+
+ switch (Expression.kind()) {
+ case MCExpr::Kind::Constant:
+ return MCValue{.AddSymbol = {},
+ .SubtractSymbol = {},
+ .Addend = *Expression.getIf<std::int64_t>(),
+ .TargetKind = 0};
+ case MCExpr::Kind::SymbolRef:
+ return MCValue{.AddSymbol = Expression.getIf<MCSymbolRefExpr>()->Symbol,
+ .SubtractSymbol = {},
+ .Addend = 0,
+ .TargetKind = 0};
+ case MCExpr::Kind::Target: {
+ const auto &Target = *Expression.getIf<MCTargetExpr>();
+ auto Result = evaluate(*Target.Operand, Depth + 1);
+ if (!Result)
+ return std::unexpected(Result.error());
+ if (Result->TargetKind != 0) {
+ return makeUnexpected(ErrorCode::RelocationFailed,
+ "nested target MC expressions are not relocatable");
+ }
+ Result->TargetKind = Target.Kind;
+ return Result;
+ }
+ case MCExpr::Kind::Unary: {
+ const auto &Unary = *Expression.getIf<MCUnaryExpr>();
+ auto Operand = evaluate(*Unary.Operand, Depth + 1);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ if (Unary.Operator == MCUnaryOperator::Plus)
+ return Operand;
+ if (Unary.Operator == MCUnaryOperator::Minus && Operand->isAbsolute()) {
+ if (Operand->Addend == std::numeric_limits<std::int64_t>::min()) {
+ return makeUnexpected(ErrorCode::RelocationFailed, "MC expression negation overflows");
+ }
+ Operand->Addend = -Operand->Addend;
+ return Operand;
+ }
+ const auto Absolute = Expression.evaluateAbsolute();
+ if (!Absolute) {
+ return makeUnexpected(ErrorCode::RelocationFailed,
+ "symbolic unary MC expression is not relocatable");
+ }
+ return MCValue{.AddSymbol = {}, .SubtractSymbol = {}, .Addend = *Absolute, .TargetKind = 0};
+ }
+ case MCExpr::Kind::Binary: {
+ const auto &Binary = *Expression.getIf<MCBinaryExpr>();
+ if (Binary.Operator != MCBinaryOperator::Add && Binary.Operator != MCBinaryOperator::Subtract) {
+ const auto Absolute = Expression.evaluateAbsolute();
+ if (!Absolute) {
+ return makeUnexpected(ErrorCode::RelocationFailed,
+ "symbolic binary MC expression is not relocatable");
+ }
+ return MCValue{.AddSymbol = {}, .SubtractSymbol = {}, .Addend = *Absolute, .TargetKind = 0};
+ }
+ auto Left = evaluate(*Binary.Left, Depth + 1);
+ auto Right = evaluate(*Binary.Right, Depth + 1);
+ if (!Left)
+ return std::unexpected(Left.error());
+ if (!Right)
+ return std::unexpected(Right.error());
+ if (Left->TargetKind != 0 || Right->TargetKind != 0) {
+ return makeUnexpected(ErrorCode::RelocationFailed,
+ "target MC expression cannot participate in outer arithmetic");
+ }
+
+ return combineLinearValues(*Left, *Right, Binary.Operator == MCBinaryOperator::Subtract);
+ }
+ }
+ return makeUnexpected(ErrorCode::InternalError, "MC expression has an invalid kind");
+}
+
+} // namespace
+
+Expected<void> MCFixup::verify() const {
+ if (Kind == fixup_kind::None)
+ return makeUnexpected(ErrorCode::InvalidArgument, "MC fixup has no kind");
+ if (!Value)
+ return makeUnexpected(ErrorCode::InvalidArgument, "MC fixup has no value expression");
+ auto Verification = Value->verify();
+ if (!Verification)
+ return std::unexpected(Verification.error());
+ return {};
+}
+
+Expected<MCValue> evaluateAsRelocatable(const MCExpr &Expression) {
+ auto Verification = Expression.verify();
+ if (!Verification)
+ return std::unexpected(Verification.error());
+ return evaluate(Expression, 0);
+}
+
+} // namespace rcc::mc