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)>; + +} diff --git a/llvm/tools/pattern-gen/lib/InstrInfo.cpp b/llvm/tools/pattern-gen/lib/InstrInfo.cpp index 5cb5f2ac5432..0be806004c12 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" : (size == 16 ? "RVInst16" : "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..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,12 +34,13 @@ struct CDSLInstr struct Field { uint8_t len; - uint32_t constV; + uint64_t constV; std::string_view ident; uint32_t identIdx; 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 703f245b1ce9..7a9dfb621eb7 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,18 +1329,31 @@ 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 && offset != 32) { + error("instruction length is not 16/32/48 bits", ts); + } + // Shift the field offsets by 16/32 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); } + uint8_t 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;