aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 01:50:59 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 01:50:59 +0800
commit068514ea70bd39ce6260c8c23982e702bafc2ab9 (patch)
tree53ce8d292cbfac7b6927046fcbbfc311ef380a1f /backend/unittests
parent4937c5107848f1c60262ef729d466e8d90df8d47 (diff)
downloadrcc-project-068514ea70bd39ce6260c8c23982e702bafc2ab9.tar.gz
rcc-project-068514ea70bd39ce6260c8c23982e702bafc2ab9.tar.xz
[RISCV] Legalize llvm.va_copy
Diffstat (limited to 'backend/unittests')
-rw-r--r--backend/unittests/CodeGen/TargetMIRTextInfoTest.cpp9
-rw-r--r--backend/unittests/Target/RISCVCodeGenTest.cpp81
2 files changed, 87 insertions, 3 deletions
diff --git a/backend/unittests/CodeGen/TargetMIRTextInfoTest.cpp b/backend/unittests/CodeGen/TargetMIRTextInfoTest.cpp
index d7e2f13..24945bd 100644
--- a/backend/unittests/CodeGen/TargetMIRTextInfoTest.cpp
+++ b/backend/unittests/CodeGen/TargetMIRTextInfoTest.cpp
@@ -109,9 +109,12 @@ void testTextSchemaQueries(TestContext &Context) {
!Text->machineMemOperandFlagNames(0x4) && !Text->virtualRegisterFlagNames(0x4),
"MMO and virtual-register flags must reject every unregistered bit");
- Context.expect(Text->intrinsic("llvm.test.seven") == rcc::IntrinsicID::fromValue(7) &&
- Text->intrinsicName(rcc::IntrinsicID::fromValue(17)) == "llvm.test.seventeen",
- "intrinsic names and strong IDs must round-trip");
+ Context.expect(
+ Text->intrinsic("llvm.test.seven") == rcc::IntrinsicID::fromValue(7) &&
+ Text->intrinsicName(rcc::IntrinsicID::fromValue(17)) == "llvm.test.seventeen" &&
+ Text->intrinsic("llvm.va_copy") == rcc::intrinsicID(rcc::GenericIntrinsic::VACopy) &&
+ Text->intrinsicName(rcc::intrinsicID(rcc::GenericIntrinsic::VACopy)) == "llvm.va_copy",
+ "intrinsic names and strong IDs must round-trip");
const auto G0 = phys(rcc::test::TestRegister::G0);
Context.expect(Text->dwarfRegister(G0) == rcc::test::TestRegister::G0 &&
diff --git a/backend/unittests/Target/RISCVCodeGenTest.cpp b/backend/unittests/Target/RISCVCodeGenTest.cpp
index fcf0e57..4f675a4 100644
--- a/backend/unittests/Target/RISCVCodeGenTest.cpp
+++ b/backend/unittests/Target/RISCVCodeGenTest.cpp
@@ -15,6 +15,7 @@
#include <cstdint>
#include <iostream>
#include <memory>
+#include <span>
#include <string>
#include <string_view>
#include <vector>
@@ -1458,6 +1459,85 @@ void testUnsupportedTypes(TestContext &Context) {
"unsupported selection diagnostics must name the rejected opcode");
}
+void testVACopyLegalization(TestContext &Context) {
+ auto Target = rcc::riscv::createTargetDescription();
+ Context.expect(Target.has_value(), "RV64GC target must be available for va_copy legalization");
+ if (!Target)
+ return;
+ Context.expect(Target->mirText().intrinsic("llvm.va_copy") ==
+ rcc::intrinsicID(rcc::GenericIntrinsic::VACopy),
+ "RV64GC MIR text must expose the generic va_copy intrinsic identity");
+
+ auto Function =
+ rcc::MachineFunction::create("riscv_vacopy", rcc::MachineFunctionStableID::fromValue(102));
+ if (!Function)
+ return;
+ auto Block = (*Function)->createBasicBlock();
+ auto Pointer = rcc::LLT::makePointer(0, 64);
+ if (!Block || !Pointer || !(*Function)->appendBlock(**Block))
+ return;
+ auto Destination = (*Function)->registerInfo().createVirtualRegister(*Pointer);
+ auto Source = (*Function)->registerInfo().createVirtualRegister(*Pointer);
+ if (!Destination || !Source)
+ return;
+
+ rcc::MachineIRBuilder Builder(**Function, *Target);
+ if (!Builder.setInsertPoint(**Block))
+ return;
+ auto Pending = Builder.buildInstr(rcc::opcode(rcc::GenericOpcode::G_INTRINSIC_W_SIDE_EFFECTS));
+ if (!Pending || !Pending->addIntrinsic(rcc::intrinsicID(rcc::GenericIntrinsic::VACopy)) ||
+ !Pending->addUse(*Destination) || !Pending->addUse(*Source)) {
+ return;
+ }
+ auto Built = Pending->build();
+ if (!Built)
+ return;
+ auto Action = rcc::riscv::legalizerInfo().classify(**Built, **Function, *Target);
+ Context.expect(Action && *Action == rcc::LegalizationAction::Custom,
+ "RV64GC must custom-legalize va_copy");
+ if (!Action)
+ return;
+ auto Lowered = rcc::riscv::legalizerInfo().lower(**Built, **Function, *Target, *Action);
+ Context.expect(Lowered.has_value(), "RV64GC va_copy legalization must succeed");
+ if (!Lowered)
+ return;
+
+ rcc::MachineInstr *Load = (*Function)->firstBlock()->firstInstruction();
+ rcc::MachineInstr *Store = Load == nullptr ? nullptr : Load->next();
+ const rcc::Register *Loaded = Load == nullptr || Load->operandAt(0) == nullptr
+ ? nullptr
+ : Load->operandAt(0)->getIf<rcc::Register>();
+ const rcc::Register *LoadAddress = Load == nullptr || Load->operandAt(1) == nullptr
+ ? nullptr
+ : Load->operandAt(1)->getIf<rcc::Register>();
+ const rcc::Register *Stored = Store == nullptr || Store->operandAt(0) == nullptr
+ ? nullptr
+ : Store->operandAt(0)->getIf<rcc::Register>();
+ const rcc::Register *StoreAddress = Store == nullptr || Store->operandAt(1) == nullptr
+ ? nullptr
+ : Store->operandAt(1)->getIf<rcc::Register>();
+ Context.expect(
+ (*Built)->parent() == nullptr && Load != nullptr && Store != nullptr &&
+ Store->next() == nullptr && Load->opcode() == rcc::opcode(rcc::GenericOpcode::G_LOAD) &&
+ Store->opcode() == rcc::opcode(rcc::GenericOpcode::G_STORE) && Loaded != nullptr &&
+ Stored != nullptr && *Loaded == *Stored && LoadAddress != nullptr &&
+ *LoadAddress == *Source && StoreAddress != nullptr && *StoreAddress == *Destination,
+ "va_copy must become a pointer load followed by a store to the destination list");
+ const auto LoadMemory =
+ Load == nullptr ? std::span<const rcc::MachineMemOperand *const>{} : Load->memOperands();
+ const auto StoreMemory =
+ Store == nullptr ? std::span<const rcc::MachineMemOperand *const>{} : Store->memOperands();
+ Context.expect(
+ LoadMemory.size() == 1 && StoreMemory.size() == 1 &&
+ LoadMemory.front()->description().Accesses.has(rcc::MemoryAccessFlag::Load) &&
+ StoreMemory.front()->description().Accesses.has(rcc::MemoryAccessFlag::Store) &&
+ LoadMemory.front()->description().Size.minimumBytes() == 8 &&
+ StoreMemory.front()->description().Size.minimumBytes() == 8 &&
+ LoadMemory.front()->description().MemoryType == *Pointer &&
+ StoreMemory.front()->description().MemoryType == *Pointer,
+ "va_copy expansion must attach complete pointer-sized load/store memory operands");
+}
+
void testMemoryOffsetSelection(TestContext &Context) {
auto Target = rcc::riscv::createTargetDescription();
Context.expect(Target.has_value(), "RV64GC target must be available for memory selection");
@@ -1541,6 +1621,7 @@ int main() {
testMultiplyLibcallWithoutM(Context);
testAtomicSelection(Context);
testUnsupportedTypes(Context);
+ testVACopyLegalization(Context);
testMemoryOffsetSelection(Context);
return Context.result();
}