diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-12 03:02:45 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-12 03:02:45 +0800 |
| commit | 888e9b5bb57a79f4eee88a7926cb859e04823361 (patch) | |
| tree | 58cba25d087e43862ba7de139b49e126f6d7445c /backend | |
| parent | 23dad063b9172982467b69650ae334bbec63e759 (diff) | |
| download | rcc-project-888e9b5bb57a79f4eee88a7926cb859e04823361.tar.gz rcc-project-888e9b5bb57a79f4eee88a7926cb859e04823361.tar.xz | |
[RISCV] Add Zba and Zbb instruction descriptions
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/lib/Target/RISCV/RISCV.rccdesc | 237 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVInstPrinter.cpp | 1 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp | 17 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVMCEncodingCoverageTest.cpp | 12 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVMCTest.cpp | 11 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVTargetTest.cpp | 22 |
6 files changed, 292 insertions, 8 deletions
diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc index bbf70b7..13fd03a 100644 --- a/backend/lib/Target/RISCV/RISCV.rccdesc +++ b/backend/lib/Target/RISCV/RISCV.rccdesc @@ -450,6 +450,7 @@ assembly_formats: - { id: 32, symbol: RS2_OFFSET_SP, name: rs2-offset-sp } - { id: 33, symbol: FRD_OFFSET_SP, name: frd-offset-sp } - { id: 34, symbol: FRS2_OFFSET_SP, name: frs2-offset-sp } + - { id: 35, symbol: RD_RS1, name: rd-rs1 } instructions: - @@ -1522,6 +1523,242 @@ instructions: encoding_category: I assembly_format: RD_RS1_IMM - + id: 1247 + symbol: SH1ADD + name: SH1ADD + assembly_mnemonic: sh1add + encoding: 547660851 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1248 + symbol: SH2ADD + name: SH2ADD + assembly_mnemonic: sh2add + encoding: 547669043 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1249 + symbol: SH3ADD + name: SH3ADD + assembly_mnemonic: sh3add + encoding: 547677235 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1250 + symbol: SH1ADD_UW + name: SH1ADD_UW + assembly_mnemonic: sh1add.uw + encoding: 547660859 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1251 + symbol: SH2ADD_UW + name: SH2ADD_UW + assembly_mnemonic: sh2add.uw + encoding: 547669051 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1252 + symbol: SH3ADD_UW + name: SH3ADD_UW + assembly_mnemonic: sh3add.uw + encoding: 547677243 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1253 + symbol: SLLI_UW + name: SLLI_UW + assembly_mnemonic: slli.uw + encoding: 135566363 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: UIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1254 + symbol: ADD_UW + name: ADD_UW + assembly_mnemonic: add.uw + encoding: 144999483 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1255 + symbol: SEXT_B + name: SEXT_B + assembly_mnemonic: sext.b + encoding: 1615107091 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1 + - + id: 1256 + symbol: SEXT_H + name: SEXT_H + assembly_mnemonic: sext.h + encoding: 1616155667 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1 + - + id: 1257 + symbol: ZEXT_H_RV32 + name: ZEXT_H_RV32 + assembly_mnemonic: zext.h + encoding: 134530099 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1 + - + id: 1258 + symbol: ZEXT_H_RV64 + name: ZEXT_H_RV64 + assembly_mnemonic: zext.h + encoding: 134530107 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1 + - + id: 1259 + symbol: MIN + name: MIN + assembly_mnemonic: min + encoding: 178570291 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1260 + symbol: MINU + name: MINU + assembly_mnemonic: minu + encoding: 178574387 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1261 + symbol: MAX + name: MAX + assembly_mnemonic: max + encoding: 178578483 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1262 + symbol: MAXU + name: MAXU + assembly_mnemonic: maxu + encoding: 178582579 + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - id: 1096 symbol: LR_W name: LR_W diff --git a/backend/lib/Target/RISCV/RISCVInstPrinter.cpp b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp index ec17b07..e72681a 100644 --- a/backend/lib/Target/RISCV/RISCVInstPrinter.cpp +++ b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp @@ -48,6 +48,7 @@ constexpr std::array LinearFormats{ LinearFormat{"rs1-target", 2}, LinearFormat{"rs1", 1}, LinearFormat{"rd-rs2", 2}, + LinearFormat{"rd-rs1", 2}, }; [[nodiscard]] const AssemblyFormatInfo *assemblyFormat(AssemblyFormatID ID) noexcept { diff --git a/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp b/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp index 81ac0f1..9ba3021 100644 --- a/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp +++ b/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp @@ -270,6 +270,7 @@ namespace { break; case AssemblyFormat::RD_FRS1: case AssemblyFormat::FRD_RS1: + case AssemblyFormat::RD_RS1: RegisterCount = 2; break; default: @@ -358,6 +359,18 @@ namespace { static_cast<std::uint32_t>(*Predecessor) << 24U | static_cast<std::uint32_t>(*Successor) << 20U; } + if (Format == AssemblyFormat::RD_RS1) { + auto Count = requireOperandCount(Instruction, 2); + if (!Count) + return std::unexpected(Count.error()); + auto Destination = registerEncoding(Instruction, 0, Target); + auto Source = registerEncoding(Instruction, 1, Target); + if (!Destination) + return std::unexpected(Destination.error()); + if (!Source) + return std::unexpected(Source.error()); + return (Assembly.Encoding & ~std::uint32_t{0x000f8f80}) | *Destination << 7U | *Source << 15U; + } if (Format != AssemblyFormat::RD_RS1_IMM && Format != AssemblyFormat::RD_OFFSET_RS1 && Format != AssemblyFormat::FRD_OFFSET_RS1) { return makeUnexpected(ErrorCode::InstructionEncodingFailed, @@ -376,8 +389,8 @@ namespace { (Assembly.Encoding & ~std::uint32_t{0x000f8f80}) | *Destination << 7U | *Source << 15U; const auto Opcode = static_cast<InstructionOpcode>(Instruction.opcode().value()); - const bool Shift64 = Opcode == InstructionOpcode::SLLI || Opcode == InstructionOpcode::SRLI || - Opcode == InstructionOpcode::SRAI; + const bool Shift64 = Opcode == InstructionOpcode::SLLI || Opcode == InstructionOpcode::SLLI_UW || + Opcode == InstructionOpcode::SRLI || Opcode == InstructionOpcode::SRAI; const bool Shift32 = Opcode == InstructionOpcode::SLLIW || Opcode == InstructionOpcode::SRLIW || Opcode == InstructionOpcode::SRAIW; if (Shift64 || Shift32) { diff --git a/backend/unittests/Target/RISCVMCEncodingCoverageTest.cpp b/backend/unittests/Target/RISCVMCEncodingCoverageTest.cpp index d66d19d..1a7157a 100644 --- a/backend/unittests/Target/RISCVMCEncodingCoverageTest.cpp +++ b/backend/unittests/Target/RISCVMCEncodingCoverageTest.cpp @@ -117,6 +117,7 @@ createStandardFixture(const rcc::InstructionDescriptor &Descriptor, addRegister(Result, Descriptor, Source1Encoding); addImmediate(Result, (Encoding >> 12U) & 7U); return Result; + case RD_RS1: case RD_FRS1: addRegister(Result, Descriptor, DestinationEncoding); addRegister(Result, Descriptor, Source1Encoding); @@ -138,12 +139,17 @@ createStandardFixture(const rcc::InstructionDescriptor &Descriptor, addImmediate(Result, (Encoding >> 20U) & 0xfU); return Result; } + if (Format == RD_RS1) { + addRegister(Result, Descriptor, DestinationEncoding); + addRegister(Result, Descriptor, Source1Encoding); + return Result; + } const bool FloatingDestination = Format == FRD_OFFSET_RS1; if (Format != RD_RS1_IMM && Format != RD_OFFSET_RS1 && !FloatingDestination) return fixtureError("unsupported I-type reference fixture format"); addRegister(Result, Descriptor, DestinationEncoding); addRegister(Result, Descriptor, Source1Encoding); - const bool Shift64 = Opcode == SLLI || Opcode == SRLI || Opcode == SRAI; + const bool Shift64 = Opcode == SLLI || Opcode == SLLI_UW || Opcode == SRLI || Opcode == SRAI; const bool Shift32 = Opcode == SLLIW || Opcode == SRLIW || Opcode == SRAIW; if (Shift64) addImmediate(Result, (Encoding >> 20U) & 0x3fU); @@ -387,8 +393,8 @@ int main() { } const std::span<const rcc::riscv::AssemblyInstructionInfo> Instructions = rcc::riscv::assemblyInstructions(); - if (Instructions.size() != 195) { - std::cerr << "RV64GC encoding coverage does not contain all 195 instructions\n"; + if (Instructions.size() != 211) { + std::cerr << "RISC-V encoding coverage does not contain all 211 instructions\n"; return 1; } diff --git a/backend/unittests/Target/RISCVMCTest.cpp b/backend/unittests/Target/RISCVMCTest.cpp index 1064cf3..d77899a 100644 --- a/backend/unittests/Target/RISCVMCTest.cpp +++ b/backend/unittests/Target/RISCVMCTest.cpp @@ -90,6 +90,12 @@ symbolExpression(rcc::mc::MCContext &Context, std::string_view Name, std::uint32 {0x13, 0x86, 0xf6, 0xfe}, "ADDI") && expectEncoding(Emitter, instruction(SRAI, {reg(X14), reg(X15), imm(63)}), {0x13, 0xd7, 0xf7, 0x43}, "SRAI") && + expectEncoding(Emitter, instruction(SH1ADD, {reg(X8), reg(X9), reg(X10)}), + {0x33, 0xa4, 0xa4, 0x20}, "SH1ADD") && + expectEncoding(Emitter, instruction(SEXT_B, {reg(X8), reg(X9)}), {0x13, 0x94, 0x44, 0x60}, + "SEXT.B") && + expectEncoding(Emitter, instruction(ZEXT_H_RV64, {reg(X8), reg(X9)}), + {0x3b, 0xc4, 0x04, 0x08}, "ZEXT.H") && expectEncoding(Emitter, instruction(SD, {reg(X16), reg(X17), imm(-32)}), {0x23, 0xb0, 0x08, 0xff}, "SD") && expectEncoding(Emitter, instruction(BGE, {reg(X18), reg(X19), imm(18)}), @@ -297,6 +303,11 @@ int main() { static_cast<std::uint32_t>(rcc::riscv::RISCVMCExprKind::AbsoluteLow), "symbol"); if (!PrintedHigh || *PrintedHigh != "%hi(symbol)" || !PrintedLow || *PrintedLow != "%lo(symbol)") return fail("RISC-V absolute address modifiers do not print canonically"); + auto PrintedUnary = Printer.printInstruction(instruction( + rcc::riscv::InstructionOpcode::SEXT_B, + {reg(rcc::riscv::PhysicalRegisterID::X8), reg(rcc::riscv::PhysicalRegisterID::X9)})); + if (!PrintedUnary || *PrintedUnary != "sext.b x8, x9") + return fail("RISC-V unary integer instructions do not print canonically"); if (!testEncodings(Emitter)) return fail("RISC-V MC encodings differ from the RV64GC reference encodings"); if (!testFixups(Emitter, Backend)) diff --git a/backend/unittests/Target/RISCVTargetTest.cpp b/backend/unittests/Target/RISCVTargetTest.cpp index 555db4c..40f5f76 100644 --- a/backend/unittests/Target/RISCVTargetTest.cpp +++ b/backend/unittests/Target/RISCVTargetTest.cpp @@ -164,7 +164,7 @@ void testABIAndDebugFacts(TestContext &Context) { void testInstructionFacts(TestContext &Context) { constexpr std::size_t TargetInstructionCount = - static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::WriteFFLAGS) - + static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::MAXU) - static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::LUI) + 1U; auto Target = rcc::riscv::createTargetDescription(); Context.expect(Target.has_value(), "RV64GC target description must be structurally valid"); @@ -183,6 +183,14 @@ void testInstructionFacts(TestContext &Context) { rcc::Opcode::fromValue(static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::FADD_S))); const auto *Atomic = Target->instructionDescriptor( rcc::Opcode::fromValue(static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::LR_W))); + const auto *ShiftAdd = Target->instructionDescriptor( + rcc::Opcode::fromValue(static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::SH1ADD))); + const auto *ShiftLeftUnsignedWord = Target->instructionDescriptor( + rcc::Opcode::fromValue(static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::SLLI_UW))); + const auto *SignExtendByte = Target->instructionDescriptor( + rcc::Opcode::fromValue(static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::SEXT_B))); + const auto *SignedMinimum = Target->instructionDescriptor( + rcc::Opcode::fromValue(static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::MIN))); const auto *Compressed = Target->instructionDescriptor(rcc::Opcode::fromValue( static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::C_ADDI16SP))); const auto *GenericAdd = Target->instructionDescriptor(rcc::opcode(rcc::GenericOpcode::G_ADD)); @@ -260,12 +268,20 @@ void testInstructionFacts(TestContext &Context) { rcc::opcode(rcc::GenericOpcode::G_LOAD), std::span<const rcc::MachineMemOperand *const>{}), "target memory operands must be optional while generic memory operands remain required"); + Context.expect(ShiftAdd != nullptr && ShiftAdd->Operands.size() == 3 && + ShiftLeftUnsignedWord != nullptr && + ShiftLeftUnsignedWord->Operands.size() == 3 && + ShiftLeftUnsignedWord->Operands.back().ImmediatePredicate && + SignExtendByte != nullptr && SignExtendByte->Operands.size() == 2 && + SignedMinimum != nullptr && SignedMinimum->Operands.size() == 3 && + SignedMinimum->Flags.has(rcc::InstructionFlag::Commutable), + "RISC-V Zba and Zbb instructions must expose complete generated constraints"); const auto Schedules = rcc::riscv::schedulingClasses(); const auto Encodings = rcc::riscv::encodingCategories(); const auto Formats = rcc::riscv::assemblyFormats(); - Context.expect(Schedules.size() == 15 && Encodings.size() == 10 && Formats.size() == 34 && - rcc::riscv::assemblyInstructions().size() == 195 && FenceAssembly != nullptr && + Context.expect(Schedules.size() == 15 && Encodings.size() == 10 && Formats.size() == 35 && + rcc::riscv::assemblyInstructions().size() == 211 && FenceAssembly != nullptr && FenceAssembly->Mnemonic == "fence.i" && std::ranges::any_of(Schedules, [](const rcc::riscv::SchedulingClassInfo &Class) { |
