aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target/RISCV/RISCVTargetObjectFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/Target/RISCV/RISCVTargetObjectFile.cpp')
-rw-r--r--backend/lib/Target/RISCV/RISCVTargetObjectFile.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/backend/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/backend/lib/Target/RISCV/RISCVTargetObjectFile.cpp
new file mode 100644
index 0000000..9a8aebb
--- /dev/null
+++ b/backend/lib/Target/RISCV/RISCVTargetObjectFile.cpp
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "RISCVTargetObjectFile.h"
+
+#include "rcc/CodeGen/GlobalObject.h"
+#include "rcc/CodeGen/MachineConstantPool.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/MCSymbol.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <ranges>
+#include <string>
+
+namespace rcc::riscv {
+namespace {
+
+[[nodiscard]] bool initializerIsZero(const GlobalInitializer &Initializer, std::size_t Depth = 0) {
+ if (Depth > 1024)
+ return false;
+ switch (Initializer.kind()) {
+ case GlobalInitializer::Kind::Integer: {
+ const auto *Value = Initializer.getIf<APInt>();
+ return Value != nullptr &&
+ std::ranges::all_of(Value->words(), [](std::uint64_t Word) { return Word == 0; });
+ }
+ case GlobalInitializer::Kind::Floating: {
+ const auto *Value = Initializer.getIf<APFloat>();
+ return Value != nullptr &&
+ std::ranges::all_of(Value->words(), [](std::uint64_t Word) { return Word == 0; });
+ }
+ case GlobalInitializer::Kind::Bytes: {
+ const auto *Value = Initializer.getIf<std::vector<std::byte>>();
+ return Value != nullptr &&
+ std::ranges::all_of(*Value, [](std::byte Byte) { return Byte == std::byte{0}; });
+ }
+ case GlobalInitializer::Kind::ZeroFill:
+ case GlobalInitializer::Kind::UndefinedStorage:
+ return true;
+ case GlobalInitializer::Kind::Repeated: {
+ const auto *Value = Initializer.getIf<GlobalRepeatedInitializer>();
+ return Value != nullptr && Value->Value && initializerIsZero(*Value->Value, Depth + 1);
+ }
+ case GlobalInitializer::Kind::Aggregate: {
+ const auto *Value = Initializer.getIf<GlobalAggregateInitializer>();
+ return Value != nullptr && std::ranges::all_of(Value->Elements, [Depth](const auto &Element) {
+ return Element && initializerIsZero(*Element, Depth + 1);
+ });
+ }
+ case GlobalInitializer::Kind::AlignmentPadding: {
+ const auto *Value = Initializer.getIf<GlobalAlignmentPadding>();
+ return Value != nullptr && Value->Fill == 0;
+ }
+ case GlobalInitializer::Kind::Target: {
+ const auto *Value = Initializer.getIf<TargetConstant>();
+ if (Value == nullptr)
+ return false;
+ auto Emission = Value->emit();
+ return Emission && Emission->Fixups.empty() &&
+ std::ranges::all_of(Emission->Bytes,
+ [](std::byte Byte) { return Byte == std::byte{0}; });
+ }
+ case GlobalInitializer::Kind::Invalid:
+ case GlobalInitializer::Kind::SymbolAddress:
+ case GlobalInitializer::Kind::SymbolDifference:
+ return false;
+ }
+ return false;
+}
+
+[[nodiscard]] bool initializerHasRelocation(const GlobalInitializer &Initializer,
+ std::size_t Depth = 0) {
+ if (Depth > 1024)
+ return true;
+ switch (Initializer.kind()) {
+ case GlobalInitializer::Kind::SymbolAddress:
+ case GlobalInitializer::Kind::SymbolDifference:
+ return true;
+ case GlobalInitializer::Kind::Repeated: {
+ const auto *Value = Initializer.getIf<GlobalRepeatedInitializer>();
+ return Value == nullptr || !Value->Value || initializerHasRelocation(*Value->Value, Depth + 1);
+ }
+ case GlobalInitializer::Kind::Aggregate: {
+ const auto *Value = Initializer.getIf<GlobalAggregateInitializer>();
+ return Value == nullptr || std::ranges::any_of(Value->Elements, [Depth](const auto &Element) {
+ return !Element || initializerHasRelocation(*Element, Depth + 1);
+ });
+ }
+ case GlobalInitializer::Kind::Target: {
+ const auto *Value = Initializer.getIf<TargetConstant>();
+ if (Value == nullptr)
+ return true;
+ auto Emission = Value->emit();
+ return !Emission || !Emission->Fixups.empty();
+ }
+ case GlobalInitializer::Kind::Invalid:
+ return true;
+ case GlobalInitializer::Kind::Integer:
+ case GlobalInitializer::Kind::Floating:
+ case GlobalInitializer::Kind::Bytes:
+ case GlobalInitializer::Kind::ZeroFill:
+ case GlobalInitializer::Kind::AlignmentPadding:
+ case GlobalInitializer::Kind::UndefinedStorage:
+ return false;
+ }
+ return true;
+}
+
+[[nodiscard]] mc::MCSectionDesc textSectionDescription() {
+ return mc::MCSectionDesc{
+ .Name = ".text",
+ .Kind = mc::MCSectionKind::Text,
+ .Flags = {mc::MCSectionFlag::Alloc, mc::MCSectionFlag::Executable},
+ .Alignment = 4,
+ .EntrySize = 0,
+ .Group = {},
+ .UniqueID = std::nullopt,
+ };
+}
+
+[[nodiscard]] mc::MCSectionDesc readOnlySectionDescription() {
+ return mc::MCSectionDesc{
+ .Name = ".rodata",
+ .Kind = mc::MCSectionKind::ReadOnly,
+ .Flags = {mc::MCSectionFlag::Alloc},
+ .Alignment = 1,
+ .EntrySize = 0,
+ .Group = {},
+ .UniqueID = std::nullopt,
+ };
+}
+
+} // namespace
+
+Expected<mc::MCSectionDesc> RISCVELFTargetObjectFile::textSection(const MachineFunction &) const {
+ return textSectionDescription();
+}
+
+Expected<mc::MCSectionDesc>
+RISCVELFTargetObjectFile::globalSection(const GlobalObjectDesc &Object,
+ MachineMCContext &Context) const {
+ if (Object.AddressSpace != 0) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RV64GC assembly does not support nonzero global address spaces");
+ }
+ if (Object.TargetFlags != 0 || !Object.TargetAttributes.empty()) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RV64GC assembly does not recognize this global target state");
+ }
+ const bool IsTLS = Object.TLSModel != GlobalTLSModel::None;
+ const bool IsZero = Object.Initializer && initializerIsZero(*Object.Initializer);
+ const bool HasRelocation = Object.Initializer && initializerHasRelocation(*Object.Initializer);
+
+ mc::MCSectionDesc Result;
+ Result.Alignment = Object.Align.bytes();
+ if (IsTLS) {
+ Result.Name = IsZero ? ".tbss" : ".tdata";
+ Result.Kind = IsZero ? mc::MCSectionKind::TLSBSS : mc::MCSectionKind::TLSData;
+ Result.Flags = {mc::MCSectionFlag::Alloc, mc::MCSectionFlag::Writable, mc::MCSectionFlag::TLS};
+ } else if (Object.IsConstant && HasRelocation) {
+ Result.Name = ".data.rel.ro";
+ Result.Kind = mc::MCSectionKind::Data;
+ Result.Flags = {mc::MCSectionFlag::Alloc, mc::MCSectionFlag::Writable};
+ } else if (Object.IsConstant) {
+ Result = readOnlySectionDescription();
+ Result.Alignment = Object.Align.bytes();
+ } else if (IsZero) {
+ Result.Name = ".bss";
+ Result.Kind = mc::MCSectionKind::BSS;
+ Result.Flags = {mc::MCSectionFlag::Alloc, mc::MCSectionFlag::Writable};
+ } else {
+ Result.Name = ".data";
+ Result.Kind = mc::MCSectionKind::Data;
+ Result.Flags = {mc::MCSectionFlag::Alloc, mc::MCSectionFlag::Writable};
+ }
+
+ if (Object.Section)
+ Result.Name = *Object.Section;
+ if (Object.COMDAT) {
+ auto Group = Context.symbol(*Object.COMDAT);
+ if (!Group)
+ return std::unexpected(Group.error());
+ Result.Flags.set(mc::MCSectionFlag::Group);
+ Result.Group = std::move(*Group);
+ if (!Object.Section)
+ Result.Name += "." + Object.Symbol;
+ }
+ return Result;
+}
+
+Expected<mc::MCSectionDesc>
+RISCVELFTargetObjectFile::constantPoolSection(const MachineFunction &Function,
+ const MachineConstantPoolEntry &Entry) const {
+ const MachineConstantPoolEntryDesc *Description = Entry.description();
+ if (Description == nullptr)
+ return makeUnexpected(ErrorCode::InvalidArgument, "constant-pool entry is not live");
+ if (Description->Placement.Section == ConstantPoolSectionKind::TextAdjacent)
+ return textSectionDescription();
+
+ mc::MCSectionDesc Result = readOnlySectionDescription();
+ if (Description->Placement.Section == ConstantPoolSectionKind::Data) {
+ Result.Name = ".data";
+ Result.Kind = mc::MCSectionKind::Data;
+ Result.Flags.set(mc::MCSectionFlag::Writable);
+ } else if (Description->Placement.Section == ConstantPoolSectionKind::Target) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RV64GC constant pool has an unknown target section");
+ } else if (Description->Placement.Section == ConstantPoolSectionKind::MergeableReadOnly) {
+ Result.Name = ".rodata.cst" + std::to_string(Description->Size);
+ Result.Flags.set(mc::MCSectionFlag::Merge);
+ Result.EntrySize = Description->Size;
+ }
+ if (Description->Placement.UniqueSection) {
+ Result.Name += "." + std::to_string(Function.stableID().value()) + "." +
+ std::to_string(Entry.index().value());
+ Result.UniqueID = static_cast<std::uint64_t>(Entry.index().value()) + 1U;
+ }
+ Result.Alignment = Description->Align.bytes();
+ return Result;
+}
+
+Expected<mc::MCSectionDesc>
+RISCVELFTargetObjectFile::jumpTableSection(const MachineFunction &Function,
+ const MachineJumpTableEntry &Entry) const {
+ const MachineJumpTableDesc *Description = Entry.description();
+ if (Description == nullptr)
+ return makeUnexpected(ErrorCode::InvalidArgument, "jump-table entry is not live");
+ mc::MCSectionDesc Result = Description->Placement.InTextSection ? textSectionDescription()
+ : readOnlySectionDescription();
+ if (Description->Placement.UniqueSection) {
+ Result.Name += "." + std::to_string(Function.stableID().value()) + ".jt." +
+ std::to_string(Entry.index().value());
+ Result.UniqueID = static_cast<std::uint64_t>(Entry.index().value()) + 1U;
+ }
+ Result.Alignment = Description->Align.bytes();
+ return Result;
+}
+
+} // namespace rcc::riscv