From 207dcff41af6e933ba55b4afb9c268a3a9e4a624 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Fri, 14 Mar 2025 11:03:14 +0100 Subject: [PATCH 1/6] [pattern-gen] Support 48-bit encodings --- llvm/tools/pattern-gen/lib/Parser.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/llvm/tools/pattern-gen/lib/Parser.cpp b/llvm/tools/pattern-gen/lib/Parser.cpp index 703f245b1ce9..cd507608314a 100644 --- a/llvm/tools/pattern-gen/lib/Parser.cpp +++ b/llvm/tools/pattern-gen/lib/Parser.cpp @@ -1260,7 +1260,7 @@ void ParseEncoding(TokenStream &ts, CDSLInstr &instr) { pop_cur(ts, EncodingKeyword); pop_cur(ts, Colon); - uint offset = 32; + uint offset = 48; uint preDefIdx = instr.fields.size(); while (1) { @@ -1329,8 +1329,19 @@ void ParseEncoding(TokenStream &ts, CDSLInstr &instr) { syntax_error(ts); } if (pop_cur_if(ts, Semicolon)) { - if (offset != 0) - error("instruction length is not 32 bits", ts); + if (offset != 0) { + if (offset != 16) { + error("instruction length is not 32 or 48 bits", ts); + } + // Shift the field offsets by 16 bits + for (auto &frag : instr.frags) + if (frag.idx == 255) { + frag.srcOffset = frag.srcOffset - offset; + frag.dstOffset = frag.dstOffset - offset; + } else { + frag.dstOffset = frag.dstOffset - offset; + } + } break; } pop_cur(ts, BitwiseConcat); From 04e4cc9f224f8416f739e87c85a6d01be7a87603 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Fri, 14 Mar 2025 12:05:19 +0100 Subject: [PATCH 2/6] [pattern-gen] Support 48-bit instrs in InstrInfo.otd --- llvm/tools/pattern-gen/lib/InstrInfo.cpp | 5 ++++- llvm/tools/pattern-gen/lib/InstrInfo.hpp | 1 + llvm/tools/pattern-gen/lib/Parser.cpp | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/llvm/tools/pattern-gen/lib/InstrInfo.cpp b/llvm/tools/pattern-gen/lib/InstrInfo.cpp index 5cb5f2ac5432..b153ca0a08bd 100644 --- a/llvm/tools/pattern-gen/lib/InstrInfo.cpp +++ b/llvm/tools/pattern-gen/lib/InstrInfo.cpp @@ -6,8 +6,11 @@ std::string EncodingToTablgen(CDSLInstr const& instr) { std::stringstream s; + uint8_t size = instr.size; + std::string base = (size == 48 ? "RVInst48" : "RVInst"); + s << "class RVInst_" << instr.name << "" - << " : RVInst {\n"; + << " : " << base << " {\n"; for (auto const& f : instr.fields) if (f.type & (CDSLInstr::FieldType::NON_CONST)) diff --git a/llvm/tools/pattern-gen/lib/InstrInfo.hpp b/llvm/tools/pattern-gen/lib/InstrInfo.hpp index 9e26b1d21532..0ac896941437 100644 --- a/llvm/tools/pattern-gen/lib/InstrInfo.hpp +++ b/llvm/tools/pattern-gen/lib/InstrInfo.hpp @@ -40,6 +40,7 @@ struct CDSLInstr FieldType type; }; + uint8_t size; std::string name; std::string mnemonic; std::string argString; diff --git a/llvm/tools/pattern-gen/lib/Parser.cpp b/llvm/tools/pattern-gen/lib/Parser.cpp index cd507608314a..ce1ce027b78a 100644 --- a/llvm/tools/pattern-gen/lib/Parser.cpp +++ b/llvm/tools/pattern-gen/lib/Parser.cpp @@ -1329,6 +1329,8 @@ void ParseEncoding(TokenStream &ts, CDSLInstr &instr) { syntax_error(ts); } if (pop_cur_if(ts, Semicolon)) { + uint size = 48 - offset; + instr.size = size; if (offset != 0) { if (offset != 16) { error("instruction length is not 32 or 48 bits", ts); From 9b2a39b353d38b5c5bfd13f8da171a5fef69aa44 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Fri, 14 Mar 2025 12:18:49 +0100 Subject: [PATCH 3/6] Add CDSL examples for 48-bit instrs --- core_descs/ExampleRV32K.core_desc | 62 ++++++++++++++++++++++ core_descs/ExampleRV32K.ll | 86 +++++++++++++++++++++++++++++++ core_descs/ExampleRV32K.td | 33 ++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 core_descs/ExampleRV32K.core_desc create mode 100644 core_descs/ExampleRV32K.ll create mode 100644 core_descs/ExampleRV32K.td diff --git a/core_descs/ExampleRV32K.core_desc b/core_descs/ExampleRV32K.core_desc new file mode 100644 index 000000000000..5e8db20bf3d6 --- /dev/null +++ b/core_descs/ExampleRV32K.core_desc @@ -0,0 +1,62 @@ +// RUN: pattern-gen %s -O 3 --mattr=+m --riscv-xlen 32 | FileCheck --check-prefixes=CHECK-RV32,CHECK-RV32-EXTEND -allow-unused-prefixes %s +// RUN: pattern-gen %s -O 3 --no-extend --mattr=+m --riscv-xlen 32 | FileCheck --check-prefixes=CHECK-RV32,CHECK-RV32-NOEXTED -allow-unused-prefixes %s + +InstructionSet XExampleRV32 extends RISCVBase { + instructions { + // CHECK-RV32: Pattern for K_LLI: (i32 uimm32:$imm) + K_LLI { + encoding: 4'b0000 :: imm[31:0] :: rd[4:0] :: 7'b1011111; + assembly: {"k.lli", "{name(rd)}, {imm}"}; + behavior: { + if ((rd % RFS) != 0) + // imm -> unsigned! + // X[rd % RFS] = (unsigned) ((unsigned) imm); + X[rd] = (unsigned) ((unsigned) imm); + } + } + // CHECK-RV32: Pattern for K_ADDI: (add GPR:$rs1, (i32 uimm24:$imm)) + K_ADDI { + encoding: 4'b0001 :: imm[23:0] :: rs1[4:0] :: 3'b000 :: rd[4:0] :: 7'b1011111; + assembly: {"k.addi", "{name(rd)}, {name(rs1)}, {imm}"}; + behavior: { + if ((rd % RFS) != 0) { + // X[rd % RFS] = X[rs1 % RFS] + (signed)imm; + X[rd] = X[rs1] + (signed)imm; + } + } + } + // CHECK-RV32: Pattern for K_ANDI: (and GPR:$rs1, (i32 uimm24:$imm)) + K_ANDI { + encoding: 4'b0001 :: imm[23:0] :: rs1[4:0] :: 3'b001 :: rd[4:0] :: 7'b1011111; + assembly: {"k.andi", "{name(rd)}, {name(rs1)}, {imm}"}; + behavior: { + if ((rd % RFS) != 0) { + // X[rd % RFS] = X[rs1 % RFS] & (unsigned)imm; + X[rd] = X[rs1] & (unsigned)imm; + } + } + } + // CHECK-RV32: Pattern for K_XORI: (xor GPR:$rs1, (i32 uimm24:$imm)) + K_XORI { + encoding: 4'b0001 :: imm[23:0] :: rs1[4:0] :: 3'b010 :: rd[4:0] :: 7'b1011111; + assembly: {"k.xori", "{name(rd)}, {name(rs1)}, {imm}"}; + behavior: { + if ((rd % RFS) != 0) { + // X[rd % RFS] = X[rs1 % RFS] ^ (unsigned)imm; + X[rd] = X[rs1] ^ (unsigned)imm; + } + } + } + // CHECK-RV32: Pattern for K_ORI: (or GPR:$rs1, (i32 uimm24:$imm)) + K_ORI { + encoding: 4'b0001 :: imm[23:0] :: rs1[4:0] :: 3'b011 :: rd[4:0] :: 7'b1011111; + assembly: {"k.ori", "{name(rd)}, {name(rs1)}, {imm}"}; + behavior: { + if ((rd % RFS) != 0) { + // X[rd % RFS] = X[rs1 % RFS] | (unsigned)imm; + X[rd] = X[rs1] | (unsigned)imm; + } + } + } + } +} diff --git a/core_descs/ExampleRV32K.ll b/core_descs/ExampleRV32K.ll new file mode 100644 index 000000000000..13eec3be4fa3 --- /dev/null +++ b/core_descs/ExampleRV32K.ll @@ -0,0 +1,86 @@ +; ModuleID = 'mod' +source_filename = "mod" + +define void @implK_LLI(i32 %imm, ptr noalias %rd) { + %1 = and i32 %imm, -1 + %2 = icmp eq i32 %imm, %1 + call void @llvm.assume(i1 %2) + br i1 true, label %3, label %4 + +3: ; preds = %0 + store i32 %imm, ptr %rd, align 4 + br label %4 + +4: ; preds = %3, %0 + ret void +} + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) +declare void @llvm.assume(i1 noundef) #0 + +define void @implK_ADDI(i32 %imm, ptr %rs1, ptr noalias %rd) { + %1 = and i32 %imm, 16777215 + %2 = icmp eq i32 %imm, %1 + call void @llvm.assume(i1 %2) + br i1 true, label %3, label %5 + +3: ; preds = %0 + %rs1.v = load i32, ptr %rs1, align 4 + %4 = add i32 %rs1.v, %imm + store i32 %4, ptr %rd, align 4 + br label %5 + +5: ; preds = %3, %0 + ret void +} + +define void @implK_ANDI(i32 %imm, ptr %rs1, ptr noalias %rd) { + %1 = and i32 %imm, 16777215 + %2 = icmp eq i32 %imm, %1 + call void @llvm.assume(i1 %2) + br i1 true, label %3, label %5 + +3: ; preds = %0 + %rs1.v = load i32, ptr %rs1, align 4 + %4 = and i32 %rs1.v, %imm + store i32 %4, ptr %rd, align 4 + br label %5 + +5: ; preds = %3, %0 + ret void +} + +define void @implK_XORI(i32 %imm, ptr %rs1, ptr noalias %rd) { + %1 = and i32 %imm, 16777215 + %2 = icmp eq i32 %imm, %1 + call void @llvm.assume(i1 %2) + br i1 true, label %3, label %5 + +3: ; preds = %0 + %rs1.v = load i32, ptr %rs1, align 4 + %4 = xor i32 %rs1.v, %imm + store i32 %4, ptr %rd, align 4 + br label %5 + +5: ; preds = %3, %0 + ret void +} + +define void @implK_ORI(i32 %imm, ptr %rs1, ptr noalias %rd) { + %1 = and i32 %imm, 16777215 + %2 = icmp eq i32 %imm, %1 + call void @llvm.assume(i1 %2) + br i1 true, label %3, label %5 + +3: ; preds = %0 + %rs1.v = load i32, ptr %rs1, align 4 + %4 = or i32 %rs1.v, %imm + store i32 %4, ptr %rd, align 4 + br label %5 + +5: ; preds = %3, %0 + ret void +} + +attributes #0 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } + diff --git a/core_descs/ExampleRV32K.td b/core_descs/ExampleRV32K.td new file mode 100644 index 000000000000..31c651a75b75 --- /dev/null +++ b/core_descs/ExampleRV32K.td @@ -0,0 +1,33 @@ +let Predicates = [HasVendorXCValu] in { + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 1, Constraints = "" in def K_LLI_ : RVInst_K_LLI<(outs GPR:$rd), (ins uimm32:$imm)>; + +def : Pat< + (i32 (i32 uimm32:$imm)), + (K_LLI_ uimm32:$imm)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 1, Constraints = "" in def K_ADDI_ : RVInst_K_ADDI<(outs GPR:$rd), (ins uimm24:$imm, GPR:$rs1)>; + +def : Pat< + (i32 (add GPR:$rs1, (i32 uimm24:$imm))), + (K_ADDI_ uimm24:$imm, GPR:$rs1)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 1, Constraints = "" in def K_ANDI_ : RVInst_K_ANDI<(outs GPR:$rd), (ins uimm24:$imm, GPR:$rs1)>; + +def : Pat< + (i32 (and GPR:$rs1, (i32 uimm24:$imm))), + (K_ANDI_ uimm24:$imm, GPR:$rs1)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 1, Constraints = "" in def K_XORI_ : RVInst_K_XORI<(outs GPR:$rd), (ins uimm24:$imm, GPR:$rs1)>; + +def : Pat< + (i32 (xor GPR:$rs1, (i32 uimm24:$imm))), + (K_XORI_ uimm24:$imm, GPR:$rs1)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 1, Constraints = "" in def K_ORI_ : RVInst_K_ORI<(outs GPR:$rd), (ins uimm24:$imm, GPR:$rs1)>; + +def : Pat< + (i32 (or GPR:$rs1, (i32 uimm24:$imm))), + (K_ORI_ uimm24:$imm, GPR:$rs1)>; + +} From 1659decbb8273eedc50c313eb87843a3e34bac83 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Fri, 14 Mar 2025 14:42:27 +0100 Subject: [PATCH 4/6] [pattern-gen] Support const fields in encoding with total length of >32bit --- llvm/tools/pattern-gen/lib/InstrInfo.hpp | 4 ++-- llvm/tools/pattern-gen/lib/Parser.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/tools/pattern-gen/lib/InstrInfo.hpp b/llvm/tools/pattern-gen/lib/InstrInfo.hpp index 0ac896941437..0b080f7d543a 100644 --- a/llvm/tools/pattern-gen/lib/InstrInfo.hpp +++ b/llvm/tools/pattern-gen/lib/InstrInfo.hpp @@ -15,7 +15,7 @@ struct CDSLInstr uint8_t len; uint8_t dstOffset; uint8_t srcOffset; - uint32_t val; + uint64_t val; }; enum FieldType @@ -34,7 +34,7 @@ struct CDSLInstr struct Field { uint8_t len; - uint32_t constV; + uint64_t constV; std::string_view ident; uint32_t identIdx; FieldType type; diff --git a/llvm/tools/pattern-gen/lib/Parser.cpp b/llvm/tools/pattern-gen/lib/Parser.cpp index ce1ce027b78a..124cad05c4d6 100644 --- a/llvm/tools/pattern-gen/lib/Parser.cpp +++ b/llvm/tools/pattern-gen/lib/Parser.cpp @@ -1329,8 +1329,6 @@ void ParseEncoding(TokenStream &ts, CDSLInstr &instr) { syntax_error(ts); } if (pop_cur_if(ts, Semicolon)) { - uint size = 48 - offset; - instr.size = size; if (offset != 0) { if (offset != 16) { error("instruction length is not 32 or 48 bits", ts); @@ -1348,12 +1346,14 @@ void ParseEncoding(TokenStream &ts, CDSLInstr &instr) { } pop_cur(ts, BitwiseConcat); } + uint size = 48 - offset; + instr.size = size; // Rather than splitting up the constant bits of the instruction into multiple - // fields, we use one trailing constant field of size 32. FieldFragments can + // fields, we use one trailing constant field of size 32/48. FieldFragments can // index into relevant sections of this single field. instr.fields.push_back(CDSLInstr::Field{ - .len = 32, .constV = 0, .type = CDSLInstr::FieldType::CONST}); + .len = size, .constV = 0, .type = CDSLInstr::FieldType::CONST}); if (instr.fields.size() > 255) error("too many instruction fields", ts); uint8_t constIdx = instr.fields.size() - 1; From c4d10f89cf5e27ce544004192a465bce413c0c7b Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Fri, 14 Mar 2025 16:48:42 +0100 Subject: [PATCH 5/6] fix compiler warning --- llvm/tools/pattern-gen/lib/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/tools/pattern-gen/lib/Parser.cpp b/llvm/tools/pattern-gen/lib/Parser.cpp index 124cad05c4d6..8268b50217b9 100644 --- a/llvm/tools/pattern-gen/lib/Parser.cpp +++ b/llvm/tools/pattern-gen/lib/Parser.cpp @@ -1346,7 +1346,7 @@ void ParseEncoding(TokenStream &ts, CDSLInstr &instr) { } pop_cur(ts, BitwiseConcat); } - uint size = 48 - offset; + uint8_t size = 48 - offset; instr.size = size; // Rather than splitting up the constant bits of the instruction into multiple From 2111b7b3fc76132d2ea4ad63e4e0f2ad92bdc6f3 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Fri, 21 Mar 2025 01:15:27 +0100 Subject: [PATCH 6/6] [pattern-gen] Parser/InstrInfo: support 16 bit encoding --- llvm/tools/pattern-gen/lib/InstrInfo.cpp | 2 +- llvm/tools/pattern-gen/lib/Parser.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/tools/pattern-gen/lib/InstrInfo.cpp b/llvm/tools/pattern-gen/lib/InstrInfo.cpp index b153ca0a08bd..0be806004c12 100644 --- a/llvm/tools/pattern-gen/lib/InstrInfo.cpp +++ b/llvm/tools/pattern-gen/lib/InstrInfo.cpp @@ -7,7 +7,7 @@ std::string EncodingToTablgen(CDSLInstr const& instr) std::stringstream s; uint8_t size = instr.size; - std::string base = (size == 48 ? "RVInst48" : "RVInst"); + std::string base = (size == 48 ? "RVInst48" : (size == 16 ? "RVInst16" : "RVInst")); s << "class RVInst_" << instr.name << "" << " : " << base << " {\n"; diff --git a/llvm/tools/pattern-gen/lib/Parser.cpp b/llvm/tools/pattern-gen/lib/Parser.cpp index 8268b50217b9..7a9dfb621eb7 100644 --- a/llvm/tools/pattern-gen/lib/Parser.cpp +++ b/llvm/tools/pattern-gen/lib/Parser.cpp @@ -1330,10 +1330,10 @@ void ParseEncoding(TokenStream &ts, CDSLInstr &instr) { } if (pop_cur_if(ts, Semicolon)) { if (offset != 0) { - if (offset != 16) { - error("instruction length is not 32 or 48 bits", ts); + if (offset != 16 && offset != 32) { + error("instruction length is not 16/32/48 bits", ts); } - // Shift the field offsets by 16 bits + // Shift the field offsets by 16/32 bits for (auto &frag : instr.frags) if (frag.idx == 255) { frag.srcOffset = frag.srcOffset - offset;