aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 03:02:45 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 03:02:45 +0800
commit888e9b5bb57a79f4eee88a7926cb859e04823361 (patch)
tree58cba25d087e43862ba7de139b49e126f6d7445c /backend
parent23dad063b9172982467b69650ae334bbec63e759 (diff)
downloadrcc-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.rccdesc237
-rw-r--r--backend/lib/Target/RISCV/RISCVInstPrinter.cpp1
-rw-r--r--backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp17
-rw-r--r--backend/unittests/Target/RISCVMCEncodingCoverageTest.cpp12
-rw-r--r--backend/unittests/Target/RISCVMCTest.cpp11
-rw-r--r--backend/unittests/Target/RISCVTargetTest.cpp22
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) {