aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-19 04:27:41 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-19 04:27:41 +0800
commit307fc0961972ac5264d6f3459978fbec95cad3a9 (patch)
tree80eff53db8f62a736a46221d258dcadf7543fa88 /backend
parent6a91664223881226e2b6186561c05ff378a19355 (diff)
downloadrcc-project-307fc0961972ac5264d6f3459978fbec95cad3a9.tar.gz
rcc-project-307fc0961972ac5264d6f3459978fbec95cad3a9.tar.xz
[RISCV][GlobalISel] Select and expand global addresses
Diffstat (limited to 'backend')
-rw-r--r--backend/include/rcc/CodeGen/GlobalObject.h9
-rw-r--r--backend/include/rcc/CodeGen/InstructionDescriptor.h1
-rw-r--r--backend/include/rcc/CodeGen/MIRParser/MIParser.h2
-rw-r--r--backend/include/rcc/CodeGen/MachineOperand.h5
-rw-r--r--backend/include/rcc/CodeGen/MachinePseudoExpansion.h14
-rw-r--r--backend/include/rcc/CodeGen/TargetPseudoExpansion.h1
-rw-r--r--backend/include/rcc/MIR/EmbeddedIR.h5
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVFixupKinds.h1
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVInstPrinter.h1
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVSubtarget.h15
-rw-r--r--backend/include/rcc/Tooling/BackendInvocation.h2
-rw-r--r--backend/lib/CodeGen/MIRParser/MIParser.cpp5
-rw-r--r--backend/lib/CodeGen/MIRParser/MIRParser.cpp6
-rw-r--r--backend/lib/CodeGen/MachineOperand.cpp7
-rw-r--r--backend/lib/CodeGen/MachinePseudoExpansion.cpp37
-rw-r--r--backend/lib/MIR/EmbeddedIR.cpp27
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp178
-rw-r--r--backend/lib/Target/RISCV/RISCVAsmBackend.cpp9
-rw-r--r--backend/lib/Target/RISCV/RISCVInstPrinter.cpp2
-rw-r--r--backend/lib/Target/RISCV/RISCVInstrInfoI.rccdesc2
-rw-r--r--backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc25
-rw-r--r--backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp3
-rw-r--r--backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp11
-rw-r--r--backend/lib/Target/RISCV/RISCVPipeline.cpp6
-rw-r--r--backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp123
-rw-r--r--backend/lib/Target/RISCV/RISCVRegisterInfo.rccdesc3
-rw-r--r--backend/lib/Target/RISCV/RISCVSubtarget.cpp4
-rw-r--r--backend/lib/Tooling/MIRFuzzer.cpp2
-rw-r--r--backend/lib/Tooling/PipelineDriver.cpp2
-rw-r--r--backend/tools/MIRTool/MIRToolMain.cpp3
-rw-r--r--backend/utils/TableGen/Common/CodeGenInstruction.cpp3
31 files changed, 495 insertions, 19 deletions
diff --git a/backend/include/rcc/CodeGen/GlobalObject.h b/backend/include/rcc/CodeGen/GlobalObject.h
index 1ddc34a..b67421f 100644
--- a/backend/include/rcc/CodeGen/GlobalObject.h
+++ b/backend/include/rcc/CodeGen/GlobalObject.h
@@ -156,6 +156,15 @@ enum class GlobalUnnamedAddress : std::uint8_t {
Count,
};
+struct GlobalValueProperties final {
+ bool DSOLocal = false;
+ bool ExternalWeak = false;
+ bool ThreadLocal = false;
+
+ friend constexpr bool operator==(const GlobalValueProperties &Left,
+ const GlobalValueProperties &Right) noexcept = default;
+};
+
struct GlobalObjectDesc final {
std::string Symbol;
GenericConstantType ObjectType;
diff --git a/backend/include/rcc/CodeGen/InstructionDescriptor.h b/backend/include/rcc/CodeGen/InstructionDescriptor.h
index ccd1b63..91881e6 100644
--- a/backend/include/rcc/CodeGen/InstructionDescriptor.h
+++ b/backend/include/rcc/CodeGen/InstructionDescriptor.h
@@ -195,6 +195,7 @@ enum class PseudoOwner : std::uint8_t {
InstructionSelect,
PhiElimination,
TwoAddressRewrite,
+ PreRAExpansion,
RegisterAllocator,
PrePEIExpansion,
PrologueEpilogueInsertion,
diff --git a/backend/include/rcc/CodeGen/MIRParser/MIParser.h b/backend/include/rcc/CodeGen/MIRParser/MIParser.h
index 0b888e5..cd40882 100644
--- a/backend/include/rcc/CodeGen/MIRParser/MIParser.h
+++ b/backend/include/rcc/CodeGen/MIRParser/MIParser.h
@@ -5,6 +5,7 @@
#include "rcc/CodeGen/MachineIRTypes.h"
#include "rcc/CodeGen/MachineMetadata.h"
+#include "rcc/CodeGen/GlobalObject.h"
#include "rcc/CodeGen/Register.h"
#include "rcc/Support/Error.h"
#include "rcc/Support/TextDiagnostic.h"
@@ -66,6 +67,7 @@ struct MIParserContext final {
std::vector<MIMetadataSlot> Metadata;
std::vector<MISyncScopeSlot> SyncScopes;
std::function<bool(std::string_view)> HasIRBlock;
+ std::function<GlobalValueProperties(std::string_view)> GlobalValuePropertiesForName;
std::function<Expected<SyncScopeID>(std::string_view)> InternSyncScope;
std::function<Expected<std::uint32_t>(std::uint32_t)> PointerSizeInBits;
};
diff --git a/backend/include/rcc/CodeGen/MachineOperand.h b/backend/include/rcc/CodeGen/MachineOperand.h
index 1f321b0..d82e41a 100644
--- a/backend/include/rcc/CodeGen/MachineOperand.h
+++ b/backend/include/rcc/CodeGen/MachineOperand.h
@@ -5,6 +5,7 @@
#include "rcc/ADT/APFloat.h"
#include "rcc/ADT/APInt.h"
+#include "rcc/CodeGen/GlobalObject.h"
#include "rcc/CodeGen/LowLevelType.h"
#include "rcc/CodeGen/MachineDebugInfo.h"
#include "rcc/CodeGen/MachineIRTypes.h"
@@ -127,6 +128,7 @@ struct JumpTableOperand final {
struct GlobalSymbolOperand final {
std::string Name;
std::int64_t Offset = 0;
+ GlobalValueProperties Properties;
friend bool operator==(const GlobalSymbolOperand &Left,
const GlobalSymbolOperand &Right) = default;
@@ -329,7 +331,8 @@ public:
[[nodiscard]] static MachineOperand jumpTable(JumpTableIndex Index,
std::uint32_t TargetFlags = 0);
[[nodiscard]] static Expected<MachineOperand>
- globalSymbol(std::string Name, std::int64_t Offset = 0, std::uint32_t TargetFlags = 0);
+ globalSymbol(std::string Name, std::int64_t Offset = 0, std::uint32_t TargetFlags = 0,
+ GlobalValueProperties Properties = {});
[[nodiscard]] static Expected<MachineOperand>
externalSymbol(std::string Name, std::int64_t Offset = 0, std::uint32_t TargetFlags = 0);
[[nodiscard]] static Expected<MachineOperand> blockAddress(std::string FunctionName,
diff --git a/backend/include/rcc/CodeGen/MachinePseudoExpansion.h b/backend/include/rcc/CodeGen/MachinePseudoExpansion.h
index 7d4b309..c30ba50 100644
--- a/backend/include/rcc/CodeGen/MachinePseudoExpansion.h
+++ b/backend/include/rcc/CodeGen/MachinePseudoExpansion.h
@@ -11,6 +11,20 @@ namespace rcc {
class TargetInstrInfo;
class TargetPseudoExpansionInfo;
+class PreRATargetPseudoExpansionPass final : public MachineFunctionPass {
+public:
+ explicit PreRATargetPseudoExpansionPass(const TargetPseudoExpansionInfo &Info) noexcept
+ : Info(&Info) {}
+
+ [[nodiscard]] const MachinePassContract &contract() const noexcept override;
+ [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function,
+ const TargetDescription &Target,
+ MachineFunctionAnalysisManager &Analyses) override;
+
+private:
+ const TargetPseudoExpansionInfo *Info;
+};
+
class PreparePostRAPseudosPass final : public MachineFunctionPass {
public:
explicit PreparePostRAPseudosPass(const TargetPseudoExpansionInfo &Info) noexcept : Info(&Info) {}
diff --git a/backend/include/rcc/CodeGen/TargetPseudoExpansion.h b/backend/include/rcc/CodeGen/TargetPseudoExpansion.h
index 4d9f556..5135d78 100644
--- a/backend/include/rcc/CodeGen/TargetPseudoExpansion.h
+++ b/backend/include/rcc/CodeGen/TargetPseudoExpansion.h
@@ -14,6 +14,7 @@ class MachineInstr;
class TargetDescription;
enum class MachinePseudoExpansionPhase : std::uint8_t {
+ PreRA,
PrePEI,
PostRA,
TargetLate,
diff --git a/backend/include/rcc/MIR/EmbeddedIR.h b/backend/include/rcc/MIR/EmbeddedIR.h
index 99f1493..1c17938 100644
--- a/backend/include/rcc/MIR/EmbeddedIR.h
+++ b/backend/include/rcc/MIR/EmbeddedIR.h
@@ -3,6 +3,7 @@
#ifndef RCC_MIR_EMBEDDEDIR_H
#define RCC_MIR_EMBEDDEDIR_H
+#include "rcc/CodeGen/GlobalObject.h"
#include "rcc/Support/TextDiagnostic.h"
#include <cstddef>
@@ -141,6 +142,8 @@ public:
[[nodiscard]] const EmbeddedIRFunction *function(std::string_view Name) const noexcept;
[[nodiscard]] const EmbeddedIRFunction *unnamedFunction(std::size_t Ordinal) const noexcept;
[[nodiscard]] const EmbeddedIRReference *globalObject(std::string_view Name) const noexcept;
+ [[nodiscard]] std::optional<GlobalValueProperties>
+ globalObjectProperties(std::string_view Name) const noexcept;
[[nodiscard]] const EmbeddedIRMetadataDefinition *metadata(std::string_view Name) const noexcept;
[[nodiscard]] const EmbeddedIRTypeDefinition *
typeDefinition(std::string_view Name) const noexcept;
@@ -167,6 +170,8 @@ private:
std::optional<TextRange> DataLayoutRange;
std::vector<EmbeddedIRFunction> Functions;
std::vector<EmbeddedIRReference> GlobalObjects;
+ std::unordered_map<std::string, GlobalValueProperties, StringHash, std::equal_to<> >
+ GlobalProperties;
std::vector<EmbeddedIRMetadataDefinition> MetadataDefinitions;
std::vector<EmbeddedIRTypeDefinition> TypeDefinitions;
std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> FunctionNameToIndex;
diff --git a/backend/include/rcc/Target/RISCV/RISCVFixupKinds.h b/backend/include/rcc/Target/RISCV/RISCVFixupKinds.h
index 7e9c8a2..e030bfc 100644
--- a/backend/include/rcc/Target/RISCV/RISCVFixupKinds.h
+++ b/backend/include/rcc/Target/RISCV/RISCVFixupKinds.h
@@ -14,6 +14,7 @@ enum class RISCVFixupKind : mc::MCFixupKind {
Low12I,
Low12S,
PCRelativeHigh20,
+ GOTPCRelativeHigh20,
PCRelativeLow12I,
PCRelativeLow12S,
JAL,
diff --git a/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h b/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h
index 1b80218..7e74ab2 100644
--- a/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h
+++ b/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h
@@ -18,6 +18,7 @@ enum class RISCVMCExprKind : std::uint32_t {
PCRelativeLow = 3,
AbsoluteHigh = 4,
AbsoluteLow = 5,
+ GOTPCRelativeHigh = 6,
};
class RISCVInstPrinter final : public mc::MCInstPrinter {
diff --git a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
index c590be6..a77a045 100644
--- a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
+++ b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
@@ -3,6 +3,7 @@
#ifndef RCC_TARGET_RISCV_RISCVSUBTARGET_H
#define RCC_TARGET_RISCV_RISCVSUBTARGET_H
+#include "rcc/CodeGen/CommandFlags.h"
#include "rcc/Support/Error.h"
#include <cstdint>
@@ -88,7 +89,9 @@ private:
class RISCVSubtarget final {
public:
- explicit RISCVSubtarget(RISCVSubtargetFeatures Features);
+ explicit RISCVSubtarget(RISCVSubtargetFeatures Features,
+ RelocationModel Relocation = RelocationModel::Static,
+ CodeModel Code = CodeModel::Small);
RISCVSubtarget(const RISCVSubtarget &) = delete;
RISCVSubtarget &operator=(const RISCVSubtarget &) = delete;
RISCVSubtarget(RISCVSubtarget &&) = delete;
@@ -99,6 +102,14 @@ public:
return Features;
}
+ [[nodiscard]] RelocationModel relocationModel() const noexcept {
+ return Relocation;
+ }
+
+ [[nodiscard]] CodeModel codeModel() const noexcept {
+ return Code;
+ }
+
[[nodiscard]] const TargetCallLowering *getCallLowering() const;
[[nodiscard]] InstructionSelector *getInstructionSelector() const;
[[nodiscard]] const LegalizerInfo *getLegalizerInfo() const;
@@ -106,6 +117,8 @@ public:
private:
RISCVSubtargetFeatures Features;
+ RelocationModel Relocation;
+ CodeModel Code;
mutable std::unique_ptr<TargetCallLowering> CallLoweringInfo;
mutable std::unique_ptr<InstructionSelector> InstSelector;
mutable std::unique_ptr<LegalizerInfo> Legalizer;
diff --git a/backend/include/rcc/Tooling/BackendInvocation.h b/backend/include/rcc/Tooling/BackendInvocation.h
index d61f038..504dc3a 100644
--- a/backend/include/rcc/Tooling/BackendInvocation.h
+++ b/backend/include/rcc/Tooling/BackendInvocation.h
@@ -55,7 +55,7 @@ struct BackendInvocation final {
std::vector<std::string> Features;
std::string ABI;
std::string DataLayout;
- rcc::RelocationModel Relocation = rcc::RelocationModel::PositionIndependent;
+ rcc::RelocationModel Relocation = rcc::RelocationModel::Static;
rcc::CodeModel Code = rcc::CodeModel::Small;
std::vector<BackendOption> TargetOptions;
LayoutOwnership Layout = LayoutOwnership::NativeObject;
diff --git a/backend/lib/CodeGen/MIRParser/MIParser.cpp b/backend/lib/CodeGen/MIRParser/MIParser.cpp
index 62f1f14..b44701b 100644
--- a/backend/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/backend/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2290,7 +2290,10 @@ bool MIParser::Impl::parseOperand(bool IsDef, ParsedOperand &Result) {
std::int64_t Offset = 0;
if (parseOptionalOffset(Offset))
return true;
- auto Created = MachineOperand::globalSymbol(Name, Offset, TargetFlags);
+ const GlobalValueProperties Properties = Context.GlobalValuePropertiesForName
+ ? Context.GlobalValuePropertiesForName(Name)
+ : GlobalValueProperties{};
+ auto Created = MachineOperand::globalSymbol(Name, Offset, TargetFlags, Properties);
if (!Created)
return importError(OperandToken, Created.error());
Operand = std::move(*Created);
diff --git a/backend/lib/CodeGen/MIRParser/MIRParser.cpp b/backend/lib/CodeGen/MIRParser/MIRParser.cpp
index 3b89491..c7e92a0 100644
--- a/backend/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/backend/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -290,6 +290,12 @@ bool MIRDocumentParser::parseFunction(const yaml::Node &Root, MIRDocument &Docum
return IRFunction->block(BlockName) != nullptr;
};
}
+ if (Document.EmbeddedIR) {
+ const EmbeddedIRReferenceIndex *Embedded = &*Document.EmbeddedIR;
+ Context.GlobalValuePropertiesForName = [Embedded](std::string_view GlobalName) {
+ return Embedded->globalObjectProperties(GlobalName).value_or(GlobalValueProperties{});
+ };
+ }
std::vector<PendingJumpTable> PendingJumpTables;
if (parseFunctionScalars(Root, Function, DocumentInfo) ||
diff --git a/backend/lib/CodeGen/MachineOperand.cpp b/backend/lib/CodeGen/MachineOperand.cpp
index 92b09dc..f265c3f 100644
--- a/backend/lib/CodeGen/MachineOperand.cpp
+++ b/backend/lib/CodeGen/MachineOperand.cpp
@@ -116,12 +116,13 @@ MachineOperand MachineOperand::jumpTable(JumpTableIndex Index, std::uint32_t Tar
}
Expected<MachineOperand> MachineOperand::globalSymbol(std::string Name, std::int64_t Offset,
- std::uint32_t TargetFlags) {
+ std::uint32_t TargetFlags,
+ GlobalValueProperties Properties) {
if (Name.empty()) {
return makeUnexpected(ErrorCode::InvalidArgument, "global symbol operand name cannot be empty");
}
- return MachineOperand(Kind::GlobalSymbol, GlobalSymbolOperand{std::move(Name), Offset},
- TargetFlags);
+ return MachineOperand(Kind::GlobalSymbol,
+ GlobalSymbolOperand{std::move(Name), Offset, Properties}, TargetFlags);
}
Expected<MachineOperand> MachineOperand::externalSymbol(std::string Name, std::int64_t Offset,
diff --git a/backend/lib/CodeGen/MachinePseudoExpansion.cpp b/backend/lib/CodeGen/MachinePseudoExpansion.cpp
index e3109ed..8388079 100644
--- a/backend/lib/CodeGen/MachinePseudoExpansion.cpp
+++ b/backend/lib/CodeGen/MachinePseudoExpansion.cpp
@@ -94,7 +94,8 @@ using BlockSizeSnapshot = std::vector<std::pair<MachineBlockStableID, std::uint6
return makeUnexpected(ErrorCode::PseudoExpansionFailed,
"pseudo expansion changed CFG resources outside its owner contract");
}
- if (Before.VirtualRegisterCount != After.VirtualRegisterCount) {
+ if (Phase != MachinePseudoExpansionPhase::PreRA &&
+ Before.VirtualRegisterCount != After.VirtualRegisterCount) {
return makeUnexpected(ErrorCode::PseudoExpansionFailed,
"post-selection pseudo expansion created a virtual register");
}
@@ -109,6 +110,8 @@ using BlockSizeSnapshot = std::vector<std::pair<MachineBlockStableID, std::uint6
[[nodiscard]] PseudoOwner ownerFor(MachinePseudoExpansionPhase Phase) noexcept {
switch (Phase) {
+ case MachinePseudoExpansionPhase::PreRA:
+ return PseudoOwner::PreRAExpansion;
case MachinePseudoExpansionPhase::PrePEI:
return PseudoOwner::PrePEIExpansion;
case MachinePseudoExpansionPhase::PostRA:
@@ -137,6 +140,21 @@ using BlockSizeSnapshot = std::vector<std::pair<MachineBlockStableID, std::uint6
}
[[nodiscard]] const MachinePassContract &phaseContract(MachinePseudoExpansionPhase Phase) {
+ static const MachinePassContract PreRA = [] {
+ MachinePassContract Value{
+ .Name = "pre-ra-target-pseudo-expansion",
+ .Requires = {MachineFunctionProperty::Selected, MachineFunctionProperty::NoPHIs,
+ MachineFunctionProperty::TiedOpsRewritten},
+ .Sets = {},
+ .Clears = {},
+ .RequiredAnalyses = {},
+ .VerificationStage = PipelineStage::TiedOpsRewritten,
+ };
+ Value.ThreadSafety = PassThreadSafety::ThreadSafe;
+ Value.DeclaredChanges = {MachinePassChange::Instructions, MachinePassChange::Operands,
+ MachinePassChange::Registers};
+ return Value;
+ }();
static const MachinePassContract PrePEI = [] {
MachinePassContract Value{
.Name = "pre-pei-target-pseudo-expansion",
@@ -185,6 +203,8 @@ using BlockSizeSnapshot = std::vector<std::pair<MachineBlockStableID, std::uint6
return Value;
}();
switch (Phase) {
+ case MachinePseudoExpansionPhase::PreRA:
+ return PreRA;
case MachinePseudoExpansionPhase::PrePEI:
return PrePEI;
case MachinePseudoExpansionPhase::PostRA:
@@ -402,6 +422,21 @@ runExpansionTransaction(MachineFunction &Function, const TargetDescription &Targ
} // namespace
+const MachinePassContract &PreRATargetPseudoExpansionPass::contract() const noexcept {
+ return phaseContract(MachinePseudoExpansionPhase::PreRA);
+}
+
+Expected<MachinePassResult>
+PreRATargetPseudoExpansionPass::run(MachineFunction &Function, const TargetDescription &Target,
+ MachineFunctionAnalysisManager &Analyses) {
+ if (!Function.properties().containsAll(contract().Requires)) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "pre-RA pseudo expansion requires selected SSA-exited MIR");
+ }
+ return runExpansionTransaction(Function, Target, *Info, MachinePseudoExpansionPhase::PreRA,
+ nullptr, Analyses);
+}
+
const MachinePassContract &PreparePostRAPseudosPass::contract() const noexcept {
return preparationContract();
}
diff --git a/backend/lib/MIR/EmbeddedIR.cpp b/backend/lib/MIR/EmbeddedIR.cpp
index 25aea05..c727539 100644
--- a/backend/lib/MIR/EmbeddedIR.cpp
+++ b/backend/lib/MIR/EmbeddedIR.cpp
@@ -117,6 +117,14 @@ EmbeddedIRReferenceIndex::globalObject(std::string_view Name) const noexcept {
return &GlobalObjects[Position->second];
}
+std::optional<GlobalValueProperties>
+EmbeddedIRReferenceIndex::globalObjectProperties(std::string_view Name) const noexcept {
+ const auto Position = GlobalProperties.find(Name);
+ if (Position == GlobalProperties.end())
+ return std::nullopt;
+ return Position->second;
+}
+
const EmbeddedIRMetadataDefinition *
EmbeddedIRReferenceIndex::metadata(std::string_view Name) const noexcept {
const auto Position = MetadataNameToIndex.find(Name);
@@ -794,12 +802,31 @@ private:
"duplicate embedded LLVM IR global object");
return;
}
+ ++Position;
+ GlobalValueProperties Properties;
+ while (Position < End) {
+ while (Position < End && !isIdentifierStart(Line[Position]))
+ ++Position;
+ const std::size_t WordBegin = Position;
+ while (Position < End && isIdentifierBody(Line[Position]))
+ ++Position;
+ if (WordBegin == Position)
+ continue;
+ const std::string_view Word = Line.substr(WordBegin, Position - WordBegin);
+ if (Word == "dso_local" || Word == "internal" || Word == "private")
+ Properties.DSOLocal = true;
+ else if (Word == "extern_weak")
+ Properties.ExternalWeak = true;
+ else if (Word == "thread_local")
+ Properties.ThreadLocal = true;
+ }
const std::size_t GlobalIndex = Index.GlobalObjects.size();
Index.GlobalNameToIndex.emplace(Name->Name, GlobalIndex);
Index.GlobalObjects.push_back(EmbeddedIRReference{
.Name = std::move(Name->Name),
.Range = Name->Range,
});
+ Index.GlobalProperties.emplace(Index.GlobalObjects.back().Name, Properties);
}
void parseMetadataDefinition(std::string_view Line, std::size_t LineOffset, std::size_t Position,
diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index a4a2113..094f9cb 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -5,6 +5,7 @@
#include "RISCVInstrInfo.h"
#include "RISCVRegisterBankInfo.h"
#include "rcc/CodeGen/GenericOpcodes.h"
+#include "rcc/CodeGen/GlobalObject.h"
#include "rcc/CodeGen/GlobalISel/GISelValueTracking.h"
#include "rcc/CodeGen/GlobalISel/InstructionSelector.h"
#include "rcc/CodeGen/LowLevelType.h"
@@ -12,6 +13,7 @@
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineIRBuilder.h"
#include "rcc/CodeGen/MachineInstr.h"
+#include "rcc/CodeGen/MachineMemOperand.h"
#include "rcc/CodeGen/MachineOperand.h"
#include "rcc/CodeGen/MachineRegisterInfo.h"
#include "rcc/CodeGen/TargetDescription.h"
@@ -33,6 +35,9 @@
namespace rcc::riscv {
namespace {
+constexpr std::uint32_t AbsoluteHighFlag = 32;
+constexpr std::uint32_t AbsoluteLowFlag = 64;
+
#define GET_GLOBALISEL_MATCH_TABLE
#include "RISCVGenGlobalISel.inc"
#undef GET_GLOBALISEL_MATCH_TABLE
@@ -591,6 +596,9 @@ public:
return {};
case GenericOpcode::G_FPEXTLOAD:
case GenericOpcode::G_FPTRUNCSTORE:
+ case GenericOpcode::G_GLOBAL_VALUE:
+ case GenericOpcode::G_JUMP_TABLE:
+ case GenericOpcode::G_CONSTANT_POOL:
return {};
case GenericOpcode::G_FCONSTANT: {
const MachineOperand *Immediate = Instruction.operandAt(1);
@@ -692,6 +700,10 @@ public:
return selectAtomicRMW(Instruction, Function, Target, Type, Generic);
case GenericOpcode::G_FENCE:
return selectFence(Instruction);
+ case GenericOpcode::G_GLOBAL_VALUE:
+ case GenericOpcode::G_JUMP_TABLE:
+ case GenericOpcode::G_CONSTANT_POOL:
+ return selectGlobalAddress(Instruction, Function, Target);
case GenericOpcode::G_PHI:
return Instruction.setOpcode(opcode(GenericOpcode::PHI));
case GenericOpcode::COPY:
@@ -715,6 +727,172 @@ public:
}
private:
+ [[nodiscard]] Expected<const MachineMemOperand *>
+ createGOTLoad(MachineFunction &Function, LowLevelType Type) const {
+ auto Size = MemorySize::fixed(Type.minimumBitWidth() / 8U);
+ if (!Size)
+ return std::unexpected(Size.error());
+ auto Alignment = rcc::Alignment::create(Type.minimumBitWidth() / 8U);
+ if (!Alignment)
+ return std::unexpected(Alignment.error());
+ MachineMemOperandDesc Description;
+ Description.Accesses = {MemoryAccessFlag::Load, MemoryAccessFlag::Dereferenceable,
+ MemoryAccessFlag::Invariant};
+ Description.Size = *Size;
+ Description.MemoryType = Type;
+ Description.Align = *Alignment;
+ Description.Base = MemoryBase::got();
+ return Function.createMemOperand(std::move(Description));
+ }
+
+ [[nodiscard]] Expected<void>
+ selectGlobalAddress(MachineInstr &Instruction, MachineFunction &Function,
+ const TargetDescription &Target) const {
+ const MachineOperand *DestinationOperand = Instruction.operandAt(0);
+ const MachineOperand *SymbolOperand = Instruction.operandAt(1);
+ const Register *Destination =
+ DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
+ const std::optional<LowLevelType> Type = resultType(Function, Instruction);
+ if (Destination == nullptr || SymbolOperand == nullptr || !Type || !Type->isPointer()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V address selection has malformed generic operands");
+ }
+ auto DestinationConstraint = constrainBuilderRegisters(Function, Target, {*Destination});
+ if (!DestinationConstraint)
+ return std::unexpected(DestinationConstraint.error());
+
+ GlobalValueProperties Properties;
+ if (Instruction.opcode() == opcode(GenericOpcode::G_GLOBAL_VALUE)) {
+ const auto *Global = SymbolOperand->getIf<GlobalSymbolOperand>();
+ if (Global == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V global address has no global symbol operand");
+ Properties = Global->Properties;
+ if (Properties.ThreadLocal) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RISC-V GlobalISel does not support thread-local global addresses");
+ }
+ }
+
+ const bool TaggedGlobals = Subtarget.features().has(RISCVSubtargetOption::TaggedGlobals);
+ const bool UseGOT = Subtarget.relocationModel() == RelocationModel::PositionIndependent ||
+ TaggedGlobals;
+ const auto ReplaceWithPseudo = [&](InstructionOpcode OpcodeValue) -> Expected<void> {
+ auto SetOpcode = Instruction.setOpcode(instructionOpcode(OpcodeValue));
+ if (!SetOpcode)
+ return std::unexpected(SetOpcode.error());
+ return constrainSelectedInstruction(Instruction, Function, Target);
+ };
+ const auto BuildGOTLoad = [&]() -> Expected<void> {
+ auto Memory = createGOTLoad(Function, *Type);
+ if (!Memory)
+ return std::unexpected(Memory.error());
+ MachineIRBuilder Builder(Function, Target);
+ auto Point = Builder.setInsertPointBefore(Instruction);
+ if (!Point)
+ return std::unexpected(Point.error());
+ auto Pending = Builder.buildInstr(instructionOpcode(InstructionOpcode::PseudoLGA));
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ auto Def = Pending->addDef(*Destination);
+ if (!Def)
+ return std::unexpected(Def.error());
+ auto Symbol = Pending->addOperand(SymbolOperand->cloneDetached());
+ if (!Symbol)
+ return std::unexpected(Symbol.error());
+ auto MemoryAdded = Pending->addMemOperand(**Memory);
+ if (!MemoryAdded)
+ return std::unexpected(MemoryAdded.error());
+ auto Result = Pending->build();
+ if (!Result)
+ return std::unexpected(Result.error());
+ auto Flags = propagateSelectionFlags(**Result, Instruction, Target);
+ if (!Flags)
+ return std::unexpected(Flags.error());
+ auto Constraint = constrainSelectedInstruction(**Result, Function, Target);
+ if (!Constraint)
+ return std::unexpected(Constraint.error());
+ MachineBasicBlock *Block = Instruction.parent();
+ if (Block == nullptr)
+ return makeUnexpected(ErrorCode::InternalError,
+ "RISC-V global address is detached from its block");
+ return Block->removeInstruction(Instruction);
+ };
+
+ if (UseGOT) {
+ if (Properties.DSOLocal && !TaggedGlobals)
+ return ReplaceWithPseudo(InstructionOpcode::PseudoLLA);
+ return BuildGOTLoad();
+ }
+
+ if (Subtarget.codeModel() == CodeModel::Medium) {
+ if (Properties.ExternalWeak)
+ return BuildGOTLoad();
+ return ReplaceWithPseudo(InstructionOpcode::PseudoLLA);
+ }
+ if (Subtarget.codeModel() != CodeModel::Small) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RISC-V GlobalISel does not support this global address code model");
+ }
+
+ auto Temporary = createTemporary(Function, *Type, Target);
+ if (!Temporary)
+ return std::unexpected(Temporary.error());
+ MachineIRBuilder Builder(Function, Target);
+ auto Point = Builder.setInsertPointBefore(Instruction);
+ if (!Point)
+ return std::unexpected(Point.error());
+ auto HighPending = Builder.buildInstr(instructionOpcode(InstructionOpcode::LUI));
+ if (!HighPending)
+ return std::unexpected(HighPending.error());
+ auto HighDef = HighPending->addDef(*Temporary);
+ if (!HighDef)
+ return std::unexpected(HighDef.error());
+ MachineOperand HighSymbol = SymbolOperand->cloneDetached();
+ HighSymbol.setTargetFlags(AbsoluteHighFlag);
+ auto HighOperand = HighPending->addOperand(std::move(HighSymbol));
+ if (!HighOperand)
+ return std::unexpected(HighOperand.error());
+ auto High = HighPending->build();
+ if (!High)
+ return std::unexpected(High.error());
+ auto HighFlags = propagateSelectionFlags(**High, Instruction, Target);
+ if (!HighFlags)
+ return std::unexpected(HighFlags.error());
+ auto HighConstraint = constrainSelectedInstruction(**High, Function, Target);
+ if (!HighConstraint)
+ return std::unexpected(HighConstraint.error());
+
+ auto LowPending = Builder.buildInstr(instructionOpcode(InstructionOpcode::ADDI));
+ if (!LowPending)
+ return std::unexpected(LowPending.error());
+ auto LowDef = LowPending->addDef(*Destination);
+ if (!LowDef)
+ return std::unexpected(LowDef.error());
+ auto LowSource = LowPending->addUse(*Temporary);
+ if (!LowSource)
+ return std::unexpected(LowSource.error());
+ MachineOperand LowSymbol = SymbolOperand->cloneDetached();
+ LowSymbol.setTargetFlags(AbsoluteLowFlag);
+ auto LowOperand = LowPending->addOperand(std::move(LowSymbol));
+ if (!LowOperand)
+ return std::unexpected(LowOperand.error());
+ auto Low = LowPending->build();
+ if (!Low)
+ return std::unexpected(Low.error());
+ auto LowFlags = propagateSelectionFlags(**Low, Instruction, Target);
+ if (!LowFlags)
+ return std::unexpected(LowFlags.error());
+ auto LowConstraint = constrainSelectedInstruction(**Low, Function, Target);
+ if (!LowConstraint)
+ return std::unexpected(LowConstraint.error());
+ MachineBasicBlock *Block = Instruction.parent();
+ if (Block == nullptr)
+ return makeUnexpected(ErrorCode::InternalError,
+ "RISC-V global address is detached from its block");
+ return Block->removeInstruction(Instruction);
+ }
+
[[nodiscard]] Expected<void> selectCopy(MachineInstr &Instruction, MachineFunction &Function,
const TargetDescription &Target) const {
const MachineOperand *DestinationOperand = Instruction.operandAt(0);
diff --git a/backend/lib/Target/RISCV/RISCVAsmBackend.cpp b/backend/lib/Target/RISCV/RISCVAsmBackend.cpp
index ac17403..e118d79 100644
--- a/backend/lib/Target/RISCV/RISCVAsmBackend.cpp
+++ b/backend/lib/Target/RISCV/RISCVAsmBackend.cpp
@@ -21,6 +21,7 @@ enum class RISCVRelocation : std::uint32_t {
Branch = 16,
JAL = 17,
CallPLT = 19,
+ GOTHigh20 = 20,
PCRelativeHigh20 = 23,
PCRelativeLow12I = 24,
PCRelativeLow12S = 25,
@@ -193,6 +194,7 @@ Expected<void> RISCVAsmBackend::applyFixup(mc::MCFixupKind Kind, std::span<std::
std::uint32_t Instruction = readWord(Data, Offset);
if (isTargetKind(Kind, RISCVFixupKind::High20) ||
isTargetKind(Kind, RISCVFixupKind::PCRelativeHigh20) ||
+ isTargetKind(Kind, RISCVFixupKind::GOTPCRelativeHigh20) ||
isTargetKind(Kind, RISCVFixupKind::CallPLT)) {
const std::uint64_t Adjusted = static_cast<std::uint64_t>(Value) + 0x800U;
const std::uint32_t High = static_cast<std::uint32_t>(Adjusted >> 12U);
@@ -244,6 +246,13 @@ Expected<std::uint32_t> RISCVAsmBackend::relocationType(const mc::MCFixup &Fixup
return std::unexpected(Kind.error());
return Relocation(RISCVRelocation::PCRelativeHigh20);
}
+ if (isTargetKind(Fixup.Kind, RISCVFixupKind::GOTPCRelativeHigh20)) {
+ auto Kind = requireRelocationTargetKind(
+ Value, static_cast<std::uint32_t>(RISCVMCExprKind::GOTPCRelativeHigh), "R_RISCV_GOT_HI20");
+ if (!Kind)
+ return std::unexpected(Kind.error());
+ return Relocation(RISCVRelocation::GOTHigh20);
+ }
if (isTargetKind(Fixup.Kind, RISCVFixupKind::PCRelativeLow12I) ||
isTargetKind(Fixup.Kind, RISCVFixupKind::PCRelativeLow12S)) {
auto Kind = requireRelocationTargetKind(
diff --git a/backend/lib/Target/RISCV/RISCVInstPrinter.cpp b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp
index e72681a..723628f 100644
--- a/backend/lib/Target/RISCV/RISCVInstPrinter.cpp
+++ b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp
@@ -279,6 +279,8 @@ Expected<std::string> RISCVInstPrinter::printTargetExpression(std::uint32_t Kind
return "%hi(" + std::string(Operand) + ")";
case RISCVMCExprKind::AbsoluteLow:
return "%lo(" + std::string(Operand) + ")";
+ case RISCVMCExprKind::GOTPCRelativeHigh:
+ return "%got_pcrel_hi(" + std::string(Operand) + ")";
}
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"RISC-V MC expression has an unknown target kind");
diff --git a/backend/lib/Target/RISCV/RISCVInstrInfoI.rccdesc b/backend/lib/Target/RISCV/RISCVInstrInfoI.rccdesc
index 33f13a9..7bb30e5 100644
--- a/backend/lib/Target/RISCV/RISCVInstrInfoI.rccdesc
+++ b/backend/lib/Target/RISCV/RISCVInstrInfoI.rccdesc
@@ -21,7 +21,7 @@ instructions:
encoding: 5143
operands:
- { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD }
- - { kinds: [immediate, basic_block, global_symbol, external_symbol, mc_symbol], immediate_predicate: UIMM20, allowed_target_flags: 3, name: IMM }
+ - { kinds: [immediate, basic_block, global_symbol, external_symbol, mc_symbol], immediate_predicate: UIMM20, allowed_target_flags: 130, name: IMM }
num_explicit_defs: 1
flags: [produces_code]
scheduling_class: ALU
diff --git a/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc b/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc
index 4523641..14bcf26 100644
--- a/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc
+++ b/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc
@@ -409,6 +409,31 @@ instructions:
owner: post_ra_expansion
deadline: post_ra_finalized
-
+ id: 1267
+ symbol: PseudoLLA
+ name: PseudoLLA
+ operands:
+ - { kinds: [register], role: def, register_class: GPR, register_bank: GPR }
+ - { kinds: [constant_pool_index, jump_table_index, global_symbol, external_symbol, block_address, mc_symbol] }
+ num_explicit_defs: 1
+ flags: [pseudo, produces_code, allowed_pre_legalizer]
+ size: 8
+ owner: pre_ra_expansion
+ deadline: tied_ops_rewritten
+ -
+ id: 1268
+ symbol: PseudoLGA
+ name: PseudoLGA
+ operands:
+ - { kinds: [register], role: def, register_class: GPR, register_bank: GPR }
+ - { kinds: [constant_pool_index, jump_table_index, global_symbol, external_symbol, block_address, mc_symbol] }
+ num_explicit_defs: 1
+ flags: [pseudo, produces_code, allowed_pre_legalizer, may_load]
+ size: 8
+ requires_memory_operands: true
+ owner: pre_ra_expansion
+ deadline: tied_ops_rewritten
+ -
id: 1263
symbol: PseudoBRIND
name: PseudoBRIND
diff --git a/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp b/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp
index 9ba3021..15a0c2d 100644
--- a/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp
+++ b/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp
@@ -186,6 +186,8 @@ namespace {
return fixupKind(RISCVFixupKind::High20);
if (*Kind == static_cast<std::uint32_t>(RISCVMCExprKind::PCRelativeHigh))
return fixupKind(RISCVFixupKind::PCRelativeHigh20);
+ if (*Kind == static_cast<std::uint32_t>(RISCVMCExprKind::GOTPCRelativeHigh))
+ return fixupKind(RISCVFixupKind::GOTPCRelativeHigh20);
if (*Kind == static_cast<std::uint32_t>(RISCVMCExprKind::CallPLT))
return fixupKind(RISCVFixupKind::CallPLT);
return makeUnexpected(ErrorCode::InstructionEncodingFailed,
@@ -493,6 +495,7 @@ namespace {
if (!Kind)
return std::unexpected(Kind.error());
const bool PCRelative = *Kind == fixupKind(RISCVFixupKind::PCRelativeHigh20) ||
+ *Kind == fixupKind(RISCVFixupKind::GOTPCRelativeHigh20) ||
*Kind == fixupKind(RISCVFixupKind::CallPLT);
auto Immediate = immediateOrFixup(Instruction, 1, *Kind, PCRelative, Result);
if (!Immediate)
diff --git a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
index 78c56a3..61cb587 100644
--- a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
+++ b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
@@ -48,9 +48,11 @@ constexpr std::uint32_t CopyF32TargetFlag = 8;
constexpr std::uint32_t CopyF64TargetFlag = 16;
constexpr std::uint32_t AbsoluteHighTargetFlag = 32;
constexpr std::uint32_t AbsoluteLowTargetFlag = 64;
-constexpr std::uint32_t KnownTargetFlags =
- CallTargetFlag | PCRelativeHighTargetFlag | PCRelativeLowTargetFlag | CopyF32TargetFlag |
- CopyF64TargetFlag | AbsoluteHighTargetFlag | AbsoluteLowTargetFlag;
+constexpr std::uint32_t GOTPCRelativeHighTargetFlag = 128;
+constexpr std::uint32_t KnownTargetFlags = CallTargetFlag | PCRelativeHighTargetFlag |
+ PCRelativeLowTargetFlag | CopyF32TargetFlag |
+ CopyF64TargetFlag | AbsoluteHighTargetFlag |
+ AbsoluteLowTargetFlag | GOTPCRelativeHighTargetFlag;
[[nodiscard]] Expected<std::uint8_t> targetRelocationSize(TargetRelocationKindID Kind) {
if (Kind == targetRelocationKind(RISCVTargetRelocationKind::Absolute32))
@@ -97,6 +99,9 @@ constexpr std::uint32_t KnownTargetFlags =
case AbsoluteLowTargetFlag:
Kind = RISCVMCExprKind::AbsoluteLow;
break;
+ case GOTPCRelativeHighTargetFlag:
+ Kind = RISCVMCExprKind::GOTPCRelativeHigh;
+ break;
default:
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"RISC-V operand combines incompatible direct target flags");
diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp
index f1de092..00a4398 100644
--- a/backend/lib/Target/RISCV/RISCVPipeline.cpp
+++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp
@@ -12,6 +12,7 @@
#include "rcc/CodeGen/MachineCombiner.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineOptimizationPipeline.h"
+#include "rcc/CodeGen/MachinePseudoExpansion.h"
#include "rcc/CodeGen/PHIElimination.h"
#include "rcc/CodeGen/RegAllocPBQP.h"
#include "rcc/CodeGen/TargetDescription.h"
@@ -65,7 +66,10 @@ template <typename PassT, typename... ArgumentT>
}
[[nodiscard]] Expected<void> addRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline) {
- auto Added = addPreRegisterAllocationOptimizationPipeline(Pipeline, optimizationPipelineInfo());
+ auto Added = addPass<PreRATargetPseudoExpansionPass>(Pipeline, pseudoExpansionInfo());
+ if (!Added)
+ return std::unexpected(Added.error());
+ Added = addPreRegisterAllocationOptimizationPipeline(Pipeline, optimizationPipelineInfo());
if (!Added)
return std::unexpected(Added.error());
return addPass<PBQPAllocatorPass>(Pipeline, registerAllocationInfo());
diff --git a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
index df3e5ad..257fa3a 100644
--- a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
+++ b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
@@ -28,6 +28,7 @@ constexpr std::uint32_t PCRelativeHighFlag = 2;
constexpr std::uint32_t PCRelativeLowFlag = 4;
constexpr std::uint32_t CopyF32Flag = 8;
constexpr std::uint32_t CopyF64Flag = 16;
+constexpr std::uint32_t GOTPCRelativeHighFlag = 128;
[[nodiscard]] std::optional<RegisterBankID>
registerBank(Register Reg, const MachineFunction &Function, const TargetDescription &Target) {
@@ -300,6 +301,121 @@ copyRegisters(const MachineInstr &Instruction) {
"RISC-V direct call pseudo has no symbol target");
}
+[[nodiscard]] Expected<Register> createGPRScratchRegister(MachineFunction &Function,
+ const TargetDescription &Target) {
+ const RegisterBankID GPRBank =
+ RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::GPR));
+ const RegisterClassID GPRClass =
+ RegisterClassID::fromValue(static_cast<std::uint32_t>(RegisterClass::GPR));
+ if (Target.registers().registerBank(GPRBank) == nullptr ||
+ Target.registers().registerClass(GPRClass) == nullptr) {
+ return makeUnexpected(ErrorCode::InternalError,
+ "RISC-V pre-RA address expansion requires the GPR register class");
+ }
+ auto Scratch = Function.registerInfo().createVirtualRegister();
+ if (!Scratch)
+ return std::unexpected(Scratch.error());
+ auto SetBank = Function.registerInfo().setRegisterBank(*Scratch, GPRBank);
+ if (!SetBank)
+ return std::unexpected(SetBank.error());
+ auto SetClass = Function.registerInfo().setRegisterClass(*Scratch, GPRClass);
+ if (!SetClass)
+ return std::unexpected(SetClass.error());
+ return *Scratch;
+}
+
+[[nodiscard]] Expected<bool> expandAddressPseudo(MachineInstr &Instruction,
+ MachineFunction &Function,
+ const TargetDescription &Target,
+ bool LoadFromGOT) {
+ const MachineOperand *Destination = Instruction.operandAt(0);
+ const MachineOperand *Symbol = Instruction.operandAt(1);
+ const Register *DestinationRegister =
+ Destination == nullptr ? nullptr : Destination->getIf<Register>();
+ if (DestinationRegister == nullptr || Symbol == nullptr || Instruction.operandCount() != 2) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V address pseudo has malformed explicit operands");
+ }
+ if (LoadFromGOT && Instruction.memOperands().size() != 1) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V global-address pseudo requires one GOT load memory operand");
+ }
+ if (!LoadFromGOT && !Instruction.memOperands().empty()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V local-address pseudo cannot carry memory operands");
+ }
+
+ auto Scratch = createGPRScratchRegister(Function, Target);
+ if (!Scratch)
+ return std::unexpected(Scratch.error());
+ MachineIRBuilder Builder(Function, Target);
+ auto Point = Builder.setInsertPointBefore(Instruction);
+ if (!Point)
+ return std::unexpected(Point.error());
+
+ auto HighPending = Builder.buildInstr(instructionOpcode(InstructionOpcode::AUIPC));
+ if (!HighPending)
+ return std::unexpected(HighPending.error());
+ auto HighDef = HighPending->addDef(*Scratch);
+ if (!HighDef)
+ return std::unexpected(HighDef.error());
+ MachineOperand HighSymbol = Symbol->cloneDetached();
+ HighSymbol.setTargetFlags(LoadFromGOT ? GOTPCRelativeHighFlag : PCRelativeHighFlag);
+ auto HighTarget = HighPending->addOperand(std::move(HighSymbol));
+ if (!HighTarget)
+ return std::unexpected(HighTarget.error());
+ auto High = HighPending->build();
+ if (!High)
+ return std::unexpected(High.error());
+ const std::string Anchor = Instruction.preInstrSymbol()
+ ? std::string(*Instruction.preInstrSymbol())
+ : ".Lrcc_pcrel_hi_" + std::to_string(Function.stableID().value()) +
+ "_" + std::to_string((*High)->stableID().value());
+ auto HighAnchor = (*High)->setPreInstrSymbol(Anchor);
+ if (!HighAnchor)
+ return std::unexpected(HighAnchor.error());
+ auto HighDecoration = copyCommonDecoration(Instruction, **High, false, false, false);
+ if (!HighDecoration)
+ return std::unexpected(HighDecoration.error());
+
+ const InstructionOpcode LowOpcode = LoadFromGOT ? InstructionOpcode::LD : InstructionOpcode::ADDI;
+ auto LowPending = Builder.buildInstr(instructionOpcode(LowOpcode));
+ if (!LowPending)
+ return std::unexpected(LowPending.error());
+ auto LowDef = LowPending->addOperand(Destination->cloneDetached());
+ if (!LowDef)
+ return std::unexpected(LowDef.error());
+ auto LowBase = LowPending->addUse(*Scratch);
+ if (!LowBase)
+ return std::unexpected(LowBase.error());
+ auto LowOffset = LowPending->addMCSymbol(Anchor, 0, PCRelativeLowFlag);
+ if (!LowOffset)
+ return std::unexpected(LowOffset.error());
+ if (LoadFromGOT) {
+ const MachineMemOperand *Memory = Instruction.memOperands().front();
+ if (Memory == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V global-address pseudo has a null memory operand");
+ auto AddedMemory = LowPending->addMemOperand(*Memory);
+ if (!AddedMemory)
+ return std::unexpected(AddedMemory.error());
+ }
+ auto Low = LowPending->build();
+ if (!Low)
+ return std::unexpected(Low.error());
+ auto LowDecoration = copyCommonDecoration(Instruction, **Low, false, true, true);
+ if (!LowDecoration)
+ return std::unexpected(LowDecoration.error());
+ auto Records =
+ Function.records().replaceInstructionReference(Instruction.stableID(), (*Low)->stableID());
+ if (!Records)
+ return std::unexpected(Records.error());
+ auto Removed = removeOldInstruction(Instruction);
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ return true;
+}
+
[[nodiscard]] bool isRegister(const MachineOperand &Operand, PhysicalRegister Reg) noexcept {
const Register *Value = Operand.getIf<Register>();
return Value != nullptr && Value->physicalRegister() == Reg;
@@ -601,6 +717,13 @@ public:
MachinePseudoExpansionPhase Phase,
MachineFunction &Function,
const TargetDescription &Target) const override {
+ if (Phase == MachinePseudoExpansionPhase::PreRA) {
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoLLA))
+ return expandAddressPseudo(Instruction, Function, Target, false);
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoLGA))
+ return expandAddressPseudo(Instruction, Function, Target, true);
+ return false;
+ }
if (Phase != MachinePseudoExpansionPhase::PostRA)
return false;
if (Instruction.opcode() == opcode(GenericOpcode::COPY))
diff --git a/backend/lib/Target/RISCV/RISCVRegisterInfo.rccdesc b/backend/lib/Target/RISCV/RISCVRegisterInfo.rccdesc
index 0a95adb..a2f26dc 100644
--- a/backend/lib/Target/RISCV/RISCVRegisterInfo.rccdesc
+++ b/backend/lib/Target/RISCV/RISCVRegisterInfo.rccdesc
@@ -388,7 +388,7 @@ register_masks:
preserved: [X1, X8, X9, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, F8_D, F9_D, F18_D, F19_D, F20_D, F21_D, F22_D, F23_D, F24_D, F25_D, F26_D, F27_D, F8_F, F9_F, F18_F, F19_F, F20_F, F21_F, F22_F, F23_F, F24_F, F25_F, F26_F, F27_F]
mir_operand_flags:
- direct_mask: 127
+ direct_mask: 255
direct:
- { name: riscv-call, value: 1 }
- { name: riscv-pcrel-hi, value: 2 }
@@ -397,4 +397,5 @@ mir_operand_flags:
- { name: riscv-copy-f64, value: 16 }
- { name: riscv-hi, value: 32 }
- { name: riscv-lo, value: 64 }
+ - { name: riscv-got-pcrel-hi, value: 128 }
bitmask: []
diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp
index b6370fd..4b3064d 100644
--- a/backend/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -171,7 +171,9 @@ bool RISCVSubtargetFeatures::has(RISCVSubtargetOption Option) const noexcept {
return (Options & optionBit(Option)) != 0;
}
-RISCVSubtarget::RISCVSubtarget(RISCVSubtargetFeatures Features) : Features(Features) {}
+RISCVSubtarget::RISCVSubtarget(RISCVSubtargetFeatures Features, RelocationModel Relocation,
+ CodeModel Code)
+ : Features(Features), Relocation(Relocation), Code(Code) {}
RISCVSubtarget::~RISCVSubtarget() = default;
diff --git a/backend/lib/Tooling/MIRFuzzer.cpp b/backend/lib/Tooling/MIRFuzzer.cpp
index dc6b8d1..7f1cc66 100644
--- a/backend/lib/Tooling/MIRFuzzer.cpp
+++ b/backend/lib/Tooling/MIRFuzzer.cpp
@@ -298,7 +298,7 @@ private:
auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features);
if (!Features)
return std::unexpected(Features.error());
- const riscv::RISCVSubtarget Subtarget(*Features);
+ const riscv::RISCVSubtarget Subtarget(*Features, Invocation.Relocation, Invocation.Code);
auto Names = riscv::canonicalPipelinePassNames(*Function, Subtarget);
if (!Names)
return std::unexpected(Names.error());
diff --git a/backend/lib/Tooling/PipelineDriver.cpp b/backend/lib/Tooling/PipelineDriver.cpp
index 42c33e7..76951b6 100644
--- a/backend/lib/Tooling/PipelineDriver.cpp
+++ b/backend/lib/Tooling/PipelineDriver.cpp
@@ -240,7 +240,7 @@ runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetD
riscv::RISCVSubtargetFeatures Features, bool AllowSnapshots,
MachinePassInstrumentation *Instrumentation) {
FunctionRunResult Result;
- const riscv::RISCVSubtarget Subtarget(Features);
+ const riscv::RISCVSubtarget Subtarget(Features, Invocation.Relocation, Invocation.Code);
MachinePassManagerOptions ManagerOptions{
.VerifyBefore = true,
.VerifyEach = Controls.VerifyEach,
diff --git a/backend/tools/MIRTool/MIRToolMain.cpp b/backend/tools/MIRTool/MIRToolMain.cpp
index d6e7d9e..2885b0f 100644
--- a/backend/tools/MIRTool/MIRToolMain.cpp
+++ b/backend/tools/MIRTool/MIRToolMain.cpp
@@ -920,7 +920,8 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe
rcc::riscv::RISCVSubtargetFeatures::fromFeatureList(Command.Invocation.Features);
if (!Features)
return std::unexpected(Features.error());
- const rcc::riscv::RISCVSubtarget Subtarget(*Features);
+ const rcc::riscv::RISCVSubtarget Subtarget(*Features, Command.Invocation.Relocation,
+ Command.Invocation.Code);
std::vector<std::string> Names;
for (std::size_t Index = 0; Index < Input->Document.unit().functionCount(); ++Index) {
const rcc::MachineFunction *Function = Input->Document.unit().functionAt(Index);
diff --git a/backend/utils/TableGen/Common/CodeGenInstruction.cpp b/backend/utils/TableGen/Common/CodeGenInstruction.cpp
index c314304..d4dbfee 100644
--- a/backend/utils/TableGen/Common/CodeGenInstruction.cpp
+++ b/backend/utils/TableGen/Common/CodeGenInstruction.cpp
@@ -110,13 +110,14 @@ instructionFlagEnumerator(std::string_view Value) noexcept {
[[nodiscard]] std::optional<std::string_view>
pseudoOwnerEnumerator(std::string_view Value) noexcept {
- static constexpr std::array<std::pair<std::string_view, std::string_view>, 12> Owners = {{
+ static constexpr std::array<std::pair<std::string_view, std::string_view>, 13> Owners = {{
{"none", "None"},
{"legalizer", "Legalizer"},
{"register_bank_select", "RegisterBankSelect"},
{"instruction_select", "InstructionSelect"},
{"phi_elimination", "PhiElimination"},
{"two_address_rewrite", "TwoAddressRewrite"},
+ {"pre_ra_expansion", "PreRAExpansion"},
{"register_allocator", "RegisterAllocator"},
{"pre_pei_expansion", "PrePEIExpansion"},
{"prologue_epilogue_insertion", "PrologueEpilogueInsertion"},