aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/lib/Target/RISCV/RISCV.rccdesc4
-rw-r--r--backend/lib/Target/RISCV/RISCVCallLowering.cpp25
-rw-r--r--backend/lib/Target/RISCV/RISCVFrameLowering.cpp46
-rw-r--r--backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp32
-rw-r--r--backend/unittests/Target/RISCVCallLoweringTest.cpp35
-rw-r--r--backend/unittests/Target/RISCVFrameLoweringTest.cpp23
6 files changed, 80 insertions, 85 deletions
diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc
index f8e22d4..ea3a775 100644
--- a/backend/lib/Target/RISCV/RISCV.rccdesc
+++ b/backend/lib/Target/RISCV/RISCV.rccdesc
@@ -3351,6 +3351,8 @@ instructions:
- { kinds: [immediate, integer_immediate] }
- { kinds: [immediate, integer_immediate] }
num_explicit_defs: 0
+ implicit_defs: [{ register: X2 }]
+ implicit_uses: [{ register: X2 }]
flags: [pseudo, allowed_pre_legalizer, has_side_effects]
owner: prologue_epilogue_insertion
deadline: frame_finalized
@@ -3362,6 +3364,8 @@ instructions:
- { kinds: [immediate, integer_immediate] }
- { kinds: [immediate, integer_immediate] }
num_explicit_defs: 0
+ implicit_defs: [{ register: X2 }]
+ implicit_uses: [{ register: X2 }]
flags: [pseudo, allowed_pre_legalizer, has_side_effects]
owner: prologue_epilogue_insertion
deadline: frame_finalized
diff --git a/backend/lib/Target/RISCV/RISCVCallLowering.cpp b/backend/lib/Target/RISCV/RISCVCallLowering.cpp
index fd01d52..3a5805a 100644
--- a/backend/lib/Target/RISCV/RISCVCallLowering.cpp
+++ b/backend/lib/Target/RISCV/RISCVCallLowering.cpp
@@ -1172,20 +1172,20 @@ createMemoryOperand(MachineFunction &Function, MemoryAccessFlags Accesses, std::
[[nodiscard]] Expected<void> emitCallFrameAdjustment(MachineIRBuilder &Builder,
InstructionOpcode OpcodeValue,
- const CallFrameRequirements &Frame,
- MachineInstrFlag Flag) {
+ const CallFrameRequirements &Frame) {
+ if (Frame.SizeBytes > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RISC-V call-frame size does not fit a MIR immediate");
+ }
auto Instruction = Builder.buildInstr(targetOpcode(OpcodeValue));
if (!Instruction)
return std::unexpected(Instruction.error());
- auto Size = addUnsignedImmediate(*Instruction, Frame.SizeBytes);
+ auto Size = Instruction->addImmediate(static_cast<std::int64_t>(Frame.SizeBytes));
if (!Size)
return std::unexpected(Size.error());
- auto Align = addUnsignedImmediate(*Instruction, Frame.Align.bytes());
- if (!Align)
- return std::unexpected(Align.error());
- auto Flags = Instruction->setFlags({Flag});
- if (!Flags)
- return std::unexpected(Flags.error());
+ auto PreparedBytes = Instruction->addImmediate(0);
+ if (!PreparedBytes)
+ return std::unexpected(PreparedBytes.error());
auto Built = Instruction->build();
if (!Built)
return std::unexpected(Built.error());
@@ -1371,8 +1371,8 @@ emitOutgoingArguments(MachineIRBuilder &Builder, const CallLoweringPlan &Plan,
[[nodiscard]] Expected<void> emitCall(MachineIRBuilder &Builder, const CallLoweringPlan &Plan) {
if (Plan.callFrame().EmitSetup) {
- auto Down = emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKDOWN,
- Plan.callFrame(), MachineInstrFlag::FrameSetup);
+ auto Down =
+ emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKDOWN, Plan.callFrame());
if (!Down)
return std::unexpected(Down.error());
}
@@ -1388,8 +1388,7 @@ emitOutgoingArguments(MachineIRBuilder &Builder, const CallLoweringPlan &Plan,
return std::unexpected(Call.error());
if (Plan.callFrame().EmitDestroy) {
- auto Up = emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKUP, Plan.callFrame(),
- MachineInstrFlag::FrameDestroy);
+ auto Up = emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKUP, Plan.callFrame());
if (!Up)
return std::unexpected(Up.error());
}
diff --git a/backend/lib/Target/RISCV/RISCVFrameLowering.cpp b/backend/lib/Target/RISCV/RISCVFrameLowering.cpp
index e47a9c8..4ba5540 100644
--- a/backend/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/backend/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -102,29 +102,33 @@ constexpr std::uint8_t DwarfOpBaseRegisterExtended = 0x92U;
struct CallFrameRequirement final {
std::int64_t Amount = 0;
- std::int64_t Alignment = 0;
+ std::int64_t PreparedBytes = 0;
std::int64_t AlignedAmount = 0;
};
[[nodiscard]] Expected<CallFrameRequirement> callFrameRequirement(const MachineInstr &Instruction) {
- if (Instruction.operandCount() != 2) {
+ if (Instruction.operandCount() < 2) {
return makeUnexpected(ErrorCode::VerificationError,
- "RISC-V call-frame pseudo requires exactly amount and alignment");
+ "RISC-V call-frame pseudo requires amount and prepared-byte operands");
+ }
+ for (std::size_t Index = 2; Index < Instruction.operandCount(); ++Index) {
+ const MachineOperand *Operand = Instruction.operandAt(Index);
+ if (Operand == nullptr || !Operand->isRegister() || !Operand->isImplicit()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V call-frame pseudo has an unexpected explicit operand");
+ }
}
auto Amount = immediateValue(*Instruction.operandAt(0));
- auto RequestedAlignment = immediateValue(*Instruction.operandAt(1));
- if (!Amount || !RequestedAlignment || *Amount < 0 || *RequestedAlignment <= 0 ||
- !std::has_single_bit(static_cast<std::uint64_t>(*RequestedAlignment))) {
+ auto PreparedBytes = immediateValue(*Instruction.operandAt(1));
+ if (!Amount || !PreparedBytes || *Amount < 0 || *PreparedBytes < 0) {
return makeUnexpected(ErrorCode::VerificationError,
- "RISC-V call-frame amount or alignment is invalid");
+ "RISC-V call-frame amount or prepared-byte count is invalid");
}
- const std::uint64_t Alignment =
- std::max(StackAlignmentBytes, static_cast<std::uint64_t>(*RequestedAlignment));
- auto Aligned = alignTo(static_cast<std::uint64_t>(*Amount), Alignment);
+ auto Aligned = alignTo(static_cast<std::uint64_t>(*Amount), StackAlignmentBytes);
if (!Aligned || *Aligned > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())) {
return makeUnexpected(ErrorCode::FrameLayoutFailed, "RISC-V call-frame amount is too large");
}
- return CallFrameRequirement{*Amount, *RequestedAlignment, static_cast<std::int64_t>(*Aligned)};
+ return CallFrameRequirement{*Amount, *PreparedBytes, static_cast<std::int64_t>(*Aligned)};
}
[[nodiscard]] Expected<std::int64_t> callFrameAmount(const MachineInstr &Instruction) {
@@ -148,23 +152,6 @@ struct CallFrameRequirement final {
if (!Object.isTombstone() && !Object.description()->IsDead)
Result = std::max(Result, Object.description()->Align.bytes());
}
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next()) {
- for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
- Instruction = Instruction->next()) {
- if (Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKDOWN) &&
- Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKUP)) {
- continue;
- }
- if (Instruction->operandCount() < 2)
- continue;
- auto Requested = immediateValue(*Instruction->operandAt(1));
- if (Requested && *Requested > 0 &&
- std::has_single_bit(static_cast<std::uint64_t>(*Requested))) {
- Result = std::max(Result, static_cast<std::uint64_t>(*Requested));
- }
- }
- }
return Result;
}
@@ -314,7 +301,8 @@ struct CallFrameRequirement final {
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V call-frame destroy has no matching setup");
}
- if (Active->Amount != Requirement->Amount || Active->Alignment != Requirement->Alignment) {
+ if (Active->Amount != Requirement->Amount ||
+ Active->PreparedBytes != Requirement->PreparedBytes) {
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V call-frame setup and destroy requirements differ");
}
diff --git a/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp b/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp
index 81fc6dc..aee09a9 100644
--- a/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp
+++ b/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp
@@ -14,7 +14,6 @@
#include <algorithm>
#include <array>
-#include <bit>
#include <cstddef>
#include <cstdint>
#include <optional>
@@ -37,20 +36,6 @@ struct SpillForm final {
return RegisterClassID::fromValue(static_cast<std::uint32_t>(Value));
}
-[[nodiscard]] std::optional<std::int64_t> immediateValue(const MachineOperand &Operand) noexcept {
- if (const auto *Immediate = Operand.getIf<std::int64_t>())
- return *Immediate;
- const auto *Integer = Operand.getIf<IntegerImmediateOperand>();
- if (Integer == nullptr || Integer->Value.bitWidth() == 0 || Integer->Value.bitWidth() > 64) {
- return std::nullopt;
- }
- std::uint64_t Raw = Integer->Value.words().empty() ? 0 : Integer->Value.words().front();
- const std::uint32_t Width = Integer->Value.bitWidth();
- if (Width < 64 && (Raw & (std::uint64_t{1} << (Width - 1U))) != 0)
- Raw |= ~std::uint64_t{0} << Width;
- return std::bit_cast<std::int64_t>(Raw);
-}
-
[[nodiscard]] constexpr std::optional<SpillForm> spillForm(RegisterClassID Class) noexcept {
if (Class == registerClassID(RegisterClass::GPR) ||
Class == registerClassID(RegisterClass::GPRC) ||
@@ -129,23 +114,6 @@ public:
RequiredAlignment = std::max(RequiredAlignment, Object.description()->Align.bytes());
}
}
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next()) {
- for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
- Instruction = Instruction->next()) {
- if (Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKDOWN) &&
- Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKUP)) {
- continue;
- }
- if (Instruction->operandCount() < 2)
- continue;
- const auto Requested = immediateValue(*Instruction->operandAt(1));
- if (Requested && *Requested > 0 &&
- std::has_single_bit(static_cast<std::uint64_t>(*Requested))) {
- RequiredAlignment = std::max(RequiredAlignment, static_cast<std::uint64_t>(*Requested));
- }
- }
- }
const bool RequiresRealignment = RequiredAlignment > 16;
if (Reg.number() == static_cast<std::uint32_t>(PhysicalRegisterID::X9))
return RequiresRealignment;
diff --git a/backend/unittests/Target/RISCVCallLoweringTest.cpp b/backend/unittests/Target/RISCVCallLoweringTest.cpp
index d3685ae..1eaf146 100644
--- a/backend/unittests/Target/RISCVCallLoweringTest.cpp
+++ b/backend/unittests/Target/RISCVCallLoweringTest.cpp
@@ -483,6 +483,8 @@ void testOrdinaryAndIndirectEmission(TestContext &Context) {
return;
const auto Instructions = instructions(*Block);
+ rcc::MachineInstr *FrameDown = Instructions.empty() ? nullptr : Instructions.front();
+ rcc::MachineInstr *FrameUp = Instructions.size() > 3 ? Instructions[3] : nullptr;
rcc::MachineInstr *Call = findInstruction(*Block, rcc::riscv::InstructionOpcode::PseudoCALL);
Context.expect(Instructions.size() == 5 &&
Instructions.front()->opcode() ==
@@ -497,6 +499,39 @@ void testOrdinaryAndIndirectEmission(TestContext &Context) {
Call->operandAt(2)->kind() == rcc::MachineOperand::Kind::RegisterMask,
"ordinary emission must materialize canonical full-value copies, call-frame, "
"target, ID, and RegMask");
+ const rcc::Register StackPointer =
+ rcc::Register::fromPhysical(physical(rcc::riscv::PhysicalRegisterID::X2));
+ const auto HasStackPointerEffects = [StackPointer](const rcc::MachineInstr *Instruction) {
+ bool HasDef = false;
+ bool HasUse = false;
+ if (Instruction == nullptr)
+ return false;
+ for (const rcc::MachineOperand &Operand : Instruction->operands()) {
+ if (!Operand.isRegister() || !Operand.isImplicit() ||
+ Operand.registerValue() != StackPointer) {
+ continue;
+ }
+ HasDef |= Operand.isDef();
+ HasUse |= Operand.isUse();
+ }
+ return HasDef && HasUse;
+ };
+ const auto ImmediateAt = [](const rcc::MachineInstr *Instruction, std::size_t Index) {
+ const rcc::MachineOperand *Operand =
+ Instruction == nullptr ? nullptr : Instruction->operandAt(Index);
+ return Operand == nullptr ? nullptr : Operand->getIf<std::int64_t>();
+ };
+ const auto *DownAmount = ImmediateAt(FrameDown, 0);
+ const auto *DownPrepared = ImmediateAt(FrameDown, 1);
+ const auto *UpAmount = ImmediateAt(FrameUp, 0);
+ const auto *UpPrepared = ImmediateAt(FrameUp, 1);
+ Context.expect(
+ DownAmount != nullptr && *DownAmount == 0 && DownPrepared != nullptr && *DownPrepared == 0 &&
+ UpAmount != nullptr && *UpAmount == 0 && UpPrepared != nullptr && *UpPrepared == 0 &&
+ HasStackPointerEffects(FrameDown) && HasStackPointerEffects(FrameUp) &&
+ !FrameDown->flags().has(rcc::MachineInstrFlag::FrameSetup) &&
+ !FrameUp->flags().has(rcc::MachineInstrFlag::FrameDestroy),
+ "call-frame pseudos must use LLVM amount/prepared-byte operands and implicit SP effects");
bool HasArgumentUse = false;
bool HasResultDef = false;
for (const rcc::MachineOperand &Operand : Call->operands()) {
diff --git a/backend/unittests/Target/RISCVFrameLoweringTest.cpp b/backend/unittests/Target/RISCVFrameLoweringTest.cpp
index 7096840..95d6a18 100644
--- a/backend/unittests/Target/RISCVFrameLoweringTest.cpp
+++ b/backend/unittests/Target/RISCVFrameLoweringTest.cpp
@@ -347,7 +347,7 @@ buildMoveToDouble(rcc::MachineFunction &Function, const rcc::TargetDescription &
[[nodiscard]] rcc::Expected<rcc::MachineInstr *>
buildCallFramePseudo(rcc::MachineFunction &Function, const rcc::TargetDescription &Target,
rcc::MachineBasicBlock &Block, rcc::riscv::InstructionOpcode OpcodeValue,
- std::int64_t Amount, std::int64_t Alignment = 16) {
+ std::int64_t Amount, std::int64_t PreparedBytes = 0) {
rcc::MachineIRBuilder Builder(Function, Target);
if (auto Result = Builder.setInsertPoint(Block); !Result)
return std::unexpected(Result.error());
@@ -356,7 +356,7 @@ buildCallFramePseudo(rcc::MachineFunction &Function, const rcc::TargetDescriptio
return std::unexpected(Pending.error());
if (auto Result = Pending->addImmediate(Amount); !Result)
return std::unexpected(Result.error());
- if (auto Result = Pending->addImmediate(Alignment); !Result)
+ if (auto Result = Pending->addImmediate(PreparedBytes); !Result)
return std::unexpected(Result.error());
return Pending->build();
}
@@ -804,14 +804,14 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target)
auto Computed = createFunction("computed-call-frame", 17);
if (!Computed)
return;
- auto ComputedOutgoingAlign = rcc::Alignment::create(16);
+ auto ComputedOutgoingAlign = rcc::Alignment::create(64);
if (!ComputedOutgoingAlign)
return;
rcc::StackObjectDesc ComputedOutgoingDescription;
ComputedOutgoingDescription.Kind = rcc::StackObjectKind::Target;
ComputedOutgoingDescription.Size = 8;
ComputedOutgoingDescription.Align = *ComputedOutgoingAlign;
- ComputedOutgoingDescription.LocalOffset = 48;
+ ComputedOutgoingDescription.LocalOffset = 0;
ComputedOutgoingDescription.TargetFlags =
static_cast<std::uint64_t>(rcc::riscv::CallStackObjectFlag::OutgoingArgument);
auto ComputedOutgoing =
@@ -825,9 +825,9 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target)
rcc::riscv::InstructionOpcode::SD,
physical(rcc::riscv::PhysicalRegisterID::X11), *ComputedLocal, 0) ||
!buildCallFramePseudo(*Computed->Function, Target, *Computed->Block,
- rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 48, 64) ||
+ rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 64) ||
!buildCallFramePseudo(*Computed->Function, Target, *Computed->Block,
- rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 48, 64) ||
+ rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 64) ||
!buildReturn(*Computed->Function, Target, *Computed->Block)) {
return;
}
@@ -846,7 +846,7 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target)
!buildCallFramePseudo(*Mismatched->Function, Target, *Mismatched->Block,
rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 48, 16) ||
!buildCallFramePseudo(*Mismatched->Function, Target, *Mismatched->Block,
- rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 48, 32) ||
+ rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 48, 24) ||
!buildReturn(*Mismatched->Function, Target, *Mismatched->Block)) {
return;
}
@@ -877,17 +877,18 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target)
return;
auto Variable =
createStackObject(*Dynamic->Function, rcc::StackObjectKind::DynamicAlloca, std::nullopt, 16);
- if (!Variable ||
+ auto OverAligned = createStackObject(*Dynamic->Function, rcc::StackObjectKind::Default, 8, 32);
+ if (!Variable || !OverAligned ||
!buildCallFramePseudo(*Dynamic->Function, Target, *Dynamic->Block,
- rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 4096, 32) ||
+ rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 4096) ||
!buildCallFramePseudo(*Dynamic->Function, Target, *Dynamic->Block,
- rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 4096, 32) ||
+ rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 4096) ||
!buildReturn(*Dynamic->Function, Target, *Dynamic->Block)) {
return;
}
Context.expect(rcc::riscv::registerAllocationInfo().isReservedForFunction(
*Dynamic->Function, physReg(rcc::riscv::PhysicalRegisterID::X9), Target),
- "over-aligned call frames must reserve BP before register allocation");
+ "over-aligned dynamic frames must reserve BP before register allocation");
auto DynamicResult = runFrameLowering(*Dynamic->Function, Target);
Context.expect(
DynamicResult &&