llvm.org GIT mirror llvm / 839cd7f
[RISCV] Tablegen-driven Instruction Compression. Summary: This patch implements a tablegen-driven Instruction Compression mechanism for generating RISCV compressed instructions (C Extension) from the expanded instruction form. This tablegen backend processes CompressPat declarations in a td file and generates all the compile-time and runtime checks required to validate the declarations, validate the input operands and generate correct instructions. The checks include validating register operands, immediate operands, fixed register operands and fixed immediate operands. Example: class CompressPat<dag input, dag output> { dag Input = input; dag Output = output; list<Predicate> Predicates = []; } let Predicates = [HasStdExtC] in { def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2), (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>; } The result is an auto-generated header file 'RISCVGenCompressEmitter.inc' which exports two functions for compressing/uncompressing MCInst instructions, plus some helper functions: bool compressInst(MCInst& OutInst, const MCInst &MI, const MCSubtargetInfo &STI, MCContext &Context); bool uncompressInst(MCInst& OutInst, const MCInst &MI, const MCRegisterInfo &MRI, const MCSubtargetInfo &STI); The clients that include this auto-generated header file and invoke these functions can compress an instruction before emitting it, in the target-specific ASM or ELF streamer, or can uncompress an instruction before printing it, when the expanded instruction format aliases is favored. The following clients were added to implement compression\uncompression for RISCV: 1) RISCVAsmParser::MatchAndEmitInstruction: Inserted a call to compressInst() to compresses instructions parsed by llvm-mc coming from an ASM input. 2) RISCVAsmPrinter::EmitInstruction: Inserted a call to compressInst() to compress instructions that were lowered from Machine Instructions (MachineInstr). 3) RVInstPrinter::printInst: Inserted a call to uncompressInst() to print the expanded version of the instruction instead of the compressed one (e.g, add s0, s0, a5 instead of c.add s0, a5) when -riscv-no-aliases is not passed. This patch squashes D45119, D42780 and D41932. It was reviewed in smaller patches by asb, efriedma, apazos and mgrang. Reviewers: asb, efriedma, apazos, llvm-commits, sabuasal Reviewed By: sabuasal Subscribers: mgorny, eraman, asb, rbar, johnrusso, simoncook, jordy.potman.lists, apazos, niosHD, kito-cheng, shiva0217, zzheng Differential Revision: https://reviews.llvm.org/D45385 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@329455 91177308-0d34-0410-b5e6-96231b3b80d8 Sameer AbuAsal 1 year, 6 months ago
29 changed file(s) with 1672 addition(s) and 44 deletion(s). Raw diff Collapse all Expand all
149149
150150 void print(raw_ostream &OS) const;
151151 void dump() const;
152 bool isBareSymbolRef() const;
153 bool evaluateAsConstantImm(int64_t &Imm) const;
152154 };
153155
154156 template <> struct isPodLike { static const bool value = true; };
99 #include "llvm/MC/MCInst.h"
1010 #include "llvm/MC/MCExpr.h"
1111 #include "llvm/MC/MCInstPrinter.h"
12 #include "llvm/Support/Casting.h"
1213 #include "llvm/Support/Compiler.h"
1314 #include "llvm/Support/Debug.h"
1415 #include "llvm/Support/raw_ostream.h"
3233 } else
3334 OS << "UNDEFINED";
3435 OS << ">";
36 }
37
38 bool MCOperand::evaluateAsConstantImm(int64_t &Imm) const {
39 if (isImm()) {
40 Imm = getImm();
41 return true;
42 }
43 return false;
44 }
45
46 bool MCOperand::isBareSymbolRef() const {
47 assert(isExpr() &&
48 "isBareSymbolRef expects only expressions");
49 const MCExpr *Expr = getExpr();
50 MCExpr::ExprKind Kind = getExpr()->getKind();
51 return Kind == MCExpr::SymbolRef &&
52 cast(Expr)->getKind() == MCSymbolRefExpr::VK_None;
3553 }
3654
3755 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2424 #include "llvm/Support/TargetRegistry.h"
2525
2626 using namespace llvm;
27
28 // Include the auto-generated portion of the compress emitter.
29 #define GEN_COMPRESS_INSTR
30 #include "RISCVGenCompressInstEmitter.inc"
2731
2832 namespace {
2933 struct RISCVOperand;
594598 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
595599 default:
596600 break;
597 case Match_Success:
601 case Match_Success: {
602 MCInst CInst;
603 bool Res = compressInst(CInst, Inst, getSTI(), Out.getContext());
604 CInst.setLoc(IDLoc);
598605 Inst.setLoc(IDLoc);
599 Out.EmitInstruction(Inst, getSTI());
606 Out.EmitInstruction((Res ? CInst : Inst), getSTI());
600607 return false;
608 }
601609 case Match_MissingFeature:
602610 return Error(IDLoc, "instruction use requires an option to be enabled");
603611 case Match_MnemonicFail:
11
22 tablegen(LLVM RISCVGenAsmMatcher.inc -gen-asm-matcher)
33 tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer)
4 tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter)
45 tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel)
56 tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler)
67 tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info)
1212
1313 #include "RISCVInstPrinter.h"
1414 #include "MCTargetDesc/RISCVBaseInfo.h"
15 #include "MCTargetDesc/RISCVMCExpr.h"
1516 #include "llvm/MC/MCAsmInfo.h"
1617 #include "llvm/MC/MCExpr.h"
1718 #include "llvm/MC/MCInst.h"
2930 #define PRINT_ALIAS_INSTR
3031 #include "RISCVGenAsmWriter.inc"
3132
33 // Include the auto-generated portion of the compress emitter.
34 #define GEN_UNCOMPRESS_INSTR
35 #include "RISCVGenCompressInstEmitter.inc"
36
3237 static cl::opt
3338 NoAliases("riscv-no-aliases",
3439 cl::desc("Disable the emission of assembler pseudo instructions"),
3742
3843 void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
3944 StringRef Annot, const MCSubtargetInfo &STI) {
40 if (NoAliases || !printAliasInstr(MI, STI, O))
41 printInstruction(MI, STI, O);
45 bool Res = false;
46 const MCInst *NewMI = MI;
47 MCInst UncompressedMI;
48 if (!NoAliases)
49 Res = uncompressInst(UncompressedMI, *MI, MRI, STI);
50 if (Res)
51 NewMI = const_cast(&UncompressedMI);
52 if (NoAliases || !printAliasInstr(NewMI, STI, O))
53 printInstruction(NewMI, STI, O);
4254 printAnnotation(O, Annot);
4355 }
4456
1111 //
1212 //===----------------------------------------------------------------------===//
1313
14 #include "RISCV.h"
1415 #include "RISCVMCExpr.h"
1516 #include "llvm/MC/MCAssembler.h"
1617 #include "llvm/MC/MCContext.h"
1919 namespace llvm {
2020
2121 class StringRef;
22 class MCOperand;
2223 class RISCVMCExpr : public MCTargetExpr {
2324 public:
2425 enum VariantKind {
1313
1414 #include "RISCV.h"
1515 #include "InstPrinter/RISCVInstPrinter.h"
16 #include "MCTargetDesc/RISCVMCExpr.h"
1617 #include "RISCVTargetMachine.h"
1718 #include "llvm/CodeGen/AsmPrinter.h"
1819 #include "llvm/CodeGen/MachineConstantPool.h"
4748 unsigned AsmVariant, const char *ExtraCode,
4849 raw_ostream &OS) override;
4950
51 void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
5052 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
5153 const MachineInstr *MI);
5254
5557 return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
5658 }
5759 };
60 }
61
62 #define GEN_COMPRESS_INSTR
63 #include "RISCVGenCompressInstEmitter.inc"
64 void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
65 MCInst CInst;
66 bool Res = compressInst(CInst, Inst, *TM.getMCSubtargetInfo(),
67 OutStreamer->getContext());
68 AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
5869 }
5970
6071 // Simple pseudo-instructions have their lowering (with expansion to real
8282 let ParserMatchClass = UImmLog2XLenAsmOperand;
8383 // TODO: should ensure invalid shamt is rejected when decoding.
8484 let DecoderMethod = "decodeUImmOperand<6>";
85 let MCOperandPredicate = [{
86 int64_t Imm;
87 if (!MCOp.evaluateAsConstantImm(Imm))
88 return false;
89 if (STI.getTargetTriple().isArch64Bit())
90 return isUInt<6>(Imm);
91 return isUInt<5>(Imm);
92 }];
8593 }
8694
8795 def uimm5 : Operand, ImmLeaf(Imm);}]> {
93101 let ParserMatchClass = SImmAsmOperand<12>;
94102 let EncoderMethod = "getImmOpValue";
95103 let DecoderMethod = "decodeSImmOperand<12>";
104 let MCOperandPredicate = [{
105 int64_t Imm;
106 if (MCOp.evaluateAsConstantImm(Imm))
107 return isInt<12>(Imm);
108 return MCOp.isBareSymbolRef();
109 }];
96110 }
97111
98112 def uimm12 : Operand {
105119 let ParserMatchClass = SImmAsmOperand<13, "Lsb0">;
106120 let EncoderMethod = "getImmOpValueAsr1";
107121 let DecoderMethod = "decodeSImmOperandAndLsl1<13>";
122 let MCOperandPredicate = [{
123 int64_t Imm;
124 if (MCOp.evaluateAsConstantImm(Imm))
125 return isShiftedInt<12, 1>(Imm);
126 return MCOp.isBareSymbolRef();
127 }];
108128 }
109129
110130 def uimm20 : Operand {
111131 let ParserMatchClass = UImmAsmOperand<20>;
112132 let EncoderMethod = "getImmOpValue";
113133 let DecoderMethod = "decodeUImmOperand<20>";
134 let MCOperandPredicate = [{
135 int64_t Imm;
136 if (MCOp.evaluateAsConstantImm(Imm))
137 return isUInt<20>(Imm);
138 return MCOp.isBareSymbolRef();
139 }];
114140 }
115141
116142 // A 21-bit signed immediate where the least significant bit is zero.
118144 let ParserMatchClass = SImmAsmOperand<21, "Lsb0">;
119145 let EncoderMethod = "getImmOpValueAsr1";
120146 let DecoderMethod = "decodeSImmOperandAndLsl1<21>";
147 let MCOperandPredicate = [{
148 int64_t Imm;
149 if (MCOp.evaluateAsConstantImm(Imm))
150 return isShiftedInt<20, 1>(Imm);
151 return MCOp.isBareSymbolRef();
152 }];
121153 }
122154
123155 // A parameterized register class alternative to i32imm/i64imm from Target.td.
2626 let ParserMatchClass = UImmLog2XLenNonZeroAsmOperand;
2727 // TODO: should ensure invalid shamt is rejected when decoding.
2828 let DecoderMethod = "decodeUImmOperand<6>";
29 let MCOperandPredicate = [{
30 int64_t Imm;
31 if (!MCOp.evaluateAsConstantImm(Imm))
32 return false;
33 if (STI.getTargetTriple().isArch64Bit())
34 return isUInt<6>(Imm) && (Imm != 0);
35 return isUInt<5>(Imm) && (Imm != 0);
36 }];
2937 }
3038
3139 def simm6 : Operand, ImmLeaf(Imm);}]> {
3240 let ParserMatchClass = SImmAsmOperand<6>;
3341 let EncoderMethod = "getImmOpValue";
3442 let DecoderMethod = "decodeSImmOperand<6>";
43 let MCOperandPredicate = [{
44 int64_t Imm;
45 if (MCOp.evaluateAsConstantImm(Imm))
46 return isInt<6>(Imm);
47 return MCOp.isBareSymbolRef();
48 }];
3549 }
3650
3751 def simm6nonzero : Operand,
3953 let ParserMatchClass = SImmAsmOperand<6, "NonZero">;
4054 let EncoderMethod = "getImmOpValue";
4155 let DecoderMethod = "decodeSImmOperand<6>";
56 let MCOperandPredicate = [{
57 int64_t Imm;
58 if (MCOp.evaluateAsConstantImm(Imm))
59 return (Imm != 0) && isInt<6>(Imm);
60 return MCOp.isBareSymbolRef();
61 }];
4262 }
4363
4464 def CLUIImmAsmOperand : AsmOperandClass {
6080 let ParserMatchClass = CLUIImmAsmOperand;
6181 let EncoderMethod = "getImmOpValue";
6282 let DecoderMethod = "decodeCLUIImmOperand";
83 let MCOperandPredicate = [{
84 int64_t Imm;
85 if (MCOp.evaluateAsConstantImm(Imm))
86 return (Imm != 0) && (isUInt<5>(Imm) ||
87 (Imm >= 0xfffe0 && Imm <= 0xfffff));
88 return MCOp.isBareSymbolRef();
89 }];
6390 }
6491
6592 // A 7-bit unsigned immediate where the least significant two bits are zero.
6895 let ParserMatchClass = UImmAsmOperand<7, "Lsb00">;
6996 let EncoderMethod = "getImmOpValue";
7097 let DecoderMethod = "decodeUImmOperand<7>";
98 let MCOperandPredicate = [{
99 int64_t Imm;
100 if (!MCOp.evaluateAsConstantImm(Imm))
101 return false;
102 return isShiftedUInt<5, 2>(Imm);
103 }];
71104 }
72105
73106 // A 8-bit unsigned immediate where the least significant two bits are zero.
76109 let ParserMatchClass = UImmAsmOperand<8, "Lsb00">;
77110 let EncoderMethod = "getImmOpValue";
78111 let DecoderMethod = "decodeUImmOperand<8>";
112 let MCOperandPredicate = [{
113 int64_t Imm;
114 if (!MCOp.evaluateAsConstantImm(Imm))
115 return false;
116 return isShiftedUInt<6, 2>(Imm);
117 }];
79118 }
80119
81120 // A 8-bit unsigned immediate where the least significant three bits are zero.
84123 let ParserMatchClass = UImmAsmOperand<8, "Lsb000">;
85124 let EncoderMethod = "getImmOpValue";
86125 let DecoderMethod = "decodeUImmOperand<8>";
126 let MCOperandPredicate = [{
127 int64_t Imm;
128 if (!MCOp.evaluateAsConstantImm(Imm))
129 return false;
130 return isShiftedUInt<5, 3>(Imm);
131 }];
87132 }
88133
89134 // A 9-bit signed immediate where the least significant bit is zero.
91136 let ParserMatchClass = SImmAsmOperand<9, "Lsb0">;
92137 let EncoderMethod = "getImmOpValueAsr1";
93138 let DecoderMethod = "decodeSImmOperandAndLsl1<9>";
139 let MCOperandPredicate = [{
140 int64_t Imm;
141 if (MCOp.evaluateAsConstantImm(Imm))
142 return isShiftedInt<8, 1>(Imm);
143 return MCOp.isBareSymbolRef();
144
145 }];
94146 }
95147
96148 // A 9-bit unsigned immediate where the least significant three bits are zero.
99151 let ParserMatchClass = UImmAsmOperand<9, "Lsb000">;
100152 let EncoderMethod = "getImmOpValue";
101153 let DecoderMethod = "decodeUImmOperand<9>";
154 let MCOperandPredicate = [{
155 int64_t Imm;
156 if (!MCOp.evaluateAsConstantImm(Imm))
157 return false;
158 return isShiftedUInt<6, 3>(Imm);
159 }];
102160 }
103161
104162 // A 10-bit unsigned immediate where the least significant two bits are zero
109167 let ParserMatchClass = UImmAsmOperand<10, "Lsb00NonZero">;
110168 let EncoderMethod = "getImmOpValue";
111169 let DecoderMethod = "decodeUImmOperand<10>";
170 let MCOperandPredicate = [{
171 int64_t Imm;
172 if (!MCOp.evaluateAsConstantImm(Imm))
173 return false;
174 return isShiftedUInt<8, 2>(Imm) && (Imm != 0);
175 }];
112176 }
113177
114178 // A 10-bit signed immediate where the least significant four bits are zero.
118182 let ParserMatchClass = SImmAsmOperand<10, "Lsb0000NonZero">;
119183 let EncoderMethod = "getImmOpValue";
120184 let DecoderMethod = "decodeSImmOperand<10>";
185 let MCOperandPredicate = [{
186 int64_t Imm;
187 if (!MCOp.evaluateAsConstantImm(Imm))
188 return false;
189 return isShiftedInt<6, 4>(Imm);
190 }];
121191 }
122192
123193 // A 12-bit signed immediate where the least significant bit is zero.
124 def simm12_lsb0 : Operand<OtherVT> {
194 def simm12_lsb0 : Operand<XLenVT> {
125195 let ParserMatchClass = SImmAsmOperand<12, "Lsb0">;
126196 let EncoderMethod = "getImmOpValueAsr1";
127197 let DecoderMethod = "decodeSImmOperandAndLsl1<12>";
198 let MCOperandPredicate = [{
199 int64_t Imm;
200 if (MCOp.evaluateAsConstantImm(Imm))
201 return isShiftedInt<11, 1>(Imm);
202 return MCOp.isBareSymbolRef();
203 }];
128204 }
129205
130206 //===----------------------------------------------------------------------===//
441517 }
442518
443519 } // Predicates = [HasStdExtC]
520
521 //===----------------------------------------------------------------------===//
522 // Compress Instruction tablegen backend.
523 //===----------------------------------------------------------------------===//
524
525 class CompressPat {
526 dag Input = input;
527 dag Output = output;
528 list Predicates = [];
529 }
530
531 // Patterns are defined in the same order the compressed instructions appear
532 // on page 82 of the ISA manual.
533
534 // Quadrant 0
535 let Predicates = [HasStdExtC] in {
536 def : CompressPat<(ADDI GPRC:$rd, SP:$rs1, uimm10_lsb00nonzero:$imm),
537 (C_ADDI4SPN GPRC:$rd, SP:$rs1, uimm10_lsb00nonzero:$imm)>;
538 } // Predicates = [HasStdExtC]
539
540 let Predicates = [HasStdExtC, HasStdExtD] in {
541 def : CompressPat<(FLD FPR64C:$rd, GPRC:$rs1, uimm8_lsb000:$imm),
542 (C_FLD FPR64C:$rd, GPRC:$rs1, uimm8_lsb000:$imm)>;
543 } // Predicates = [HasStdExtC, HasStdExtD]
544
545 let Predicates = [HasStdExtC] in {
546 def : CompressPat<(LW GPRC:$rd, GPRC:$rs1, uimm7_lsb00:$imm),
547 (C_LW GPRC:$rd, GPRC:$rs1, uimm7_lsb00:$imm)>;
548 } // Predicates = [HasStdExtC]
549
550 let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
551 def : CompressPat<(FLW FPR32C:$rd, GPRC:$rs1, uimm7_lsb00:$imm),
552 (C_FLW FPR32C:$rd, GPRC:$rs1, uimm7_lsb00:$imm)>;
553 } // Predicates = [HasStdExtC, HasStdExtF, IsRV32]
554
555 let Predicates = [HasStdExtC, IsRV64] in {
556 def : CompressPat<(LD GPRC:$rd, GPRC:$rs1, uimm8_lsb000:$imm),
557 (C_LD GPRC:$rd, GPRC:$rs1, uimm8_lsb000:$imm)>;
558 } // Predicates = [HasStdExtC, IsRV64]
559
560 let Predicates = [HasStdExtC, HasStdExtD] in {
561 def : CompressPat<(FSD FPR64C:$rs2, GPRC:$rs1, uimm8_lsb000:$imm),
562 (C_FSD FPR64C:$rs2, GPRC:$rs1, uimm8_lsb000:$imm)>;
563 } // Predicates = [HasStdExtC, HasStdExtD]
564
565 let Predicates = [HasStdExtC] in {
566 def : CompressPat<(SW GPRC:$rs2, GPRC:$rs1, uimm7_lsb00:$imm),
567 (C_SW GPRC:$rs2, GPRC:$rs1, uimm7_lsb00:$imm)>;
568 } // Predicates = [HasStdExtC]
569
570 let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
571 def : CompressPat<(FSW FPR32C:$rs2, GPRC:$rs1,uimm7_lsb00:$imm),
572 (C_FSW FPR32C:$rs2, GPRC:$rs1, uimm7_lsb00:$imm)>;
573 } // Predicate = [HasStdExtC, HasStdExtF, IsRV32]
574
575 let Predicates = [HasStdExtC, IsRV64] in {
576 def : CompressPat<(SD GPRC:$rs2, GPRC:$rs1, uimm8_lsb000:$imm),
577 (C_SD GPRC:$rs2, GPRC:$rs1, uimm8_lsb000:$imm)>;
578 } // Predicates = [HasStdExtC, IsRV64]
579
580 // Quadrant 1
581 let Predicates = [HasStdExtC] in {
582 def : CompressPat<(ADDI X0, X0, 0), (C_NOP)>;
583 def : CompressPat<(ADDI GPRNoX0:$rs1, GPRNoX0:$rs1, simm6nonzero:$imm),
584 (C_ADDI GPRNoX0:$rs1, simm6nonzero:$imm)>;
585 } // Predicates = [HasStdExtC]
586
587 let Predicates = [HasStdExtC, IsRV32] in {
588 def : CompressPat<(JAL X1, simm12_lsb0:$offset),
589 (C_JAL simm12_lsb0:$offset)>;
590 } // Predicates = [HasStdExtC, IsRV32]
591
592 let Predicates = [HasStdExtC, IsRV64] in {
593 def : CompressPat<(ADDIW GPRNoX0:$rs1, GPRNoX0:$rs1, simm6:$imm),
594 (C_ADDIW GPRNoX0:$rs1, simm6:$imm)>;
595 } // Predicates = [HasStdExtC, IsRV64]
596
597 let Predicates = [HasStdExtC] in {
598 def : CompressPat<(ADDI GPRNoX0:$rd, X0, simm6:$imm),
599 (C_LI GPRNoX0:$rd, simm6:$imm)>;
600 def : CompressPat<(ADDI X2, X2, simm10_lsb0000nonzero:$imm),
601 (C_ADDI16SP X2, simm10_lsb0000nonzero:$imm)>;
602 def : CompressPat<(LUI GPRNoX0X2:$rd, c_lui_imm:$imm),
603 (C_LUI GPRNoX0X2:$rd, c_lui_imm:$imm)>;
604 def : CompressPat<(SRLI GPRC:$rs1, GPRC:$rs1, uimmlog2xlennonzero:$imm),
605 (C_SRLI GPRC:$rs1, uimmlog2xlennonzero:$imm)>;
606 def : CompressPat<(SRAI GPRC:$rs1, GPRC:$rs1, uimmlog2xlennonzero:$imm),
607 (C_SRAI GPRC:$rs1, uimmlog2xlennonzero:$imm)>;
608 def : CompressPat<(ANDI GPRC:$rs1, GPRC:$rs1, simm6:$imm),
609 (C_ANDI GPRC:$rs1, simm6:$imm)>;
610 def : CompressPat<(SUB GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
611 (C_SUB GPRC:$rs1, GPRC:$rs2)>;
612 def : CompressPat<(XOR GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
613 (C_XOR GPRC:$rs1, GPRC:$rs2)>;
614 def : CompressPat<(XOR GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
615 (C_XOR GPRC:$rs1, GPRC:$rs2)>;
616 def : CompressPat<(OR GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
617 (C_OR GPRC:$rs1, GPRC:$rs2)>;
618 def : CompressPat<(OR GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
619 (C_OR GPRC:$rs1, GPRC:$rs2)>;
620 def : CompressPat<(AND GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
621 (C_AND GPRC:$rs1, GPRC:$rs2)>;
622 def : CompressPat<(AND GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
623 (C_AND GPRC:$rs1, GPRC:$rs2)>;
624 } // Predicates = [HasStdExtC]
625
626 let Predicates = [HasStdExtC, IsRV64] in {
627 def : CompressPat<(SUBW GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
628 (C_SUBW GPRC:$rs1, GPRC:$rs2)>;
629 def : CompressPat<(ADDW GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
630 (C_ADDW GPRC:$rs1, GPRC:$rs2)>;
631 def : CompressPat<(ADDW GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
632 (C_ADDW GPRC:$rs1, GPRC:$rs2)>;
633 } // Predicates = [HasStdExtC, IsRV64]
634
635 let Predicates = [HasStdExtC] in {
636 def : CompressPat<(JAL X0, simm12_lsb0:$offset),
637 (C_J simm12_lsb0:$offset)>;
638 def : CompressPat<(BEQ GPRC:$rs1, X0, simm9_lsb0:$imm),
639 (C_BEQZ GPRC:$rs1, simm9_lsb0:$imm)>;
640 def : CompressPat<(BNE GPRC:$rs1, X0, simm9_lsb0:$imm),
641 (C_BNEZ GPRC:$rs1, simm9_lsb0:$imm)>;
642 } // Predicates = [HasStdExtC]
643
644 // Quadrant 2
645 let Predicates = [HasStdExtC] in {
646 def : CompressPat<(SLLI GPRNoX0:$rs1, GPRNoX0:$rs1, uimmlog2xlennonzero:$imm),
647 (C_SLLI GPRNoX0:$rs1, uimmlog2xlennonzero:$imm)>;
648 } // Predicates = [HasStdExtC]
649
650 let Predicates = [HasStdExtC, HasStdExtD] in {
651 def : CompressPat<(FLD FPR64:$rd, SP:$rs1, uimm9_lsb000:$imm),
652 (C_FLDSP FPR64:$rd, SP:$rs1, uimm9_lsb000:$imm)>;
653 } // Predicates = [HasStdExtC, HasStdExtD]
654
655 let Predicates = [HasStdExtC] in {
656 def : CompressPat<(LW GPRNoX0:$rd, SP:$rs1, uimm8_lsb00:$imm),
657 (C_LWSP GPRNoX0:$rd, SP:$rs1, uimm8_lsb00:$imm)>;
658 } // Predicates = [HasStdExtC]
659
660 let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
661 def : CompressPat<(FLW FPR32:$rd, SP:$rs1, uimm8_lsb00:$imm),
662 (C_FLWSP FPR32:$rd, SP:$rs1, uimm8_lsb00:$imm)>;
663 } // Predicates = [HasStdExtC, HasStdExtF, IsRV32]
664
665 let Predicates = [HasStdExtC, IsRV64] in {
666 def : CompressPat<(LD GPRNoX0:$rd, SP:$rs1, uimm9_lsb000:$imm),
667 (C_LDSP GPRNoX0:$rd, SP:$rs1, uimm9_lsb000:$imm)>;
668 } // Predicates = [HasStdExtC, IsRV64]
669
670 let Predicates = [HasStdExtC] in {
671 def : CompressPat<(JALR X0, GPRNoX0:$rs1, 0),
672 (C_JR GPRNoX0:$rs1)>;
673 def : CompressPat<(ADD GPRNoX0:$rs1, X0, GPRNoX0:$rs2),
674 (C_MV GPRNoX0:$rs1, GPRNoX0:$rs2)>;
675 def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs2, X0),
676 (C_MV GPRNoX0:$rs1, GPRNoX0:$rs2)>;
677 def : CompressPat<(EBREAK), (C_EBREAK)>;
678 def : CompressPat<(JALR X1, GPRNoX0:$rs1, 0),
679 (C_JALR GPRNoX0:$rs1)>;
680 def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2),
681 (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>;
682 def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs2, GPRNoX0:$rs1),
683 (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>;
684 } // Predicates = [HasStdExtC]
685
686 let Predicates = [HasStdExtC, HasStdExtD] in {
687 def : CompressPat<(FSD FPR64:$rs2, SP:$rs1, uimm9_lsb000:$imm),
688 (C_FSDSP FPR64:$rs2, SP:$rs1, uimm9_lsb000:$imm)>;
689 } // Predicates = [HasStdExtC, HasStdExtD]
690
691 let Predicates = [HasStdExtC] in {
692 def : CompressPat<(SW GPR:$rs2, SP:$rs1, uimm8_lsb00:$imm),
693 (C_SWSP GPR:$rs2, SP:$rs1, uimm8_lsb00:$imm)>;
694 } // Predicates = [HasStdExtC]
695
696 let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
697 def : CompressPat<(FSW FPR32:$rs2, SP:$rs1, uimm8_lsb00:$imm),
698 (C_FSWSP FPR32:$rs2, SP:$rs1, uimm8_lsb00:$imm)>;
699 } // Predicates = [HasStdExtC, HasStdExtF, IsRV32]
700
701 let Predicates = [HasStdExtC, IsRV64] in {
702 def : CompressPat<(SD GPR:$rs2, SP:$rs1, uimm9_lsb000:$imm),
703 (C_SDSP GPR:$rs2, SP:$rs1, uimm9_lsb000:$imm)>;
704 } // Predicates = [HasStdExtC, IsRV64]
11 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
22 ; RUN: | FileCheck %s -check-prefix=RV32I
33
4 ; RUN: llc -mtriple=riscv32 -mattr=+c -filetype=obj < %s \
5 ; RUN: |llvm-objdump -d -triple=riscv32 -mattr=+c -riscv-no-aliases - \
6 ; RUN: | FileCheck -check-prefix=RV32IC %s
7
48 ; These tests are each targeted at a particular RISC-V ALU instruction. Other
59 ; files in this folder exercise LLVM IR instructions that don't directly match a
610 ; RISC-V instruction
1216 ; RV32I: # %bb.0:
1317 ; RV32I-NEXT: addi a0, a0, 1
1418 ; RV32I-NEXT: ret
19
20 ; RV32IC-LABEL: addi:
21 ; RV32IC-NEXT: c.addi a0, 1
22 ; RV32IC-NEXT: c.jr ra
1523 %1 = add i32 %a, 1
1624 ret i32 %1
1725 }
5967 ; RV32I: # %bb.0:
6068 ; RV32I-NEXT: andi a0, a0, 6
6169 ; RV32I-NEXT: ret
70
71
72 ; RV32IC-LABEL: andi:
73 ; RV32IC: c.andi a0, 6
74 ; RV32IC: c.jr ra
6275 %1 = and i32 %a, 6
6376 ret i32 %1
6477 }
6881 ; RV32I: # %bb.0:
6982 ; RV32I-NEXT: slli a0, a0, 7
7083 ; RV32I-NEXT: ret
84
85 ; RV32IC-LABEL: slli:
86 ; RV32IC-NEXT: slli a0, 7
87 ; RV32IC-NEXT: c.jr ra
7188 %1 = shl i32 %a, 7
7289 ret i32 %1
7390 }
7794 ; RV32I: # %bb.0:
7895 ; RV32I-NEXT: srli a0, a0, 8
7996 ; RV32I-NEXT: ret
97
98 ; RV32IC-LABEL: srli:
99 ; RV32IC-NEXT: c.srli a0, 8
100 ; RV32IC-NEXT: c.jr ra
80101 %1 = lshr i32 %a, 8
81102 ret i32 %1
82103 }
86107 ; RV32I: # %bb.0:
87108 ; RV32I-NEXT: srai a0, a0, 9
88109 ; RV32I-NEXT: ret
110
111 ; RV32IC-LABEL: srai:
112 ; RV32IC-NEXT: c.srai a0, 9
113 ; RV32IC-NEXT: c.jr ra
89114 %1 = ashr i32 %a, 9
90115 ret i32 %1
91116 }
97122 ; RV32I: # %bb.0:
98123 ; RV32I-NEXT: add a0, a0, a1
99124 ; RV32I-NEXT: ret
125
126 ; RV32IC-LABEL: add:
127 ; RV32IC-NEXT: c.add a0, a1
128 ; RV32IC-NEXT: c.jr ra
129
100130 %1 = add i32 %a, %b
101131 ret i32 %1
102132 }
106136 ; RV32I: # %bb.0:
107137 ; RV32I-NEXT: sub a0, a0, a1
108138 ; RV32I-NEXT: ret
139
140 ; RV32IC-LABEL: sub:
141 ; RV32IC-NEXT: c.sub a0, a1
142 ; RV32IC-NEXT: c.jr ra
109143 %1 = sub i32 %a, %b
110144 ret i32 %1
111145 }
144178 ; RV32I: # %bb.0:
145179 ; RV32I-NEXT: xor a0, a0, a1
146180 ; RV32I-NEXT: ret
181
182 ; RV32IC-LABEL: xor:
183 ; RV32IC-NEXT: c.xor a0, a1
184 ; RV32IC-NEXT: c.jr ra
147185 %1 = xor i32 %a, %b
148186 ret i32 %1
149187 }
180218 ; RV32I: # %bb.0:
181219 ; RV32I-NEXT: and a0, a0, a1
182220 ; RV32I-NEXT: ret
221
222 ; RV32IC-LABEL: and:
223 ; RV32IC-NEXT: c.and a0, a1
224 ; RV32IC-NEXT: c.jr ra
183225 %1 = and i32 %a, %b
184226 ret i32 %1
185227 }
0 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
11 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
22 ; RUN: | FileCheck -check-prefix=RV32I %s
3
4
5 ; RUN: llc -mtriple=riscv32 -mattr=+c -filetype=obj < %s \
6 ; RUN: |llvm-objdump -d -triple=riscv32 -mattr=+c -riscv-no-aliases - \
7 ; RUN: | FileCheck -check-prefix=RV32IC %s
38
49 define void @foo(i32 %a, i32 *%b, i1 %c) {
510 ; RV32I-LABEL: foo:
4146 ; RV32I-NEXT: lw a0, 0(a1)
4247 ; RV32I-NEXT: .LBB0_12: # %end
4348 ; RV32I-NEXT: ret
49
50 ; RV32IC-LABEL: foo:
51 ; RV32IC: c.lw a3, 0(a1)
52 ; RV32IC-NEXT: beq a3, a0, 68
53 ; RV32IC-NEXT: c.lw a3, 0(a1)
54 ; RV32IC-NEXT: bne a3, a0, 62
55 ; RV32IC-NEXT: c.lw a3, 0(a1)
56 ; RV32IC-NEXT: blt a3, a0, 56
57 ; RV32IC-NEXT: c.lw a3, 0(a1)
58 ; RV32IC-NEXT: bge a3, a0, 50
59 ; RV32IC-NEXT: c.lw a3, 0(a1)
60 ; RV32IC-NEXT: bltu a3, a0, 44
61 ; RV32IC-NEXT: c.lw a3, 0(a1)
62 ; RV32IC-NEXT: bgeu a3, a0, 38
63 ; RV32IC-NEXT: c.lw a3, 0(a1)
64 ; RV32IC-NEXT: blt a0, a3, 32
65 ; RV32IC-NEXT: c.lw a3, 0(a1)
66 ; RV32IC-NEXT: bge a0, a3, 26
67 ; RV32IC-NEXT: c.lw a3, 0(a1)
68 ; RV32IC-NEXT: bltu a0, a3, 20
69 ; RV32IC-NEXT: c.lw a3, 0(a1)
70 ; RV32IC-NEXT: bgeu a0, a3, 14
71 ; RV32IC-NEXT: c.lw a0, 0(a1)
72 ; RV32IC-NEXT: andi a0, a2, 1
73 ; RV32IC-NEXT: c.bnez a0, 4
74 ; RV32IC-NEXT: c.lw a0, 0(a1)
75 ; RV32IC-NEXT: c.jr ra
4476
4577 %val1 = load volatile i32, i32* %b
4678 %tst1 = icmp eq i32 %val1, %a
0 ; RUN: llc -mtriple=riscv32 -mattr=+c -riscv-no-aliases -o %t1 < %s
1 ; RUN: FileCheck %s < %t1
2
3 define void @foo() {
4 ; CHECK-LABEL: foo:
5 ; CHECK: c.jr
6
7 end:
8 ret void
9 }
0 ; RUN: llc -mtriple=riscv32 -mattr=+c -filetype=obj < %s\
1 ; RUN: | llvm-objdump -triple=riscv32 -mattr=+c -d -riscv-no-aliases -\
2 ; RUN: | FileCheck -check-prefix=CHECK %s
3
4 @ext = external global i32
5
6 define i32 @compress_test(i32 %a) {
7 ; CHECK-LABEL: compress_test:
8 ; CHECK: c.add a0, a1
9 ; CHECK-NEXT: c.jr ra
10 %1 = load i32, i32* @ext
11 %2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 %a, i32 %1)
12 ret i32 %2
13 }
14
0 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
1 # RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s
1 # RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=CHECK-INST %s
22
33 # alpha and main are 8 byte alignment
44 # but the alpha function's size is 6
0 # RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding < %s \
1 # RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
2 # RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding \
3 # RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
4 # RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj < %s \
5 # RUN: | llvm-objdump -triple riscv32 -mattr=+c -d - \
6 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
7 # RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj < %s \
8 # RUN: | llvm-objdump -triple riscv32 -mattr=+c -d -riscv-no-aliases - \
9 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
10
11 # c.jal is an rv32 only instruction.
12 jal ra, 2046
13 # CHECK-BYTES: fd 2f
14 # CHECK-ALIAS: jal 2046
15 # CHECK-INST: c.jal 2046
16 # CHECK: # encoding: [0xfd,0x2f]
0 # RUN: llvm-mc -triple riscv32 -mattr=+c,+d -show-encoding < %s \
1 # RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
2 # RUN: llvm-mc -triple riscv32 -mattr=+c,+d -show-encoding \
3 # RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
4 # RUN: llvm-mc -triple riscv32 -mattr=+c,+d -filetype=obj < %s \
5 # RUN: | llvm-objdump -triple riscv32 -mattr=+c,+d -d - \
6 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
7 # RUN: llvm-mc -triple riscv32 -mattr=+c,+d -filetype=obj < %s \
8 # RUN: | llvm-objdump -triple riscv32 -mattr=+c,+d -d -riscv-no-aliases - \
9 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
10
11 # RUN: llvm-mc -triple riscv64 -mattr=+c,+d -show-encoding < %s \
12 # RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s
13 # RUN: llvm-mc -triple riscv64 -mattr=+c,+d -show-encoding \
14 # RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %s
15 # RUN: llvm-mc -triple riscv64 -mattr=+c,+d -filetype=obj < %s \
16 # RUN: | llvm-objdump -triple riscv64 -mattr=+c,+d -d - \
17 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
18 # RUN: llvm-mc -triple riscv64 -mattr=+c,+d -filetype=obj < %s \
19 # RUN: | llvm-objdump -triple riscv64 -mattr=+c,+d -d -riscv-no-aliases - \
20 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
21
22 # Tests double precision floating point instructions available in rv32 and in rv64.
23
24 fld ft0, 64(sp)
25 # CHECK-BYTES: 06 20
26 # CHECK-ALIAS: fld ft0, 64(sp)
27 # CHECK-INST: c.fldsp ft0, 64(sp)
28 # CHECK: # encoding: [0x06,0x20]
29 fsd ft0, 64(sp)
30 # CHECK-BYTES: 82 a0
31 # CHECK-ALIAS: fsd ft0, 64(sp)
32 # CHECK-INST: c.fsdsp ft0, 64(sp)
33 # CHECK: # encoding: [0x82,0xa0]
34 fld fs0, 248(s0)
35 # CHECK-BYTES: 60 3c
36 # CHECK-ALIAS: fld fs0, 248(s0)
37 # CHECK-INST: c.fld fs0, 248(s0)
38 # CHECK: # encoding: [0x60,0x3c]
39 fsd fs0, 248(s0)
40 # CHECK-BYTES: 60 bc
41 # CHECK-ALIAS: fsd fs0, 248(s0)
42 # CHECK-INST: c.fsd fs0, 248(s0)
43 # CHECK: # encoding: [0x60,0xbc]
0 # RUN: llvm-mc -triple riscv32 -mattr=+c,+f -show-encoding < %s \
1 # RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
2 # RUN: llvm-mc -triple riscv32 -mattr=+c,+f -show-encoding \
3 # RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
4 # RUN: llvm-mc -triple riscv32 -mattr=+c,+f -filetype=obj < %s \
5 # RUN: | llvm-objdump -triple riscv32 -mattr=+c,+f -d - \
6 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
7 # RUN: llvm-mc -triple riscv32 -mattr=+c,+f -filetype=obj < %s \
8 # RUN: | llvm-objdump -triple riscv32 -mattr=+c,+f -d -riscv-no-aliases - \
9 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
10
11 # Instructions that are 32 bit only.
12 flw ft0, 124(sp)
13 # CHECK-BYTES: 76 70
14 # CHECK-ALIAS: flw ft0, 124(sp)
15 # CHECK-INST: c.flwsp ft0, 124(sp)
16 # CHECK: # encoding: [0x76,0x70]
17 fsw ft0, 124(sp)
18 # CHECK-BYTES: 82 fe
19 # CHECK-ALIAS: fsw ft0, 124(sp)
20 # CHECK-INST: c.fswsp ft0, 124(sp)
21 # CHECK: # encoding: [0x82,0xfe]
22 flw fs0, 124(s0)
23 # CHECK-BYTES: 60 7c
24 # CHECK-ALIAS: flw fs0, 124(s0)
25 # CHECK-INST: c.flw fs0, 124(s0)
26 # CHECK: # encoding: [0x60,0x7c]
27 fsw fs0, 124(s0)
28 # CHECK-BYTES: 60 fc
29 # CHECK-ALIAS: fsw fs0, 124(s0)
30 # CHECK-INST: c.fsw fs0, 124(s0)
31 # CHECK: # encoding: [0x60,0xfc]
0 # RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding < %s \
1 # RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
2 # RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding \
3 # RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
4 # RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj < %s \
5 # RUN: | llvm-objdump -triple riscv32 -mattr=+c -d - \
6 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
7 # RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj < %s \
8 # RUN: | llvm-objdump -triple riscv32 -mattr=+c -d -riscv-no-aliases - \
9 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
10
11 # RUN: llvm-mc -triple riscv64 -mattr=+c -show-encoding < %s \
12 # RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s
13 # RUN: llvm-mc -triple riscv64 -mattr=+c -show-encoding \
14 # RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %s
15 # RUN: llvm-mc -triple riscv64 -mattr=+c -filetype=obj < %s \
16 # RUN: | llvm-objdump -triple riscv64 -mattr=+c -d - \
17 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
18 # RUN: llvm-mc -triple riscv64 -mattr=+c -filetype=obj < %s \
19 # RUN: | llvm-objdump -triple riscv64 -mattr=+c -d -riscv-no-aliases - \
20 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
21
22 # CHECK-BYTES: e0 1f
23 # CHECK-ALIAS: addi s0, sp, 1020
24 # CHECK-INST: c.addi4spn s0, sp, 1020
25 # CHECK: # encoding: [0xe0,0x1f]
26 addi s0, sp, 1020
27
28 # CHECK-BYTES: e0 5f
29 # CHECK-ALIAS: lw s0, 124(a5)
30 # CHECK-INST: c.lw s0, 124(a5)
31 # CHECK: # encoding: [0xe0,0x5f]
32 lw s0, 124(a5)
33
34 # CHECK-BYTES: e0 df
35 # CHECK-ALIAS: sw s0, 124(a5)
36 # CHECK-INST: c.sw s0, 124(a5)
37 # CHECK: # encoding: [0xe0,0xdf]
38 sw s0, 124(a5)
39
40 # CHECK-BYTES: 01 00
41 # CHECK-ALIAS: nop
42 # CHECK-INST: c.nop
43 # CHECK: # encoding: [0x01,0x00]
44 nop
45
46 # CHECK-BYTES: 81 10
47 # CHECK-ALIAS: addi ra, ra, -32
48 # CHECK-INST: c.addi ra, -32
49 # CHECK: # encoding: [0x81,0x10]
50 addi ra, ra, -32
51
52 # CHECK-BYTES: 85 50
53 # CHECK-ALIAS: addi ra, zero, -31
54 # CHECK-INST: c.li ra, -31
55 # CHECK: # encoding: [0x85,0x50]
56 addi ra, zero, -31
57
58 # CHECK-BYTES: 39 71
59 # CHECK-ALIAS: addi sp, sp, -64
60 # CHECK-INST: c.addi16sp sp, -64
61 # CHECK: # encoding: [0x39,0x71]
62 addi sp, sp, -64
63
64 # CHECK-BYTES: fd 61
65 # CHECK-ALIAS: lui gp, 31
66 # CHECK-INST: c.lui gp, 31
67 # CHECK: # encoding: [0xfd,0x61]
68 lui gp, 31
69
70 # CHECK-BYTES: 7d 80
71 # CHECK-ALIAS: srli s0, s0, 31
72 # CHECK-INST: c.srli s0, 31
73 # CHECK: # encoding: [0x7d,0x80]
74 srli s0, s0, 31
75
76 # CHECK-BYTES: 7d 84
77 # CHECK-ALIAS: srai s0, s0, 31
78 # CHECK-INST: c.srai s0, 31
79 # CHECK: # encoding: [0x7d,0x84]
80 srai s0, s0, 31
81
82 # CHECK-BYTES: 7d 88
83 # CHECK-ALIAS: andi s0, s0, 31
84 # CHECK-INST: c.andi s0, 31
85 # CHECK: # encoding: [0x7d,0x88]
86 andi s0, s0, 31
87
88 # CHECK-BYTES: 1d 8c
89 # CHECK-ALIAS: sub s0, s0, a5
90 # CHECK-INST: c.sub s0, a5
91 # CHECK: # encoding: [0x1d,0x8c]
92 sub s0, s0, a5
93
94 # CHECK-BYTES: 3d 8c
95 # CHECK-ALIAS: xor s0, s0, a5
96 # CHECK-INST: c.xor s0, a5
97 # CHECK: # encoding: [0x3d,0x8c]
98 xor s0, s0, a5
99
100 # CHECK-BYTES: 3d 8c
101 # CHECK-ALIAS: xor s0, s0, a5
102 # CHECK-INST: c.xor s0, a5
103 # CHECK: # encoding: [0x3d,0x8c]
104 xor s0, a5, s0
105
106 # CHECK-BYTES: 5d 8c
107 # CHECK-ALIAS: or s0, s0, a5
108 # CHECK-INST: c.or s0, a5
109 # CHECK: # encoding: [0x5d,0x8c]
110 or s0, s0, a5
111
112 # CHECK-BYTES: 45 8c
113 # CHECK-ALIAS: or s0, s0, s1
114 # CHECK-INST: c.or s0, s1
115 # CHECK: # encoding: [0x45,0x8c]
116 or s0, s1, s0
117
118 # CHECK-BYTES: 7d 8c
119 # CHECK-ALIAS: and s0, s0, a5
120 # CHECK-INST: c.and s0, a5
121 # CHECK: # encoding: [0x7d,0x8c]
122 and s0, s0, a5
123
124 # CHECK-BYTES: 7d 8c
125 # CHECK-ALIAS: and s0, s0, a5
126 # CHECK-INST: c.and s0, a5
127 # CHECK: # encoding: [0x7d,0x8c]
128 and s0, a5, s0
129
130 # CHECK-BYTES: 01 b0
131 # CHECK-ALIAS: j -2048
132 # CHECK-INST: c.j -2048
133 # CHECK: # encoding: [0x01,0xb0]
134 jal zero, -2048
135
136 # CHECK-BYTES: 01 d0
137 # CHECK-ALIAS: beqz s0, -256
138 # CHECK-INST: c.beqz s0, -256
139 # CHECK: # encoding: [0x01,0xd0]
140 beq s0, zero, -256
141
142 # CHECK-BYTES: 7d ec
143 # CHECk-ALIAS: bnez s0, 254
144 # CHECK-INST: c.bnez s0, 254
145 # CHECK: # encoding: [0x7d,0xec]
146 bne s0, zero, 254
147
148 # CHECK-BYTES: 7e 04
149 # CHECK-ALIAS: slli s0, s0, 31
150 # CHECK-INST: c.slli s0, 31
151 # CHECK: # encoding: [0x7e,0x04]
152 slli s0, s0, 31
153
154 # CHECK-BYTES: fe 50
155 # CHECK-ALIAS: lw ra, 252(sp)
156 # CHECK-INST: c.lwsp ra, 252(sp)
157 # CHECK: # encoding: [0xfe,0x50]
158 lw ra, 252(sp)
159
160 # CHECK-BYTES: 82 80
161 # CHECK-ALIAS: ret
162 # CHECK-INST: c.jr ra
163 # CHECK: # encoding: [0x82,0x80]
164 jalr zero, ra, 0
165
166 # CHECK-BYTES: 92 80
167 # CHECK-ALIAS: add ra, zero, tp
168 # CHECK-INST: c.mv ra, tp
169 # CHECK: # encoding: [0x92,0x80]
170 add ra, zero, tp
171
172 # CHECK-BYTES: 92 80
173 # CHECK-ALIAS: add ra, zero, tp
174 # CHECK-INST: c.mv ra, tp
175 # CHECK: # encoding: [0x92,0x80]
176 add ra, tp, zero
177
178 # CHECK-BYTES: 02 90
179 # CHECK-ALIAS: ebreak
180 # CHECK-INST: c.ebreak
181 # CHECK: # encoding: [0x02,0x90]
182 ebreak
183
184 # CHECK-BYTES: 02 94
185 # CHECK-ALIAS: jalr s0
186 # CHECK-INST: c.jalr s0
187 # CHECK: # encoding: [0x02,0x94]
188 jalr ra, s0, 0
189
190 # CHECK-BYTES: 3e 94
191 # CHECK-ALIAS: add s0, s0, a5
192 # CHECK-INST: c.add s0, a5
193 # CHECK: # encoding: [0x3e,0x94]
194 add s0, a5, s0
195
196 # CHECK-BYTES: 3e 94
197 # CHECK-ALIAS: add s0, s0, a5
198 # CHECK-INST: c.add s0, a5
199 # CHECK: # encoding: [0x3e,0x94]
200 add s0, s0, a5
201
202 # CHECK-BYTES: 82 df
203 # CHECK-ALIAS: sw zero, 252(sp)
204 # CHECK-INST: c.swsp zero, 252(sp)
205 # CHECK: # encoding: [0x82,0xdf]
206 sw zero, 252(sp)
0 # RUN: llvm-mc -triple riscv64 -mattr=+c -show-encoding < %s \
1 # RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s
2 # RUN: llvm-mc -triple riscv64 -mattr=+c -show-encoding \
3 # RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %s
4 # RUN: llvm-mc -triple riscv64 -mattr=+c -filetype=obj < %s \
5 # RUN: | llvm-objdump -triple riscv64 -mattr=+c -d - \
6 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
7 # RUN: llvm-mc -triple riscv64 -mattr=+c -filetype=obj < %s \
8 # RUN: | llvm-objdump -triple riscv64 -mattr=+c -d -riscv-no-aliases - \
9 # RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
10
11 # Tests compressed instructions available in rv64 and not in rv32.
12
13 # CHECK-BYTES: e0 7f
14 # CHECK-ALIAS: ld s0, 248(a5)
15 # CHECK-INST: c.ld s0, 248(a5)
16 # CHECK: # encoding: [0xe0,0x7f]
17 ld s0, 248(a5)
18
19 # CHECK-BYTES: a0 e3
20 # CHECK-ALIAS: sd s0, 64(a5)
21 # CHECK-INST: c.sd s0, 64(a5)
22 # CHECK: # encoding: [0xa0,0xe3]
23 sd s0, 64(a5)
24
25 # CHECK-BYTES: 7d 22
26 # CHEACK-ALIAS: addiw tp, tp, 31
27 # CHECK-INST: c.addiw tp, 31
28 # CHECK: # encoding: [0x7d,0x22]
29 addiw tp, tp, 31
30
31 # CHECK-BYTES: 1d 9c
32 # CHEACK-ALIAS: subw s0, s0, a5
33 # CHECK-INST: c.subw s0, a5
34 # CHECK: # encoding: [0x1d,0x9c]
35 subw s0, s0, a5
36
37 # CHECK-BYTES: 3d 9c
38 # CHECK-ALIAS: addw s0, s0, a5
39 # CHECK-INST: c.addw s0, a5
40 # CHECK: # encoding: [0x3d,0x9c]
41 addw s0, s0, a5
42
43 # CHECK-BYTES: 3d 9c
44 # CHECK-ALIAS: addw s0, s0, a5
45 # CHECK-INST: c.addw s0, a5
46 # CHECK: # encoding: [0x3d,0x9c]
47 addw s0, a5, s0
48
49 # CHECK-BYTES: ee 70
50 # CHECK-ALIAS: ld ra, 248(sp)
51 # CHECK-INST: c.ldsp ra, 248(sp)
52 # CHECK: # encoding: [0xee,0x70]
53 ld ra, 248(sp)
54
55 # CHECK-BYTES: a2 e0
56 # CHECK-ALIAS: sd s0, 64(sp)
57 # CHECK-INST: c.sdsp s0, 64(sp)
58 # CHECK: # encoding: [0xa2,0xe0]
59 sd s0, 64(sp)
0 # RUN: llvm-mc -triple riscv32 -mattr=+c -riscv-no-aliases < %s -show-encoding \
1 # RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
2 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
3 # RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s
4
5 # Check prefixes:
6 # RELOC - Check the relocation in the object.
7 # FIXUP - Check the fixup on the instruction.
8 # INSTR - Check the instruction is handled properly by the ASMPrinter
9 c.jal foo
10 # A compressed jump (c.j) to an unresolved symbol will be relaxed to a (jal).
11 # RELOC: R_RISCV_JAL
12 # INSTR: c.jal foo
13 # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_jump
14
15 c.bnez a0, foo
16 # A compressed branch (c.bnez) to an unresolved symbol will be relaxed to a (bnez).
17 # RELOC: R_RISCV_BRANCH
18 # INSTR: c.bnez a0, foo
19 # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_branch
0 # RUN: llvm-mc %s -triple riscv32 -mattr=+c -show-encoding \
11 # RUN: | FileCheck -check-prefix=CHECK-FIXUP %s
22 # RUN: llvm-mc -triple riscv32 -filetype=obj -mattr=+c < %s \
3 # RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s
3 # RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=CHECK-INSTR %s
44 # RUN: llvm-mc -filetype=obj -mattr=+c -triple=riscv32 %s \
55 # RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL
66
None # RUN: llvm-mc -triple riscv32 -mattr=+c -riscv-no-aliases < %s -show-encoding \
0 # RUN: llvm-mc -triple riscv32 -riscv-no-aliases < %s -show-encoding \
11 # RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
22 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
33 # RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s
8282 # RELOC: R_RISCV_BRANCH
8383 # INSTR: bgeu a0, a1, foo
8484 # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch
85
86 c.jal foo
87 # A compressed jump (c.j) to an unresolved symbol will be relaxed to a (jal).
88 # RELOC: R_RISCV_JAL
89 # INSTR: c.jal foo
90 # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_jump
91
92 c.bnez a0, foo
93 # A compressed branch (c.bnez) to an unresolved symbol will be relaxed to a (bnez).
94 # RELOC: R_RISCV_BRANCH
95 # INSTR: c.bnez a0, foo
96 # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_branch
0 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
1 # RUN: | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s
1 # RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=INSTR %s
22
33 FAR_JUMP_NEGATIVE:
44 c.nop
1717 c.bnez a0, NEAR_NEGATIVE
1818 #INSTR: c.bnez a0, -4
1919 c.bnez a0, FAR_BRANCH
20 #INSTR-NEXT: bnez a0, 326
20 #INSTR-NEXT: bne a0, zero, 326
2121 c.bnez a0, FAR_BRANCH_NEGATIVE
22 #INSTR-NEXT: bnez a0, -268
22 #INSTR-NEXT: bne a0, zero, -268
2323 c.bnez a0, FAR_JUMP
24 #INSTR-NEXT: bnez a0, 2320
24 #INSTR-NEXT: bne a0, zero, 2320
2525 c.bnez a0, FAR_JUMP_NEGATIVE
26 #INSTR-NEXT: bnez a0, -2278
26 #INSTR-NEXT: bne a0, zero, -2278
2727
2828 c.beqz a0, NEAR
2929 #INSTR-NEXT: c.beqz a0, 52
3030 c.beqz a0, NEAR_NEGATIVE
3131 #INSTR-NEXT: c.beqz a0, -24
3232 c.beqz a0, FAR_BRANCH
33 #INSTR-NEXT: beqz a0, 306
33 #INSTR-NEXT: beq a0, zero, 306
3434 c.beqz a0, FAR_BRANCH_NEGATIVE
35 #INSTR-NEXT: beqz a0, -288
35 #INSTR-NEXT: beq a0, zero, -288
3636 c.beqz a0, FAR_JUMP
37 #INSTR-NEXT: beqz a0, 2300
37 #INSTR-NEXT: beq a0, zero, 2300
3838 c.beqz a0, FAR_JUMP_NEGATIVE
39 #INSTR-NEXT: beqz a0, -2298
39 #INSTR-NEXT: beq a0, zero, -2298
4040
4141 c.j NEAR
4242 #INSTR-NEXT: c.j 32
4747 c.j FAR_BRANCH_NEGATIVE
4848 #INSTR-NEXT: c.j -306
4949 c.j FAR_JUMP
50 #INSTR-NEXT: j 2284
50 #INSTR-NEXT: jal zero, 2284
5151 c.j FAR_JUMP_NEGATIVE
52 #INSTR-NEXT: j -2314
52 #INSTR-NEXT: jal zero, -2314
5353
5454 c.jal NEAR
5555 #INSTR: c.jal 16
6060 c.jal FAR_BRANCH_NEGATIVE
6161 #INSTR-NEXT: c.jal -322
6262 c.jal FAR_JUMP
63 #INSTR-NEXT: jal 2268
63 #INSTR-NEXT: jal ra, 2268
6464 c.jal FAR_JUMP_NEGATIVE
65 #INSTR-NEXT: jal -2330
65 #INSTR-NEXT: jal ra, -2330
6666
6767 NEAR:
6868 c.nop
0 # RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c < %s \
1 # RUN: | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s
1 # RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=INSTR %s
22
33 FAR_JUMP_NEGATIVE:
44 c.nop
1717 c.bnez a0, NEAR_NEGATIVE
1818 #INSTR: c.bnez a0, -4
1919 c.bnez a0, FAR_BRANCH
20 #INSTR-NEXT: bnez a0, 310
20 #INSTR-NEXT: bne a0, zero, 310
2121 c.bnez a0, FAR_BRANCH_NEGATIVE
22 #INSTR-NEXT: bnez a0, -268
22 #INSTR-NEXT: bne a0, zero, -268
2323 c.bnez a0, FAR_JUMP
24 #INSTR-NEXT: bnez a0, 2304
24 #INSTR-NEXT: bne a0, zero, 2304
2525 c.bnez a0, FAR_JUMP_NEGATIVE
26 #INSTR-NEXT: bnez a0, -2278
26 #INSTR-NEXT: bne a0, zero, -2278
2727
2828 c.beqz a0, NEAR
2929 #INSTR-NEXT: c.beqz a0, 36
3030 c.beqz a0, NEAR_NEGATIVE
3131 #INSTR-NEXT: c.beqz a0, -24
3232 c.beqz a0, FAR_BRANCH
33 #INSTR-NEXT: beqz a0, 290
33 #INSTR-NEXT: beq a0, zero, 290
3434 c.beqz a0, FAR_BRANCH_NEGATIVE
35 #INSTR-NEXT: beqz a0, -288
35 #INSTR-NEXT: beq a0, zero, -288
3636 c.beqz a0, FAR_JUMP
37 #INSTR-NEXT: beqz a0, 2284
37 #INSTR-NEXT: beq a0, zero, 2284
3838 c.beqz a0, FAR_JUMP_NEGATIVE
39 #INSTR-NEXT: beqz a0, -2298
39 #INSTR-NEXT: beq a0, zero, -2298
4040
4141 c.j NEAR
4242 #INSTR-NEXT: c.j 16
4747 c.j FAR_BRANCH_NEGATIVE
4848 #INSTR-NEXT: c.j -306
4949 c.j FAR_JUMP
50 #INSTR-NEXT: j 2268
50 #INSTR-NEXT: jal zero, 2268
5151 c.j FAR_JUMP_NEGATIVE
52 #INSTR-NEXT: j -2314
52 #INSTR-NEXT: jal zero, -2314
5353
5454 NEAR:
5555 c.nop
2929 IntrinsicEmitter.cpp
3030 OptParserEmitter.cpp
3131 PseudoLoweringEmitter.cpp
32 RISCVCompressInstEmitter.cpp
3233 RegisterBankEmitter.cpp
3334 RegisterInfoEmitter.cpp
3435 SDNodeProperties.cpp
0 //===- RISCVCompressInstEmitter.cpp - Generator for RISCV Compression -===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 // RISCVCompressInstEmitter implements a tablegen-driven CompressPat based
8 // RISCV Instruction Compression mechanism.
9 //
10 //===--------------------------------------------------------------===//
11 //
12 // RISCVCompressInstEmitter implements a tablegen-driven CompressPat Instruction
13 // Compression mechanism for generating RISCV compressed instructions
14 // (C ISA Extension) from the expanded instruction form.
15
16 // This tablegen backend processes CompressPat declarations in a
17 // td file and generates all the required checks to validate the pattern
18 // declarations; validate the input and output operands to generate the correct
19 // compressed instructions. The checks include validating different types of
20 // operands; register operands, immediate operands, fixed register and fixed
21 // immediate inputs.
22 //
23 // Example:
24 // class CompressPat {
25 // dag Input = input;
26 // dag Output = output;
27 // list Predicates = [];
28 // }
29 //
30 // let Predicates = [HasStdExtC] in {
31 // def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2),
32 // (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>;
33 // }
34 //
35 // The result is an auto-generated header file
36 // 'RISCVGenCompressInstEmitter.inc' which exports two functions for
37 // compressing/uncompressing MCInst instructions, plus
38 // some helper functions:
39 //
40 // bool compressInst(MCInst& OutInst, const MCInst &MI,
41 // const MCSubtargetInfo &STI,
42 // MCContext &Context);
43 //
44 // bool uncompressInst(MCInst& OutInst, const MCInst &MI,
45 // const MCRegisterInfo &MRI,
46 // const MCSubtargetInfo &STI);
47 //
48 // The clients that include this auto-generated header file and
49 // invoke these functions can compress an instruction before emitting
50 // it in the target-specific ASM or ELF streamer or can uncompress
51 // an instruction before printing it when the expanded instruction
52 // format aliases is favored.
53
54 //===----------------------------------------------------------------------===//
55
56 #include "CodeGenInstruction.h"
57 #include "CodeGenTarget.h"
58 #include "llvm/ADT/IndexedMap.h"
59 #include "llvm/ADT/SmallVector.h"
60 #include "llvm/ADT/StringExtras.h"
61 #include "llvm/ADT/StringMap.h"
62 #include "llvm/Support/Debug.h"
63 #include "llvm/Support/ErrorHandling.h"
64 #include "llvm/TableGen/Error.h"
65 #include "llvm/TableGen/Record.h"
66 #include "llvm/TableGen/TableGenBackend.h"
67 #include
68 using namespace llvm;
69
70 #define DEBUG_TYPE "compress-inst-emitter"
71
72 namespace {
73 class RISCVCompressInstEmitter {
74 struct OpData {
75 enum MapKind { Operand, Imm, Reg };
76 MapKind Kind;
77 union {
78 unsigned Operand; // Operand number mapped to.
79 uint64_t Imm; // Integer immediate value.
80 Record *Reg; // Physical register.
81 } Data;
82 int TiedOpIdx = -1; // Tied operand index within the instruction.
83 };
84 struct CompressPat {
85 CodeGenInstruction Source; // The source instruction definition.
86 CodeGenInstruction Dest; // The destination instruction to transform to.
87 std::vector
88 PatReqFeatures; // Required target features to enable pattern.
89 IndexedMap
90 SourceOperandMap; // Maps operands in the Source Instruction to
91 // the corresponding Dest instruction operand.
92 IndexedMap
93 DestOperandMap; // Maps operands in the Dest Instruction
94 // to the corresponding Source instruction operand.
95 CompressPat(CodeGenInstruction &S, CodeGenInstruction &D,
96 std::vector RF, IndexedMap &SourceMap,
97 IndexedMap &DestMap)
98 : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap),
99 DestOperandMap(DestMap) {}
100 };
101
102 RecordKeeper &Records;
103 CodeGenTarget Target;
104 SmallVector CompressPatterns;
105
106 void addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Inst,
107 IndexedMap &OperandMap, bool IsSourceInst);
108 void evaluateCompressPat(Record *Compress);
109 void emitCompressInstEmitter(raw_ostream &o, bool Compress);
110 bool validateTypes(Record *SubType, Record *Type, bool IsSourceInst);
111 bool validateRegister(Record *Reg, Record *RegClass);
112 void createDagOperandMapping(Record *Rec, StringMap &SourceOperands,
113 StringMap &DestOperands,
114 DagInit *SourceDag, DagInit *DestDag,
115 IndexedMap &SourceOperandMap);
116
117 void createInstOperandMapping(Record *Rec, DagInit *SourceDag,
118 DagInit *DestDag,
119 IndexedMap &SourceOperandMap,
120 IndexedMap &DestOperandMap,
121 StringMap &SourceOperands,
122 CodeGenInstruction &DestInst);
123
124 public:
125 RISCVCompressInstEmitter(RecordKeeper &R) : Records(R), Target(R) {}
126
127 void run(raw_ostream &o);
128 };
129 } // End anonymous namespace.
130
131 bool RISCVCompressInstEmitter::validateRegister(Record *Reg, Record *RegClass) {
132 assert(Reg->isSubClassOf("Register") && "Reg record should be a Register\n");
133 assert(RegClass->isSubClassOf("RegisterClass") && "RegClass record should be"
134 " a RegisterClass\n");
135 CodeGenRegisterClass RC = Target.getRegisterClass(RegClass);
136 const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower());
137 assert((R != nullptr) &&
138 ("Register" + Reg->getName().str() + " not defined!!\n").c_str());
139 return RC.contains(R);
140 }
141
142 bool RISCVCompressInstEmitter::validateTypes(Record *DagOpType,
143 Record *InstOpType,
144 bool IsSourceInst) {
145 if (DagOpType == InstOpType)
146 return true;
147 // Only source instruction operands are allowed to not match Input Dag
148 // operands.
149 if (!IsSourceInst)
150 return false;
151
152 if (DagOpType->isSubClassOf("RegisterClass") &&
153 InstOpType->isSubClassOf("RegisterClass")) {
154 CodeGenRegisterClass RC = Target.getRegisterClass(InstOpType);
155 CodeGenRegisterClass SubRC = Target.getRegisterClass(DagOpType);
156 return RC.hasSubClass(&SubRC);
157 }
158
159 // At this point either or both types are not registers, reject the pattern.
160 if (DagOpType->isSubClassOf("RegisterClass") ||
161 InstOpType->isSubClassOf("RegisterClass"))
162 return false;
163
164 // Let further validation happen when compress()/uncompress() functions are
165 // invoked.
166 DEBUG(dbgs() << (IsSourceInst ? "Input" : "Output") << " Dag Operand Type: '"
167 << DagOpType->getName() << "' and "
168 << "Instruction Operand Type: '" << InstOpType->getName()
169 << "' can't be checked at pattern validation time!\n");
170 return true;
171 }
172
173 /// The patterns in the Dag contain different types of operands:
174 /// Register operands, e.g.: GPRC:$rs1; Fixed registers, e.g: X1; Immediate
175 /// operands, e.g.: simm6:$imm; Fixed immediate operands, e.g.: 0. This function
176 /// maps Dag operands to its corresponding instruction operands. For register
177 /// operands and fixed registers it expects the Dag operand type to be contained
178 /// in the instantiated instruction operand type. For immediate operands and
179 /// immediates no validation checks are enforced at pattern validation time.
180 void RISCVCompressInstEmitter::addDagOperandMapping(
181 Record *Rec, DagInit *Dag, CodeGenInstruction &Inst,
182 IndexedMap &OperandMap, bool IsSourceInst) {
183 // TiedCount keeps track of the number of operands skipped in Inst
184 // operands list to get to the corresponding Dag operand. This is
185 // necessary because the number of operands in Inst might be greater
186 // than number of operands in the Dag due to how tied operands
187 // are represented.
188 unsigned TiedCount = 0;
189 for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) {
190 int TiedOpIdx = Inst.Operands[i].getTiedRegister();
191 if (-1 != TiedOpIdx) {
192 // Set the entry in OperandMap for the tied operand we're skipping.
193 OperandMap[i].Kind = OperandMap[TiedOpIdx].Kind;
194 OperandMap[i].Data = OperandMap[TiedOpIdx].Data;
195 TiedCount++;
196 continue;
197 }
198 if (DefInit *DI = dyn_cast(Dag->getArg(i - TiedCount))) {
199 if (DI->getDef()->isSubClassOf("Register")) {
200 // Check if the fixed register belongs to the Register class.
201 if (!validateRegister(DI->getDef(), Inst.Operands[i].Rec))
202 PrintFatalError(Rec->getLoc(),
203 "Error in Dag '" + Dag->getAsString() +
204 "'Register: '" + DI->getDef()->getName() +
205 "' is not in register class '" +
206 Inst.Operands[i].Rec->getName() + "'");
207 OperandMap[i].Kind = OpData::Reg;
208 OperandMap[i].Data.Reg = DI->getDef();
209 continue;
210 }
211 // Validate that Dag operand type matches the type defined in the
212 // corresponding instruction. Operands in the input Dag pattern are
213 // allowed to be a subclass of the type specified in corresponding
214 // instruction operand instead of being an exact match.
215 if (!validateTypes(DI->getDef(), Inst.Operands[i].Rec, IsSourceInst))
216 PrintFatalError(Rec->getLoc(),
217 "Error in Dag '" + Dag->getAsString() + "'. Operand '" +
218 Dag->getArgNameStr(i - TiedCount) + "' has type '" +
219 DI->getDef()->getName() +
220 "' which does not match the type '" +
221 Inst.Operands[i].Rec->getName() +
222 "' in the corresponding instruction operand!");
223
224 OperandMap[i].Kind = OpData::Operand;
225 } else if (IntInit *II = dyn_cast(Dag->getArg(i - TiedCount))) {
226 // Validate that corresponding instruction operand expects an immediate.
227 if (Inst.Operands[i].Rec->isSubClassOf("RegisterClass"))
228 PrintFatalError(
229 Rec->getLoc(),
230 ("Error in Dag '" + Dag->getAsString() + "' Found immediate: '" +
231 II->getAsString() +
232 "' but corresponding instruction operand expected a register!"));
233 // No pattern validation check possible for values of fixed immediate.
234 OperandMap[i].Kind = OpData::Imm;
235 OperandMap[i].Data.Imm = II->getValue();
236 DEBUG(dbgs() << " Found immediate '" << II->getValue() << "' at "
237 << (IsSourceInst ? "input " : "output ")
238 << "Dag. No validation time check possible for values of "
239 "fixed immediate.\n");
240 } else
241 llvm_unreachable("Unhandled CompressPat argument type!");
242 }
243 }
244
245 // Verify the Dag operand count is enough to build an instruction.
246 static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag,
247 bool IsSource) {
248 if (Dag->getNumArgs() == Inst.Operands.size())
249 return true;
250 // Source instructions are non compressed instructions and don't have tied
251 // operands.
252 if (IsSource)
253 PrintFatalError("Input operands for Inst '" + Inst.TheDef->getName() +
254 "' and input Dag operand count mismatch");
255 // The Dag can't have more arguments than the Instruction.
256 if (Dag->getNumArgs() > Inst.Operands.size())
257 PrintFatalError("Inst '" + Inst.TheDef->getName() +
258 "' and Dag operand count mismatch");
259
260 // The Instruction might have tied operands so the Dag might have
261 // a fewer operand count.
262 unsigned RealCount = Inst.Operands.size();
263 for (unsigned i = 0; i < Inst.Operands.size(); i++)
264 if (Inst.Operands[i].getTiedRegister() != -1)
265 --RealCount;
266
267 if (Dag->getNumArgs() != RealCount)
268 PrintFatalError("Inst '" + Inst.TheDef->getName() +
269 "' and Dag operand count mismatch");
270 return true;
271 }
272
273 static bool validateArgsTypes(Init *Arg1, Init *Arg2) {
274 DefInit *Type1 = dyn_cast(Arg1);
275 DefInit *Type2 = dyn_cast(Arg2);
276 assert(Type1 && ("Arg1 type not found\n"));
277 assert(Type2 && ("Arg2 type not found\n"));
278 return Type1->getDef() == Type2->getDef();
279 }
280
281 // Creates a mapping between the operand name in the Dag (e.g. $rs1) and
282 // its index in the list of Dag operands and checks that operands with the same
283 // name have the same types. For example in 'C_ADD $rs1, $rs2' we generate the
284 // mapping $rs1 --> 0, $rs2 ---> 1. If the operand appears twice in the (tied)
285 // same Dag we use the last occurrence for indexing.
286 void RISCVCompressInstEmitter::createDagOperandMapping(
287 Record *Rec, StringMap &SourceOperands,
288 StringMap &DestOperands, DagInit *SourceDag, DagInit *DestDag,
289 IndexedMap &SourceOperandMap) {
290 for (unsigned i = 0; i < DestDag->getNumArgs(); ++i) {
291 // Skip fixed immediates and registers, they were handled in
292 // addDagOperandMapping.
293 if ("" == DestDag->getArgNameStr(i))
294 continue;
295 DestOperands[DestDag->getArgNameStr(i)] = i;
296 }
297
298 for (unsigned i = 0; i < SourceDag->getNumArgs(); ++i) {
299 // Skip fixed immediates and registers, they were handled in
300 // addDagOperandMapping.
301 if ("" == SourceDag->getArgNameStr(i))
302 continue;
303
304 StringMap::iterator it =
305 SourceOperands.find(SourceDag->getArgNameStr(i));
306 if (it != SourceOperands.end()) {
307 // Operand sharing the same name in the Dag should be mapped as tied.
308 SourceOperandMap[i].TiedOpIdx = it->getValue();
309 if (!validateArgsTypes(SourceDag->getArg(it->getValue()),
310 SourceDag->getArg(i)))
311 PrintFatalError(Rec->getLoc(),
312 "Input Operand '" + SourceDag->getArgNameStr(i) +
313 "' has a mismatched tied operand!\n");
314 }
315 it = DestOperands.find(SourceDag->getArgNameStr(i));
316 if (it == DestOperands.end())
317 PrintFatalError(Rec->getLoc(), "Operand " + SourceDag->getArgNameStr(i) +
318 " defined in Input Dag but not used in"
319 " Output Dag!\n");
320 // Input Dag operand types must match output Dag operand type.
321 if (!validateArgsTypes(DestDag->getArg(it->getValue()),
322 SourceDag->getArg(i)))
323 PrintFatalError(Rec->getLoc(), "Type mismatch between Input and "
324 "Output Dag operand '" +
325 SourceDag->getArgNameStr(i) + "'!");
326 SourceOperands[SourceDag->getArgNameStr(i)] = i;
327 }
328 }
329
330 /// Map operand names in the Dag to their index in both corresponding input and
331 /// output instructions. Validate that operands defined in the input are
332 /// used in the output pattern while populating the maps.
333 void RISCVCompressInstEmitter::createInstOperandMapping(
334 Record *Rec, DagInit *SourceDag, DagInit *DestDag,
335 IndexedMap &SourceOperandMap, IndexedMap &DestOperandMap,
336 StringMap &SourceOperands, CodeGenInstruction &DestInst) {
337 // TiedCount keeps track of the number of operands skipped in Inst
338 // operands list to get to the corresponding Dag operand.
339 unsigned TiedCount = 0;
340 DEBUG(dbgs() << " Operand mapping:\n Source Dest\n");
341 for (unsigned i = 0, e = DestInst.Operands.size(); i != e; ++i) {
342 int TiedInstOpIdx = DestInst.Operands[i].getTiedRegister();
343 if (TiedInstOpIdx != -1) {
344 ++TiedCount;
345 DestOperandMap[i].Data = DestOperandMap[TiedInstOpIdx].Data;
346 DestOperandMap[i].Kind = DestOperandMap[TiedInstOpIdx].Kind;
347 if (DestOperandMap[i].Kind == OpData::Operand)
348 // No need to fill the SourceOperandMap here since it was mapped to
349 // destination operand 'TiedInstOpIdx' in a previous iteration.
350 DEBUG(dbgs() << " " << DestOperandMap[i].Data.Operand << " ====> "
351 << i << " Dest operand tied with operand '"
352 << TiedInstOpIdx << "'\n");
353 continue;
354 }
355 // Skip fixed immediates and registers, they were handled in
356 // addDagOperandMapping.
357 if (DestOperandMap[i].Kind != OpData::Operand)
358 continue;
359
360 unsigned DagArgIdx = i - TiedCount;
361 StringMap::iterator SourceOp =
362 SourceOperands.find(DestDag->getArgNameStr(DagArgIdx));
363 if (SourceOp == SourceOperands.end())
364 PrintFatalError(Rec->getLoc(),
365 "Output Dag operand '" +
366 DestDag->getArgNameStr(DagArgIdx) +
367 "' has no matching input Dag operand.");
368
369 assert(DestDag->getArgNameStr(DagArgIdx) ==
370 SourceDag->getArgNameStr(SourceOp->getValue()) &&
371 "Incorrect operand mapping detected!\n");
372 DestOperandMap[i].Data.Operand = SourceOp->getValue();
373 SourceOperandMap[SourceOp->getValue()].Data.Operand = i;
374 DEBUG(dbgs() << " " << SourceOp->getValue() << " ====> " << i << "\n");
375 }
376 }
377
378 /// Validates the CompressPattern and create operand mapping.
379 /// These are the checks to validate a CompressPat pattern declarations.
380 /// Error out with message under these conditions:
381 /// - Dag Input opcode is an expanded instruction and Dag Output opcode is a
382 /// compressed instruction.
383 /// - Operands in Dag Input must be all used in Dag Output.
384 /// Register Operand type in Dag Input Type must be contained in the
385 /// corresponding Source Instruction type.
386 /// - Register Operand type in Dag Input must be the same as in Dag Ouput.
387 /// - Register Operand type in Dag Output must be the same as the
388 /// corresponding Destination Inst type.
389 /// - Immediate Operand type in Dag Input must be the same as in Dag Ouput.
390 /// - Immediate Operand type in Dag Ouput must be the same as the corresponding
391 /// Destination Instruction type.
392 /// - Fixed register must be contained in the corresponding Source Instruction
393 /// type.
394 /// - Fixed register must be contained in the corresponding Destination
395 /// Instruction type. Warning message printed under these conditions:
396 /// - Fixed immediate in Dag Input or Dag Ouput cannot be checked at this time
397 /// and generate warning.
398 /// - Immediate operand type in Dag Input differs from the corresponding Source
399 /// Instruction type and generate a warning.
400 void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) {
401 // Validate input Dag operands.
402 DagInit *SourceDag = Rec->getValueAsDag("Input");
403 assert(SourceDag && "Missing 'Input' in compress pattern!");
404 DEBUG(dbgs() << "Input: " << *SourceDag << "\n");
405
406 DefInit *OpDef = dyn_cast(SourceDag->getOperator());
407 if (!OpDef)
408 PrintFatalError(Rec->getLoc(),
409 Rec->getName() + " has unexpected operator type!");
410 // Checking we are transforming from compressed to uncompressed instructions.
411 Record *Operator = OpDef->getDef();
412 if (!Operator->isSubClassOf("RVInst"))
413 PrintFatalError(Rec->getLoc(), "Input instruction '" + Operator->getName() +
414 "' is not a 32 bit wide instruction!");
415 CodeGenInstruction SourceInst(Operator);
416 verifyDagOpCount(SourceInst, SourceDag, true);
417
418 // Validate output Dag operands.
419 DagInit *DestDag = Rec->getValueAsDag("Output");
420 assert(DestDag && "Missing 'Output' in compress pattern!");
421 DEBUG(dbgs() << "Output: " << *DestDag << "\n");
422
423 DefInit *DestOpDef = dyn_cast(DestDag->getOperator());
424 if (!DestOpDef)
425 PrintFatalError(Rec->getLoc(),
426 Rec->getName() + " has unexpected operator type!");
427
428 Record *DestOperator = DestOpDef->getDef();
429 if (!DestOperator->isSubClassOf("RVInst16"))
430 PrintFatalError(Rec->getLoc(), "Output instruction '" +
431 DestOperator->getName() +
432 "' is not a 16 bit wide instruction!");
433 CodeGenInstruction DestInst(DestOperator);
434 verifyDagOpCount(DestInst, DestDag, false);
435
436 // Fill the mapping from the source to destination instructions.
437
438 IndexedMap SourceOperandMap;
439 SourceOperandMap.grow(SourceInst.Operands.size());
440 // Create a mapping between source Dag operands and source Inst operands.
441 addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap,
442 /*IsSourceInst*/ true);
443
444 IndexedMap DestOperandMap;
445 DestOperandMap.grow(DestInst.Operands.size());
446 // Create a mapping between destination Dag operands and destination Inst
447 // operands.
448 addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap,
449 /*IsSourceInst*/ false);
450
451 StringMap SourceOperands;
452 StringMap DestOperands;
453 createDagOperandMapping(Rec, SourceOperands, DestOperands, SourceDag, DestDag,
454 SourceOperandMap);
455 // Create operand mapping between the source and destination instructions.
456 createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap,
457 DestOperandMap, SourceOperands, DestInst);
458
459 // Get the target features for the CompressPat.
460 std::vector PatReqFeatures;
461 std::vector RF = Rec->getValueAsListOfDefs("Predicates");
462 copy_if(RF, std::back_inserter(PatReqFeatures), [](Record *R) {
463 return R->getValueAsBit("AssemblerMatcherPredicate");
464 });
465
466 CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures,
467 SourceOperandMap, DestOperandMap));
468 }
469
470 static void getReqFeatures(std::map &FeaturesMap,
471 const std::vector &ReqFeatures) {
472 for (auto &R : ReqFeatures) {
473 StringRef AsmCondString = R->getValueAsString("AssemblerCondString");
474
475 // AsmCondString has syntax [!]F(,[!]F)*
476 SmallVector Ops;
477 SplitString(AsmCondString, Ops, ",");
478 assert(!Ops.empty() && "AssemblerCondString cannot be empty");
479
480 for (auto &Op : Ops) {
481 assert(!Op.empty() && "Empty operator");
482 if (FeaturesMap.find(Op) == FeaturesMap.end())
483 FeaturesMap[Op] = FeaturesMap.size();
484 }
485 }
486 }
487
488 unsigned getMCOpPredicate(DenseMap &MCOpPredicateMap,
489 std::vector &MCOpPredicates,
490 Record *Rec) {
491 unsigned Entry = MCOpPredicateMap[Rec];
492 if (Entry)
493 return Entry;
494
495 if (!Rec->isValueUnset("MCOperandPredicate")) {
496 MCOpPredicates.push_back(Rec);
497 Entry = MCOpPredicates.size();
498 MCOpPredicateMap[Rec] = Entry;
499 return Entry;
500 }
501
502 PrintFatalError(Rec->getLoc(),
503 "No MCOperandPredicate on this operand at all: " +
504 Rec->getName().str() + "'");
505 return 0;
506 }
507
508 static std::string mergeCondAndCode(raw_string_ostream &CondStream,
509 raw_string_ostream &CodeStream) {
510 std::string S;
511 raw_string_ostream CombinedStream(S);
512 CombinedStream.indent(4)
513 << "if ("
514 << CondStream.str().substr(
515 6, CondStream.str().length() -
516 10) // remove first indentation and last '&&'.
517 << ") {\n";
518 CombinedStream << CodeStream.str();
519 CombinedStream.indent(4) << " return true;\n";
520 CombinedStream.indent(4) << "} // if\n";
521 return CombinedStream.str();
522 }
523
524 void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
525 bool Compress) {
526 Record *AsmWriter = Target.getAsmWriter();
527 if (!AsmWriter->getValueAsInt("PassSubtarget"))
528 PrintFatalError("'PassSubtarget' is false. SubTargetInfo object is needed "
529 "for target features.\n");
530
531 std::string Namespace = Target.getName();
532
533 // Sort entries in CompressPatterns to handle instructions that can have more
534 // than one candidate for compression\uncompression, e.g ADD can be
535 // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the
536 // source and destination are flipped and the sort key needs to change
537 // accordingly.
538 std::stable_sort(CompressPatterns.begin(), CompressPatterns.end(),
539 [Compress](const CompressPat &LHS, const CompressPat &RHS) {
540 if (Compress)
541 return (LHS.Source.TheDef->getName().str() <
542 RHS.Source.TheDef->getName().str());
543 else
544 return (LHS.Dest.TheDef->getName().str() <
545 RHS.Dest.TheDef->getName().str());
546 });
547
548 // A list of MCOperandPredicates for all operands in use, and the reverse map.
549 std::vector MCOpPredicates;
550 DenseMap MCOpPredicateMap;
551
552 std::string F;
553 std::string FH;
554 raw_string_ostream Func(F);
555 raw_string_ostream FuncH(FH);
556 bool NeedMRI = false;
557
558 if (Compress)
559 o << "\n#ifdef GEN_COMPRESS_INSTR\n"
560 << "#undef GEN_COMPRESS_INSTR\n\n";
561 else
562 o << "\n#ifdef GEN_UNCOMPRESS_INSTR\n"
563 << "#undef GEN_UNCOMPRESS_INSTR\n\n";
564
565 if (Compress) {
566 FuncH << "static bool compressInst(MCInst& OutInst,\n";
567 FuncH.indent(25) << "const MCInst &MI,\n";
568 FuncH.indent(25) << "const MCSubtargetInfo &STI,\n";
569 FuncH.indent(25) << "MCContext &Context) {\n";
570 } else {
571 FuncH << "static bool uncompressInst(MCInst& OutInst,\n";
572 FuncH.indent(27) << "const MCInst &MI,\n";
573 FuncH.indent(27) << "const MCRegisterInfo &MRI,\n";
574 FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n";
575 }
576
577 if (CompressPatterns.empty()) {
578 o << FuncH.str();
579 o.indent(2) << "return false;\n}\n";
580 if (Compress)
581 o << "\n#endif //GEN_COMPRESS_INSTR\n";
582 else
583 o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n";
584 return;
585 }
586
587 std::string CaseString("");
588 raw_string_ostream CaseStream(CaseString);
589 std::string PrevOp("");
590 std::string CurOp("");
591 CaseStream << " switch (MI.getOpcode()) {\n";
592 CaseStream << " default: return false;\n";
593
594 for (auto &CompressPat : CompressPatterns) {
595 std::string CondString;
596 std::string CodeString;
597 raw_string_ostream CondStream(CondString);
598 raw_string_ostream CodeStream(CodeString);
599 CodeGenInstruction &Source =
600 Compress ? CompressPat.Source : CompressPat.Dest;
601 CodeGenInstruction &Dest = Compress ? CompressPat.Dest : CompressPat.Source;
602 IndexedMap SourceOperandMap =
603 Compress ? CompressPat.SourceOperandMap : CompressPat.DestOperandMap;
604 IndexedMap &DestOperandMap =
605 Compress ? CompressPat.DestOperandMap : CompressPat.SourceOperandMap;
606
607 CurOp = Source.TheDef->getName().str();
608 // Check current and previous opcode to decide to continue or end a case.
609 if (CurOp != PrevOp) {
610 if (PrevOp != "")
611 CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n";
612 CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n";
613 }
614
615 std::map FeaturesMap;
616 // Add CompressPat required features.
617 getReqFeatures(FeaturesMap, CompressPat.PatReqFeatures);
618
619 // Add Dest instruction required features.
620 std::vector ReqFeatures;
621 std::vector RF = Dest.TheDef->getValueAsListOfDefs("Predicates");
622 copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) {
623 return R->getValueAsBit("AssemblerMatcherPredicate");
624 });
625 getReqFeatures(FeaturesMap, ReqFeatures);
626
627 // Emit checks for all required features.
628 for (auto &F : FeaturesMap) {
629 StringRef Op = F.first;
630 if (Op[0] == '!')
631 CondStream.indent(6) << ("!STI.getFeatureBits()[" + Namespace +
632 "::" + Op.substr(1) + "]")
633 .str() +
634 " &&\n";
635 else
636 CondStream.indent(6)
637 << ("STI.getFeatureBits()[" + Namespace + "::" + Op + "]").str() +
638 " &&\n";
639 }
640
641 // Start Source Inst operands validation.
642 unsigned OpNo = 0;
643 for (OpNo = 0; OpNo < Source.Operands.size(); ++OpNo) {
644 if (SourceOperandMap[OpNo].TiedOpIdx != -1) {
645 if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass"))
646 CondStream.indent(6)
647 << "(MI.getOperand("
648 << std::to_string(OpNo) + ").getReg() == MI.getOperand("
649 << std::to_string(SourceOperandMap[OpNo].TiedOpIdx)
650 << ").getReg()) &&\n";
651 else
652 PrintFatalError("Unexpected tied operand types!\n");
653 }
654 // Check for fixed immediates\registers in the source instruction.
655 switch (SourceOperandMap[OpNo].Kind) {
656 case OpData::Operand:
657 // We don't need to do anything for source instruction operand checks.
658 break;
659 case OpData::Imm:
660 CondStream.indent(6)
661 << "(MI.getOperand(" + std::to_string(OpNo) + ").isImm()) &&\n" +
662 " (MI.getOperand(" + std::to_string(OpNo) +
663 ").getImm() == " +
664 std::to_string(SourceOperandMap[OpNo].Data.Imm) + ") &&\n";
665 break;
666 case OpData::Reg: {
667 Record *Reg = SourceOperandMap[OpNo].Data.Reg;
668 CondStream.indent(6) << "(MI.getOperand(" + std::to_string(OpNo) +
669 ").getReg() == " + Namespace +
670 "::" + Reg->getName().str() + ") &&\n";
671 break;
672 }
673 }
674 }
675 CodeStream.indent(6) << "// " + Dest.AsmString + "\n";
676 CodeStream.indent(6) << "OutInst.setOpcode(" + Namespace +
677 "::" + Dest.TheDef->getName().str() + ");\n";
678 OpNo = 0;
679 for (const auto &DestOperand : Dest.Operands) {
680 CodeStream.indent(6) << "// Operand: " + DestOperand.Name + "\n";
681 switch (DestOperandMap[OpNo].Kind) {
682 case OpData::Operand: {
683 unsigned OpIdx = DestOperandMap[OpNo].Data.Operand;
684 // Check that the operand in the Source instruction fits
685 // the type for the Dest instruction.
686 if (DestOperand.Rec->isSubClassOf("RegisterClass")) {
687 NeedMRI = true;
688 // This is a register operand. Check the register class.
689 // Don't check register class if this is a tied operand, it was done
690 // for the operand its tied to.
691 if (DestOperand.getTiedRegister() == -1)
692 CondStream.indent(6)
693 << "(MRI.getRegClass(" + Namespace +
694 "::" + DestOperand.Rec->getName().str() +
695 "RegClassID).contains(" + "MI.getOperand(" +
696 std::to_string(OpIdx) + ").getReg())) &&\n";
697
698 CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" +
699 std::to_string(OpIdx) + "));\n";
700 } else {
701 // Handling immediate operands.
702 unsigned Entry = getMCOpPredicate(MCOpPredicateMap, MCOpPredicates,
703 DestOperand.Rec);
704 CondStream.indent(6) << Namespace + "ValidateMCOperand(" +
705 "MI.getOperand(" + std::to_string(OpIdx) +
706 "), STI, " + std::to_string(Entry) +
707 ") &&\n";
708 CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" +
709 std::to_string(OpIdx) + "));\n";
710 }
711 break;
712 }
713 case OpData::Imm: {
714 unsigned Entry =
715 getMCOpPredicate(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec);
716 CondStream.indent(6)
717 << Namespace + "ValidateMCOperand(" + "MCOperand::createImm(" +
718 std::to_string(DestOperandMap[OpNo].Data.Imm) + "), STI, " +
719 std::to_string(Entry) + ") &&\n";
720 CodeStream.indent(6)
721 << "OutInst.addOperand(MCOperand::createImm(" +
722 std::to_string(DestOperandMap[OpNo].Data.Imm) + "));\n";
723 } break;
724 case OpData::Reg: {
725 // Fixed register has been validated at pattern validation time.
726 Record *Reg = DestOperandMap[OpNo].Data.Reg;
727 CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createReg(" +
728 Namespace + "::" + Reg->getName().str() +
729 "));\n";
730 } break;
731 }
732 ++OpNo;
733 }
734 CaseStream << mergeCondAndCode(CondStream, CodeStream);
735 PrevOp = CurOp;
736 }
737 Func << CaseStream.str() << "\n";
738 // Close brace for the last case.
739 Func.indent(4) << "} // case " + CurOp + "\n";
740 Func.indent(2) << "} // switch\n";
741 Func.indent(2) << "return false;\n}\n";
742
743 if (!MCOpPredicates.empty()) {
744 o << "static bool " << Namespace
745 << "ValidateMCOperand(const MCOperand &MCOp,\n"
746 << " const MCSubtargetInfo &STI,\n"
747 << " unsigned PredicateIndex) {\n"
748 << " switch (PredicateIndex) {\n"
749 << " default:\n"
750 << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"
751 << " break;\n";
752
753 for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
754 Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate");
755 if (CodeInit *SI = dyn_cast(MCOpPred))
756 o << " case " << i + 1 << ": {\n"
757 << " // " << MCOpPredicates[i]->getName().str() << SI->getValue()
758 << "\n"
759 << " }\n";
760 else
761 llvm_unreachable("Unexpected MCOperandPredicate field!");
762 }
763 o << " }\n"
764 << "}\n\n";
765 }
766
767 o << FuncH.str();
768 if (NeedMRI && Compress)
769 o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n";
770 o << Func.str();
771
772 if (Compress)
773 o << "\n#endif //GEN_COMPRESS_INSTR\n";
774 else
775 o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n";
776 }
777
778 void RISCVCompressInstEmitter::run(raw_ostream &o) {
779 Record *CompressClass = Records.getClass("CompressPat");
780 assert(CompressClass && "Compress class definition missing!");
781 std::vector Insts;
782 for (const auto &D : Records.getDefs()) {
783 if (D.second->isSubClassOf(CompressClass))
784 Insts.push_back(D.second.get());
785 }
786
787 // Process the CompressPat definitions, validating them as we do so.
788 for (unsigned i = 0, e = Insts.size(); i != e; ++i)
789 evaluateCompressPat(Insts[i]);
790
791 // Emit file header.
792 emitSourceFileHeader("Compress instruction Source Fragment", o);
793 // Generate compressInst() function.
794 emitCompressInstEmitter(o, true);
795 // Generate uncompressInst() function.
796 emitCompressInstEmitter(o, false);
797 }
798
799 namespace llvm {
800
801 void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS) {
802 RISCVCompressInstEmitter(RK).run(OS);
803 }
804
805 } // namespace llvm
3131 GenAsmMatcher,
3232 GenDisassembler,
3333 GenPseudoLowering,
34 GenCompressInst,
3435 GenCallingConv,
3536 GenDAGISel,
3637 GenDFAPacketizer,
7172 "Generate disassembler"),
7273 clEnumValN(GenPseudoLowering, "gen-pseudo-lowering",
7374 "Generate pseudo instruction lowering"),
75 clEnumValN(GenCompressInst, "gen-compress-inst-emitter",
76 "Generate RISCV compressed instructions."),
7477 clEnumValN(GenAsmMatcher, "gen-asm-matcher",
7578 "Generate assembly instruction matcher"),
7679 clEnumValN(GenDAGISel, "gen-dag-isel",
143146 case GenPseudoLowering:
144147 EmitPseudoLowering(Records, OS);
145148 break;
149 case GenCompressInst:
150 EmitCompressInst(Records, OS);
151 break;
146152 case GenDAGISel:
147153 EmitDAGISel(Records, OS);
148154 break;
7373 void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS);
7474 void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS);
7575 void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS);
76 void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS);
7677 void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS);
7778 void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS);
7879 void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);