Index: lib/Target/RISCV/CMakeLists.txt =================================================================== --- lib/Target/RISCV/CMakeLists.txt +++ lib/Target/RISCV/CMakeLists.txt @@ -9,6 +9,7 @@ tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel) tablegen(LLVM RISCVGenSubtargetInfo.inc -gen-subtarget) tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM RISCVGenCompressEmitter.inc -gen-compress-emitter) add_public_tablegen_target(RISCVCommonTableGen) Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -83,6 +83,14 @@ let ParserMatchClass = UImmLog2XLenAsmOperand; // TODO: should ensure invalid shamt is rejected when decoding. let DecoderMethod = "decodeUImmOperand<6>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + if (STI.getTargetTriple().isArch64Bit()) + return isUInt<6>(Imm); + return isUInt<5>(Imm); + }]; } def uimm5 : Operand, ImmLeaf(Imm);}]> { @@ -94,6 +102,12 @@ let ParserMatchClass = SImmAsmOperand<12>; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeSImmOperand<12>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isInt<12>(Imm); + }]; } def uimm12 : Operand { @@ -102,23 +116,44 @@ } // A 13-bit signed immediate where the least significant bit is zero. -def simm13_lsb0 : Operand { +def simm13_lsb0 : Operand { +// , ImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<13, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<13>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedInt<12, 1>(Imm); + }]; } -def uimm20 : Operand { +def uimm20 : Operand , + ImmLeaf(Imm);}]>{ let ParserMatchClass = UImmAsmOperand<20>; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeUImmOperand<20>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isUInt<20>(Imm); + }]; } // A 21-bit signed immediate where the least significant bit is zero. def simm21_lsb0 : Operand { +// , ImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<21, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedInt<20, 1>(Imm); + }]; } // A parameterized register class alternative to i32imm/i64imm from Target.td. Index: lib/Target/RISCV/RISCVInstrInfoC.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfoC.td +++ lib/Target/RISCV/RISCVInstrInfoC.td @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// // Operand definitions. //===----------------------------------------------------------------------===// - def UImmLog2XLenNonZeroAsmOperand : AsmOperandClass { let Name = "UImmLog2XLenNonZero"; let RenderMethod = "addImmOperands"; @@ -27,18 +26,38 @@ let ParserMatchClass = UImmLog2XLenNonZeroAsmOperand; // TODO: should ensure invalid shamt is rejected when decoding. let DecoderMethod = "decodeUImmOperand<6>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + if (STI.getTargetTriple().isArch64Bit()) + return isUInt<6>(Imm) && (Imm != 0); + return isUInt<5>(Imm) && (Imm != 0); + }]; } def simm6 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<6>; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeSImmOperand<6>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isInt<6>(Imm); + }]; } def uimm6nonzero : Operand, ImmLeaf(Imm) && (Imm != 0);}]> { let ParserMatchClass = UImmAsmOperand<6, "NonZero">; let DecoderMethod = "decodeUImmOperand<6>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isUInt<6>(Imm) && (Imm != 0); + }]; } // A 7-bit unsigned immediate where the least significant two bits are zero. @@ -47,6 +66,12 @@ let ParserMatchClass = UImmAsmOperand<7, "Lsb00">; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeUImmOperand<7>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedUInt<5, 2>(Imm); + }]; } // A 8-bit unsigned immediate where the least significant two bits are zero. @@ -55,6 +80,12 @@ let ParserMatchClass = UImmAsmOperand<8, "Lsb00">; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeUImmOperand<8>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedUInt<6, 2>(Imm); + }]; } // A 8-bit unsigned immediate where the least significant three bits are zero. @@ -63,13 +94,26 @@ let ParserMatchClass = UImmAsmOperand<8, "Lsb000">; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeUImmOperand<8>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedUInt<5, 3>(Imm); + }]; } // A 9-bit signed immediate where the least significant bit is zero. def simm9_lsb0 : Operand { +// , ImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<9, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<9>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedInt<8, 1>(Imm); + }]; } // A 9-bit unsigned immediate where the least significant three bits are zero. @@ -78,6 +122,12 @@ let ParserMatchClass = UImmAsmOperand<9, "Lsb000">; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeUImmOperand<9>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedUInt<6, 3>(Imm); + }]; } // A 10-bit unsigned immediate where the least significant two bits are zero @@ -88,6 +138,12 @@ let ParserMatchClass = UImmAsmOperand<10, "Lsb00NonZero">; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeUImmOperand<10>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedUInt<8, 2>(Imm) && (Imm != 0); + }]; } // A 10-bit signed immediate where the least significant four bits are zero. @@ -96,13 +152,26 @@ let ParserMatchClass = SImmAsmOperand<10, "Lsb0000">; let EncoderMethod = "getImmOpValue"; let DecoderMethod = "decodeSImmOperand<10>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedInt<6, 4>(Imm); + }]; } // A 12-bit signed immediate where the least significant bit is zero. -def simm12_lsb0 : Operand { +def simm12_lsb0 : Operand // { + , ImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<12, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<12>"; + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Imm = MCOp.getImm(); + return isShiftedInt<11, 1>(Imm); + }]; } //===----------------------------------------------------------------------===// @@ -419,3 +488,128 @@ } } // Predicates = [HasStdExtC] + +//===----------------------------------------------------------------------===// +// Compressed Instructions Patterns for auto-generated Compress +// tablegen backend. +//===----------------------------------------------------------------------===// + +class CompressPat { + dag Input = input; + dag Output = output; + list Predicates = []; +} + +let Predicates = [HasStdExtC] in { +// FIXME: missing few D and Q instructions, nop, ebreak. +def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2), + (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>; +def : CompressPat<(AND GPRC:$rs1, GPRC:$rs1, GPRC:$rs2), + (C_AND GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(OR GPRC:$rs1, GPRC:$rs1, GPRC:$rs2), + (C_OR GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(XOR GPRC:$rs1, GPRC:$rs1, GPRC:$rs2), + (C_XOR GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(SUB GPRC:$rs1, GPRC:$rs1, GPRC:$rs2), + (C_SUB GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(ADDI GPRNoX0:$rs1, GPRNoX0:$rs1, simm6:$imm), + (C_ADDI GPRNoX0:$rs1, simm6:$imm)>; +def : CompressPat<(ANDI GPRC:$rs1, GPRC:$rs1, simm6:$imm), + (C_ANDI GPRC:$rs1, simm6:$imm)>; +def : CompressPat<(SLLI GPRNoX0:$rs1, GPRNoX0:$rs1, uimmlog2xlennonzero:$imm), + (C_SLLI GPRNoX0:$rs1, uimmlog2xlennonzero:$imm)>; +def : CompressPat<(SRLI GPRC:$rs1, GPRC:$rs1, uimmlog2xlennonzero:$imm), + (C_SRLI GPRC:$rs1, uimmlog2xlennonzero:$imm)>; +def : CompressPat<(SRAI GPRC:$rs1, GPRC:$rs1, uimmlog2xlennonzero:$imm), + (C_SRAI GPRC:$rs1, uimmlog2xlennonzero:$imm)>; +def : CompressPat<(JAL X0, simm12_lsb0:$offset), + (C_J simm12_lsb0:$offset)>; +def : CompressPat<(BEQ GPRC:$rs1, X0, simm9_lsb0:$imm), + (C_BEQZ GPRC:$rs1, simm9_lsb0:$imm)>; +def : CompressPat<(BNE GPRC:$rs1, X0, simm9_lsb0:$imm), + (C_BNEZ GPRC:$rs1, simm9_lsb0:$imm)>; +def : CompressPat<(ADDI GPRNoX0:$rd, X0, simm6:$imm), + (C_LI GPRNoX0:$rd, simm6:$imm)>; +def : CompressPat<(ADD GPRNoX0:$rs1, X0, GPRNoX0:$rs2), + (C_MV GPRNoX0:$rs1, GPRNoX0:$rs2)>; +def : CompressPat<(ADDI X2, X2, simm10_lsb0000:$imm), + (C_ADDI16SP X2, simm10_lsb0000:$imm)>; +def : CompressPat<(ADDI GPRC:$rd, SP:$rs1, uimm10_lsb00nonzero:$imm), + (C_ADDI4SPN GPRC:$rd, SP:$rs1, uimm10_lsb00nonzero:$imm)>; +def : CompressPat<(LUI GPRNoX0X2:$rd, uimm6nonzero:$imm), + (C_LUI GPRNoX0X2:$rd, uimm6nonzero:$imm)>; +def : CompressPat<(LW GPRC:$rd, GPRC:$rs1, uimm7_lsb00:$imm), + (C_LW GPRC:$rd, GPRC:$rs1, uimm7_lsb00:$imm)>; +def : CompressPat<(LW GPRNoX0:$rd, SP:$rs1, uimm8_lsb00:$imm), + (C_LWSP GPRNoX0:$rd, SP:$rs1, uimm8_lsb00:$imm)>; +def : CompressPat<(SW GPRC:$rs2, GPRC:$rs1, uimm7_lsb00:$imm), + (C_SW GPRC:$rs2, GPRC:$rs1, uimm7_lsb00:$imm)>; +def : CompressPat<(SW GPR:$rs2, SP:$rs1, uimm8_lsb00:$imm), + (C_SWSP GPR:$rs2, SP:$rs1, uimm8_lsb00:$imm)>; +def : CompressPat<(JALR X0, GPRNoX0:$rs1, 0), + (C_JR GPRNoX0:$rs1)>; +def : CompressPat<(JALR X1, GPRNoX0:$rs1, 0), + (C_JALR GPRNoX0:$rs1)>; + +// With commuted and repeated operands. +def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs2, GPRNoX0:$rs1), + (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>; +def : CompressPat<(AND GPRC:$rs1, GPRC:$rs2, GPRC:$rs1), + (C_AND GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(OR GPRC:$rs1, GPRC:$rs2, GPRC:$rs1), + (C_OR GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(XOR GPRC:$rs1, GPRC:$rs2, GPRC:$rs1), + (C_XOR GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs2, X0), + (C_MV GPRNoX0:$rs1, GPRNoX0:$rs2)>; +} // Predicates = [HasStdExtC] + +let Predicates = [HasStdExtC, IsRV32] in { +def : CompressPat<(JAL X1, simm12_lsb0:$offset), + (C_JAL simm12_lsb0:$offset)>; +} // Predicates = [HasStdExtC, IsRV32] + +let Predicates = [HasStdExtC, IsRV64] in { +def : CompressPat<(ADDW GPRC:$rs1, GPRC:$rs1, GPRC:$rs2), + (C_ADDW GPRC:$rs1, GPRC:$rs2)>; +def : CompressPat<(SUBW GPRC:$rs1, GPRC:$rs1, GPRC:$rs2), + (C_SUBW GPRC:$rs1, GPRC:$rs2)>; + +def : CompressPat<(ADDIW GPRNoX0:$rs1, GPRNoX0:$rs1, simm6:$imm), + (C_ADDIW GPRNoX0:$rs1, simm6:$imm)>; + +def : CompressPat<(LD GPRC:$rd, GPRC:$rs1, uimm8_lsb000:$imm), + (C_LD GPRC:$rd, GPRC:$rs1, uimm8_lsb000:$imm)>; +def : CompressPat<(LD GPRNoX0:$rd, SP:$rs1, uimm9_lsb000:$imm), + (C_LDSP GPRNoX0:$rd, SP:$rs1, uimm9_lsb000:$imm)>; +def : CompressPat<(SD GPRC:$rs2, GPRC:$rs1, uimm8_lsb000:$imm), + (C_SD GPRC:$rs2, GPRC:$rs1, uimm8_lsb000:$imm)>; +def : CompressPat<(SD GPR:$rs2, SP:$rs1, uimm9_lsb000:$imm), + (C_SDSP GPR:$rs2, SP:$rs1, uimm9_lsb000:$imm)>; + +// With commuted and repeated operands. +def : CompressPat<(ADDW GPRC:$rs1, GPRC:$rs2, GPRC:$rs1), + (C_ADDW GPRC:$rs1, GPRC:$rs2)>; +} // Predicates = [HasStdExtC, IsRV64] + +let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in { +def : CompressPat<(FLW FPR32C:$rd, GPRC:$rs1, uimm7_lsb00:$imm), + (C_FLW FPR32C:$rd, GPRC:$rs1, uimm7_lsb00:$imm)>; +def : CompressPat<(FLW FPR32:$rd, SP:$rs1, uimm8_lsb00:$imm), + (C_FLWSP FPR32:$rd, SP:$rs1, uimm8_lsb00:$imm)>; +def : CompressPat<(FSW FPR32C:$rs2, GPRC:$rs1,uimm7_lsb00:$imm), + (C_FSW FPR32C:$rs2, GPRC:$rs1, uimm7_lsb00:$imm)>; +def : CompressPat<(FSW FPR32:$rs2, SP:$rs1, uimm8_lsb00:$imm), + (C_FSWSP FPR32:$rs2, SP:$rs1, uimm8_lsb00:$imm)>; +} // Predicates = [HasStdExtC, HasStdExtF, IsRV32] + +let Predicates = [HasStdExtC, HasStdExtD] in { +def : CompressPat<(FLD FPR64C:$rd, GPRC:$rs1, uimm8_lsb000:$imm), + (C_FLD FPR64C:$rd, GPRC:$rs1, uimm8_lsb000:$imm)>; +def : CompressPat<(FLD FPR64:$rd, SP:$rs1, uimm9_lsb000:$imm), + (C_FLDSP FPR64:$rd, SP:$rs1, uimm9_lsb000:$imm)>; +def : CompressPat<(FSD FPR64C:$rs2, GPRC:$rs1, uimm8_lsb000:$imm), + (C_FSD FPR64C:$rs2, GPRC:$rs1, uimm8_lsb000:$imm)>; +def : CompressPat<(FSD FPR64:$rs2, SP:$rs1, uimm9_lsb000:$imm), + (C_FSDSP FPR64:$rs2, SP:$rs1, uimm9_lsb000:$imm)>; +} // Predicates = [HasStdExtC, HasStdExtD] Index: test/MC/RISCV/compress32.s =================================================================== --- /dev/null +++ test/MC/RISCV/compress32.s @@ -0,0 +1,259 @@ +# RUN: llvm-mc -triple riscv32 -mattr=+c,+f,+d -show-encoding < %s \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s +# RUN: llvm-mc -triple riscv32 -mattr=+c,+f,+d -show-encoding \ +# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -triple riscv32 -mattr=+c,+f,+d -filetype=obj < %s \ +# RUN: | llvm-objdump -triple riscv32 -mattr=+c,+f,+d -d - \ +# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s +# RUN: llvm-mc -triple riscv32 -mattr=+c,+f,+d -filetype=obj < %s \ +# RUN: | llvm-objdump -triple riscv32 -mattr=+c,+f,+d -d -riscv-no-aliases - \ +# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s + +#Load and Store Instructions +lw ra, 252 (sp) +# CHECK-BYTES: fe 50 +# CHECK-ALIAS: lw ra, 252(sp) +# CHECK-INST: c.lwsp ra, 252(sp) +# CHECK: # encoding: [0xfe,0x50] +sw x0, 252 (x2) +# CHECK-BYTES: 82 df +# CHECK-ALIAS: sw zero, 252(sp) +# CHECK-INST: c.swsp zero, 252(sp) +# CHECK: # encoding: [0x82,0xdf] +lw x8, 124 (x15) +# CHECK-BYTES: e0 5f +# CHECK-ALIAS: lw s0, 124(a5) +# CHECK-INST: c.lw s0, 124(a5) +# CHECK: # encoding: [0xe0,0x5f] +sw x8, 124 (x15) +# CHECK-BYTES: e0 df +# CHECK-ALIAS: sw s0, 124(a5) +# CHECK-INST: c.sw s0, 124(a5) +# CHECK: # encoding: [0xe0,0xdf] + +#Load and Store Instructions 32 bit only +flw ft0, 124(sp) +# CHECK-BYTES: 76 70 +# CHECK-ALIAS: flw ft0, 124(sp) +# CHECK-INST: c.flwsp ft0, 124(sp) +# CHECK: # encoding: [0x76,0x70] +fsw ft0, 124(sp) +# CHECK-BYTES: 82 fe +# CHECK-ALIAS: fsw ft0, 124(sp) +# CHECK-INST: c.fswsp ft0, 124(sp) +# CHECK: # encoding: [0x82,0xfe] +flw fs0, 124(s0) +# CHECK-BYTES: 60 7c +# CHECK-ALIAS: flw fs0, 124(s0) +# CHECK-INST: c.flw fs0, 124(s0) +# CHECK: # encoding: [0x60,0x7c] +fsw fs0, 124(s0) +# CHECK-BYTES: 60 fc +# CHECK-ALIAS: fsw fs0, 124(s0) +# CHECK-INST: c.fsw fs0, 124(s0) +# CHECK: # encoding: [0x60,0xfc] + +#Load and Store Instructions 32 and 64 bit only +fld ft0, 64 (sp) +# CHECK-BYTES: 06 20 +# CHECK-ALIAS: fld ft0, 64(sp) +# CHECK-INST: c.fldsp ft0, 64(sp) +# CHECK: # encoding: [0x06,0x20] +fsd ft0, 64 (sp) +# CHECK-BYTES: 82 a0 +# CHECK-ALIAS: fsd ft0, 64(sp) +# CHECK-INST: c.fsdsp ft0, 64(sp) +# CHECK: # encoding: [0x82,0xa0] +fld fs0, 248(s0) +# CHECK-BYTES: 60 3c +# CHEC-ALIAS: fld fs0, 248(s0) +# CHECK-INST: c.fld fs0, 248(s0) +# CHECK: # encoding: [0x60,0x3c] +fsd fs0, 248(s0) +# CHECK-BYTES: 60 bc +# CHECK-ALIAS: fsd fs0, 248(s0) +# CHECK-INST: c.fsd fs0, 248(s0) +# CHECK: # encoding: [0x60,0xbc] + +# Control Transfer Instructions + +jal zero, -2048 +# CHECK-BYTES: 01 b0 +# CHECK-ALIAS: j -2048 +# CHECK-INST: c.j -2048 +# CHECK: # encoding: [0x01,0xb0] +jal ra, 2046 +# CHECK-BYTES: fd 2f +# CHECK-ALIAS: jal 2046 +# CHECK-INST: c.jal 2046 +# CHECK: # encoding: [0xfd,0x2f] +jalr zero, ra, 0 +# CHECK-BYTES: 82 80 +# CHECK-ALIAS-NOT: jalr zero, ra, 0 +# CHECK-ALIAS: ret +# CHECK-INST: c.jr ra +# CHECK: # encoding: [0x82,0x80] +jalr ra, s0, 0 +# CHECK-BYTES: 02 94 +# CHECK-ALIAS-NOT: jalr ra, s0, 0 +# CHECK-ALIAS: jalr s0 +# CHECK-INST: c.jalr s0 +# CHECK: # encoding: [0x02,0x94] + +beq s0, zero, -256 +# CHECK-BYTES: 01 d0 +# CHECK-ALIAS-NOT: beq s0, zero, -256 +# CHECK-ALIAS: beqz s0, -256 +# CHECK-INST: c.beqz s0, -256 +# CHECK: # encoding: [0x01,0xd0] +bne s0, zero, 254 +# CHECK-BYTES: 7d ec +# CHECk-ALIAS-NOT: bne s0, zero, 254 +# CHECk-ALIAS: bnez s0, 254 +# CHECK-INST: c.bnez s0, 254 +# CHECK: # encoding: [0x7d,0xec] + +# Integer Computational Instructions + +addi ra, zero, -31 +# CHECK-BYTES: 85 50 +# CHECK-ALIAS: addi ra, zero, -31 +# CHECK-INST: c.li ra, -31 +# CHECK: # encoding: [0x85,0x50] +lui gp, 63 +# CHECK-BYTES: fd 71 +# CHECK-ALIAS: lui gp, 63 +# CHECK-INST: c.lui gp, 63 +# CHECK: # encoding: [0xfd,0x71] +addi ra, ra, -32 +# CHECK-BYTES: 81 10 +# CHECK-ALIAS: addi ra, ra, -32 +# CHECK-INST: c.addi ra, -32 +# CHECK: # encoding: [0x81,0x10] +addi sp, sp, -64 +# CHECK-BYTES: 39 71 +# CHECK-ALIAS: addi sp, sp, -64 +# CHECK-INST: c.addi16sp sp, -64 +# CHECK: # encoding: [0x39,0x71] + +slli s0, s0, 31 +# CHECK-BYTES: 7e 04 +# CHECK-ALIAS: slli s0, s0, 31 +# CHECK-INST: c.slli s0, 31 +# CHECK: # encoding: [0x7e,0x04] +srli s0, s0, 31 +# CHECK-BYTES: 7d 80 +# CHECK-ALIAS: srli s0, s0, 31 +# CHECK-INST: c.srli s0, 31 +# CHECK: # encoding: [0x7d,0x80] +srai s0, s0, 31 +# CHECK-BYTES: 7d 84 +# CHECK-ALIAS: srai s0, s0, 31 +# CHECK-INST: c.srai s0, 31 +# CHECK: # encoding: [0x7d,0x84] + +andi s0, s0, 31 +# CHECK-BYTES: 7d 88 +# CHECK-ALIAS: andi s0, s0, 31 +# CHECK-INST: c.andi s0, 31 +# CHECK: # encoding: [0x7d,0x88] + +# Integer Computational Instructions 32/64 bit only +addi s0, sp, 1020 +# CHECK-BYTES: e0 1f +# CHECK-ALIAS: addi s0, sp, 1020 +# CHECK-INST: c.addi4spn s0, sp, 1020 +# CHECK: # encoding: [0xe0,0x1f] + +# Integer Register-Tegister Operations +add s0, zero, a5 +# CHECK-BYTES: 3e 84 +# CHECK-ALIAS: add s0, zero, a5 +# CHECK-INST: c.mv s0, a5 +# CHECK: # encoding: [0x3e,0x84] +add s0, s0, a5 +# CHECK-BYTES: 3e 94 +# CHECK-ALIAS: add s0, s0, a5 +# CHECK-INST: c.add s0, a5 +# CHECK: # encoding: [0x3e,0x94] +and s0, s0, a5 +# CHECK-BYTES: 7d 8c +# CHECK-ALIAS: and s0, s0, a5 +# CHECK-INST: c.and s0, a5 +# CHECK: # encoding: [0x7d,0x8c] +or s0, s0, a5 +# CHECK-BYTES: 5d 8c +# CHECK_ALIAS: or s0, s0, a5 +# CHECK_INST: c.or s0, a5 +# CHECK: # encoding: [0x5d,0x8c] +xor s0, s0, a5 +# CHECK-BYTES: 3d 8c +# CHECK_ALIAS: xor s0, s0, a5 +# CHECK-INST: c.xor s0, a5 +# CHECK: # encoding: [0x3d,0x8c] +sub s0, s0, a5 +# CHECK-BYTES: 1d 8c +# CHECK-ALIAS: sub s0, s0, a5 +# CHECK-INST: c.sub s0, a5 +# CHECK: # encoding: [0x1d,0x8c] + +# With commuted and repeated operands. +add ra, tp, ra +# CHECK-BYTES: 92 90 +# CHECK-ALIAS: add ra, ra, tp +# CHECK-INST: c.add ra, tp +# CHECK: # encoding: [0x92,0x90] +add ra, ra, ra +# CHECK-BYTES: 86 90 +# CHECK-ALIAS: add ra, ra, ra +# CHECK-INST: c.add ra, ra +# CHECK: # encoding: [0x86,0x90] +and s0, s1, s0 +# CHECK-BYTES: 65 8c +# CHECK-ALIAS: and s0, s0, s1 +# CHECK-INST: c.and s0, s1 +# CHECK: # encoding: [0x65,0x8c] +and s0, s0, s0 +# CHECK-BYTES: 61 8c +# CHECK-ALIAS: and s0, s0, s0 +# CHECK-INST: c.and s0, s0 +# CHECK: # encoding: [0x61,0x8c] +or s0, s1, s0 +# CHECK-BYTES: 45 8c +# CHECK-ALIAS: or s0, s0, s1 +# CHECK-INST: c.or s0, s1 +# CHECK: # encoding: [0x45,0x8c] +or s0, s0, s0 +# CHECK-BYTES: 41 8c +# CHECK-ALIAS: or s0, s0, s0 +# CHECK-INST: c.or s0, s0 +# CHECK: # encoding: [0x41,0x8c] +xor s0, s1, s0 +# CHECK-BYTES: 25 8c +# CHECK-ALIAS: xor s0, s0, s1 +# CHECK-INST: c.xor s0, s1 +# CHECK: # encoding: [0x25,0x8c] +xor s0, s0, s0 +# CHECK-BYTES: 21 8c +# CHECK-ALIAS: xor s0, s0, s0 +# CHECK-INST: c.xor s0, s0 +# CHECK: # encoding: [0x21,0x8c] +add ra, zero, tp +# CHECK-BYTES: 92 80 +# CHECK-ALIAS: add ra, zero, tp +# CHECK-INST: c.mv ra, tp +# CHECK: # encoding: [0x92,0x80] +add ra, tp, zero +# CHECK-BYTES: 92 80 +# CHECK-ALIAS: add ra, zero, tp +# CHECK-INST: c.mv ra, tp +# CHECK: # encoding: [0x92,0x80] + + +# FIXME: nop and ebreak. +#c.nop +#addi x0, x0, 0 +#c.ebreak +#c.add x0, x0 + + Index: test/MC/RISCV/compress64.s =================================================================== --- /dev/null +++ test/MC/RISCV/compress64.s @@ -0,0 +1,298 @@ +# RUN: llvm-mc -triple riscv64 -mattr=+c,+f,+d -show-encoding < %s \ +# RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s +# RUN: llvm-mc -triple riscv64 -mattr=+c,+f,+d -show-encoding \ +# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %s +# RUN: llvm-mc -triple riscv64 -mattr=+c,+f,+d -filetype=obj < %s \ +# RUN: | llvm-objdump -triple riscv64 -mattr=+c,+f,+d -d - \ +# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s +# RUN: llvm-mc -triple riscv64 -mattr=+c,+f,+d -filetype=obj < %s \ +# RUN: | llvm-objdump -triple riscv64 -mattr=+c,+f,+d -d -riscv-no-aliases - \ +# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s + +#Load and Store Instructions +lw ra, 252(sp) +# CHECK-BYTES: fe 50 +# CHECK-ALIAS: lw ra, 252(sp) +# CHECK-INST: c.lwsp ra, 252(sp) +# CHECK: # encoding: [0xfe,0x50] +sw zero, 252(sp) +# CHECK-BYTES: 82 df +# CHECK-ALIAS: sw zero, 252(sp) +# CHECK-INST: c.swsp zero, 252(sp) +# CHECK: # encoding: [0x82,0xdf] +lw s0, 124(a5) +# CHECK-BYTES: e0 5f +# CHECK-ALIAS: lw s0, 124(a5) +# CHECK-INST: c.lw s0, 124(a5) +# CHECK: # encoding: [0xe0,0x5f] +sw s0, 124(a5) +# CHECK-BYTES: e0 df +# CHECK-ALIAS: sw s0, 124(a5) +# CHECK-INST: c.sw s0, 124(a5) +# CHECK: # encoding: [0xe0,0xdf] + +#Load and Store Instructions 32 and 64 bit only +fld ft0, 64(sp) +# CHECK-BYTES: 06 20 +# CHECK-ALIAS: fld ft0, 64(sp) +# CHECK-INST: c.fldsp ft0, 64(sp) +# CHECK: # encoding: [0x06,0x20] +fsd ft0, 64(sp) +# CHECK-BYTES: 82 a0 +# CHECK-ALIAS: fsd ft0, 64(sp) +# CHECK-INST: c.fsdsp ft0, 64(sp) +# CHECK: # encoding: [0x82,0xa0] +fld fs0, 248(s0) +# CHECK-BYTES: 60 3c +# CHECK-ALIAS: fld fs0, 248(s0) +# CHECK-INST: c.fld fs0, 248(s0) +# CHECK: # encoding: [0x60,0x3c] +fsd fs0, 248(s0) +# CHECK-BYTES: 60 bc +# CHECK-ALIAS: fsd fs0, 248(s0) +# CHECK-INST: c.fsd fs0, 248(s0) +# CHECK: # encoding: [0x60,0xbc] + +#Load and Store Instructions 64/128bit +ld s0, 248(a5) +# CHECK-BYTES: e0 7f +# CHECK-ALIAS: ld s0, 248(a5) +# CHECK-INST: c.ld s0, 248(a5) +# CHECK: # encoding: [0xe0,0x7f] +ld ra, 248(sp) +# CHECK-BYTES: ee 70 +# CHECK-ALIAS: ld ra, 248(sp) +# CHECK-INST: c.ldsp ra, 248(sp) +# CHECK: # encoding: [0xee,0x70] +sd s0, 64(sp) +# CHECK-BYTES: a2 e0 +# CHECK-ALIAS: sd s0, 64(sp) +# CHECK-INST: c.sdsp s0, 64(sp) +# CHECK: # encoding: [0xa2,0xe0] +sd s0, 64(a5) +# CHECK-BYTES: a0 e3 +# CHECK-ALIAS: sd s0, 64(a5) +# CHECK-INST: c.sd s0, 64(a5) +# CHECK: # encoding: [0xa0,0xe3] + +# FIXME: Load and Store Instructions 128bit +# lq x8, 252 (x15) +# c.lq x8, 252 (x15) +# lq x1, 252 (x2) +# c.ldsp x1, 252 (x2) +# sq x1, 252 (x2) +# c.sqsp x1, 252 (x2) +# sq x8, 252 (x15) + +# Control Transfer Instructions + +jal zero, -2048 +# CHECK-BYTES: 01 b0 +# CHECK-ALIAS: j -2048 +# CHECK-INST: c.j -2048 +# CHECK: # encoding: [0x01,0xb0] +jalr zero, ra, 0 +# CHECK-BYTES: 82 80 +# CHEACK-ALIAS: jalr zero, ra, 0 +# CHECK-INST: c.jr ra +# CHECK: # encoding: [0x82,0x80] +jalr ra, s0, 0 +# CHECK-BYTES: 02 94 +# CHEACK-ALIAS: jalr ra, s0, 0 +# CHECK-INST: c.jalr s0 +# CHECK: # encoding: [0x02,0x94] + +beq s0, zero, -256 +# CHECK-BYTES: 01 d0 +# CHECK-ALIAS: beqz s0, -256 +# CHECK-INST: c.beqz s0, -256 +# CHECK: # encoding: [0x01,0xd0] +bne s0, zero, 254 +# CHECK-BYTES: 7d ec +# CHECk-ALIAS: bnez s0, 254 +# CHECK-INST: c.bnez s0, 254 +# CHECK: # encoding: [0x7d,0xec] + +# Integer Computational Instructions + +addi ra, zero, -31 +# CHECK-BYTES: 85 50 +# CHECK-ALIAS: addi ra, zero, -31 +# CHECK-INST: c.li ra, -31 +# CHECK: # encoding: [0x85,0x50] +lui gp, 63 +# CHECK-BYTES: fd 71 +# CHECK-ALIAS: lui gp, 63 +# CHECK-INST: c.lui gp, 63 +# CHECK: # encoding: [0xfd,0x71] +addi ra, ra, -32 +# CHECK-BYTES: 81 10 +# CHECK-ALIAS: addi ra, ra, -32 +# CHECK-INST: c.addi ra, -32 +# CHECK: # encoding: [0x81,0x10] +addi sp, sp, -64 +# CHECK-BYTES: 39 71 +# CHECK-ALIAS: addi sp, sp, -64 +# CHECK-INST: c.addi16sp sp, -64 +# CHECK: # encoding: [0x3d,0x71] +# CHECK: # encoding: [0x39,0x71] + +slli s0, s0, 31 +# CHECK-BYTES: 7e 04 +# CHECK-ALIAS: slli s0, s0, 31 +# CHECK-INST: c.slli s0, 31 +# CHECK: # encoding: [0x7e,0x04] +srli s0, s0, 31 +# CHECK-BYTES: 7d 80 +# CHECK-ALIAS: srli s0, s0, 31 +# CHECK-INST: c.srli s0, 31 +# CHECK: # encoding: [0x7d,0x80] +srai s0, s0, 31 +# CHECK-BYTES: 7d 84 +# CHEACK-ALIAS: srai s0, s0, 31 +# CHECK-INST: c.srai s0, 31 +# CHECK: # encoding: [0x7d,0x84] + +andi s0, s0, 31 +# CHECK-BYTES: 7d 88 +# CHEACK-ALIAS: andi s0, s0, 31 +# CHECK-INST: c.andi s0, 31 +# CHECK: # encoding: [0x7d,0x88] + +# Integer Computational Instructions 32/64 bit only +addi s0, sp, 1020 +# CHECK-BYTES: e0 1f +# CHECK-ALIAS: addi s0, sp, 1020 +# CHECK-INST: c.addi4spn s0, sp, 1020 +# CHECK: # encoding: [0xe0,0x1f] + +# Integer Computational Instructions 64/128 bit only +addiw tp, tp, 31 +# CHECK-BYTES: 7d 22 +# CHEACK-ALIAS: addiw tp, tp, 31 +# CHECK-INST: c.addiw tp, 31 +# CHECK: # encoding: [0x7d,0x22] +#sext.w x4 +# c.addiw tp, 0 + +# FIXME: Integer Computational Instructions 128 bit only +#slli x8, x8, 64 +#c.slli x8, 0 +#srli x8, x8, 64 +#c.srli x8, 0 +#srai x8, x8, 64 +#c.srai x8, 0 + +# Integer Register-Tegister Operations +add s0, zero, a5 +# CHECK-BYTES: 3e 84 +# CHECK-ALIAS: add s0, zero, a5 +# CHECK-INST: c.mv s0, a5 +# CHECK: # encoding: [0x3e,0x84] +add s0, s0, a5 +# CHECK-BYTES: 3e 94 +# CHECK-ALIAS: add s0, s0, a5 +# CHECK-INST: c.add s0, a5 +# CHECK: # encoding: [0x3e,0x94] +and s0, s0, a5 +# CHECK-BYTES: 7d 8c +# CHECK-ALIAS: and s0, s0, a5 +# CHECK-INST: c.and s0, a5 +# CHECK: # encoding: [0x7d,0x8c] +or s0, s0, a5 +# CHECK-BYTES: 5d 8c +# CHECK-ALIAS: or s0, s0, a5 +# CHECK-INST: c.or s0, a5 +# CHECK: # encoding: [0x5d,0x8c] +xor s0, s0, a5 +# CHECK-BYTES: 3d 8c +# CHECK-ALIAS: xor s0, s0, a5 +# CHECK-INST: c.xor s0, a5 +# CHECK: # encoding: [0x3d,0x8c] +sub s0, s0, a5 +# CHECK-BYTES: 1d 8c +# CHECK-ALIAS: sub s0, s0, a5 +# CHECK-INST: c.sub s0, a5 +# CHECK: # encoding: [0x1d,0x8c] + + +# Integer Register-Tegister Operations 64/128 only +addw s0, s0, a5 +# CHECK-BYTES: 3d 9c +# CHECK-ALIAS: addw s0, s0, a5 +# CHECK-INST: c.addw s0, a5 +# CHECK: # encoding: [0x3d,0x9c] +subw s0, s0, a5 +# CHECK-BYTES: 1d 9c +# CHEACK-ALIAS: subw s0, s0, a5 +# CHECK-INST: c.subw s0, a5 +# CHECK: # encoding: [0x1d,0x9c] + +# With commuted and repeated operands. +add ra, tp, ra +# CHECK-BYTES: 92 90 +# CHECK-ALIAS: add ra, ra, tp +# CHECK-INST: c.add ra, tp +# CHECK: # encoding: [0x92,0x90] +add ra, ra, ra +# CHECK-BYTES: 86 90 +# CHECK-ALIAS: add ra, ra, ra +# CHECK-INST: c.add ra, ra +# CHECK: # encoding: [0x86,0x90] +and s0, s1, s0 +# CHECK-BYTES: 65 8c +# CHECK-ALIAS: and s0, s0, s1 +# CHECK-INST: c.and s0, s1 +# CHECK: # encoding: [0x65,0x8c] +and s0, s0, s0 +# CHECK-BYTES: 61 8c +# CHECK-ALIAS: and s0, s0, s0 +# CHECK-INST: c.and s0, s0 +# CHECK: # encoding: [0x61,0x8c] +or s0, s1, s0 +# CHECK-BYTES: 45 8c +# CHECK-ALIAS: or s0, s0, s1 +# CHECK-INST: c.or s0, s1 +# CHECK: # encoding: [0x45,0x8c] +or s0, s0, s0 +# CHECK-BYTES: 41 8c +# CHECK-ALIAS: or s0, s0, s0 +# CHECK-INST: c.or s0, s0 +# CHECK: # encoding: [0x41,0x8c] +xor s0, s1, s0 +# CHECK-BYTES: 25 8c +# CHECK-ALIAS: xor s0, s0, s1 +# CHECK-INST: c.xor s0, s1 +# CHECK: # encoding: [0x25,0x8c] +xor s0, s0, s0 +# CHECK-BYTES: 21 8c +# CHECK-ALIAS: xor s0, s0, s0 +# CHECK-INST: c.xor s0, s0 +# CHECK: # encoding: [0x21,0x8c] +add ra, zero, tp +# CHECK-BYTES: 92 80 +# CHECK-ALIAS: add ra, zero, tp +# CHECK-INST: c.mv ra, tp +# CHECK: # encoding: [0x92,0x80] +add ra, tp, zero +# CHECK-BYTES: 92 80 +# CHECK-ALIAS: add ra, zero, tp +# CHECK-INST: c.mv ra, tp +# CHECK: # encoding: [0x92,0x80] +addw s0, s1, s0 +# CHECK-BYTES: 25 9c +# CHECK-ALIAS: addw s0, s0, s1 +# CHECK-INST: c.addw s0, s1 +# CHECK: # encoding: [0x25,0x9c] +addw s0, s0, s0 +# CHECK-BYTES: 21 9c +# CHECK-ALIAS: addw s0, s0, s0 +# CHECK-INST: c.addw s0, s0 +# CHECK: # encoding: [0x21,0x9c] + +# FIXME: nop and ebreak. +#c.nop +#addi x0, x0, 0 +#c.ebreak +#c.add x0, x0 + Index: utils/TableGen/CMakeLists.txt =================================================================== --- utils/TableGen/CMakeLists.txt +++ utils/TableGen/CMakeLists.txt @@ -29,6 +29,7 @@ InstrDocsEmitter.cpp IntrinsicEmitter.cpp OptParserEmitter.cpp + RISCVCompressEmitter.cpp PseudoLoweringEmitter.cpp RegisterBankEmitter.cpp RegisterInfoEmitter.cpp Index: utils/TableGen/RISCVCompressEmitter.cpp =================================================================== --- /dev/null +++ utils/TableGen/RISCVCompressEmitter.cpp @@ -0,0 +1,817 @@ +//===- RISCVCompressEmitter.cpp - Generator for RISCV Compression -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// RISCVCompressEmitter implements a tablegen-driven RISCV Instruction +// Compression mechanism. +// +//===--------------------------------------------------------------===// +// +// RISCVCompressEmitter 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 instuctions. +// The checks include validating register operands, immediate +// operands, fixed register operands and fixed immediate operands. +// +// Example: +// class CompressPat { +// dag Input = input; +// dag Output = output; +// list 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. + +//===----------------------------------------------------------------------===// + +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +using namespace llvm; + +#define DEBUG_TYPE "compress-emitter" + +namespace { +class RISCVCompressEmitter { + struct OpData { + enum MapKind { Operand, Imm, Reg }; + MapKind Kind; + union { + unsigned Operand; // Operand number mapped to. + uint64_t Imm; // Integer immedate value. + Record *Reg; // Physical register. + } Data; + }; + struct CompressTransform { + CodeGenInstruction Source; // The source instruction definition. + CodeGenInstruction Dest; // The destination instruction to transform to. + std::vector PatReqFeatures; + IndexedMap + SourceOperandMap; // Maps operands in the Source Instruction to + // the corresponding Dest operand. + IndexedMap DestOperandMap; // Maps operands in th Dest Instruction + // to the corresponding Source operand. + std::pair MatchPair; + CompressTransform(CodeGenInstruction &S, CodeGenInstruction &D, + std::vector RF, IndexedMap &SourceMap, + IndexedMap &DestMap, + std::pair &mp) + : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap), + DestOperandMap(DestMap), MatchPair(mp) {} + }; + + RecordKeeper &Records; + + // It's overkill to have an instance of the full CodeGenTarget object, + // but it loads everything on demand, not in the constructor, so it's + // lightweight in performance, so it works out OK. + CodeGenTarget Target; + + SmallVector Expansions; + + unsigned addDagOperandMapping(Record *Rec, DagInit *Dag, + CodeGenInstruction &Insn, + IndexedMap &OperandMap, + unsigned BaseIdx, bool IsSource); + void evaluateCompressTransform(Record *Compress); + void emitCompressEmitter(raw_ostream &o, bool Compress); + bool matchTypes(Record *SubType, Record *Type, bool IsSource); + bool matchRegisterClass(Record *Reg, Record *RegClass); + +public: + RISCVCompressEmitter(RecordKeeper &R) : Records(R), Target(R) {} + + /// run - Output the compress-lowering. + void run(raw_ostream &o); +}; +} // End anonymous namespace + +bool RISCVCompressEmitter::matchRegisterClass(Record *Reg, Record *RegClass) { + assert(Reg->isSubClassOf("Register") && + "Reg record is should be a Register\n"); + assert(RegClass->isSubClassOf("RegisterClass") && "RegClass record should be" + " a RegisterClass\n"); + CodeGenRegisterClass RC = Target.getRegisterClass(RegClass); + const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower()); + assert((R != NULL) && + ("Register" + Reg->getName() + "not defined!!\n").str().c_str()); + return RC.contains(R); +} + +bool RISCVCompressEmitter::matchTypes(Record *SubType, Record *Type, + bool IsSource) { + // Check that both records are register types. + // If the types are registers check for register containment. + DEBUG(dbgs() << "Checking Type : " << SubType->getName() << " and " + << Type->getName() << ".\n"); + if (SubType == Type) + return true; + + // Only Source is allowed to not have exact type match with the dag. + if (!IsSource) + return false; + + if (SubType->isSubClassOf("RegisterClass") && + Type->isSubClassOf("RegisterClass")) { + DEBUG(dbgs() + << " Both types are registers so we can check register classes.\n"); + CodeGenRegisterClass RC = Target.getRegisterClass(Type); + CodeGenRegisterClass SubRC = Target.getRegisterClass(SubType); + return RC.hasSubClass(&SubRC); + } else if (SubType->isSubClassOf("ImmLeaf") || + Type->isSubClassOf("ImmLeaf")) { + DEBUG(dbgs() << "Type : " << SubType->getName() << " and " + << Type->getName() + << " is an immediate type and can't be checked for\n" + << " compatibility relying only on runtime check for\n" + << " the operand value.\n"); + return true; + } else if ((SubType->isSubClassOf("RegisterClass") && + Type->isSubClassOf("ImmLeaf")) || + (SubType->isSubClassOf("ImmLeaf") && + Type->isSubClassOf("RegisterClass"))) { + return false; + } + + // FIXME: In theory we shouldn't need to return true by default but we + // have to since some immediate types in RISCV are not a SubClass of ImmLeaf. + return true; +} + +unsigned RISCVCompressEmitter::addDagOperandMapping( + Record *Rec, DagInit *Dag, CodeGenInstruction &Insn, + IndexedMap &OperandMap, unsigned BaseIdx, bool IsSource) { + unsigned OpsAdded = 0; + unsigned TiedCount = 0; + DEBUG(dbgs() << "addDagOperandMapping: " << *Dag << "\n"); + for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { + if (DefInit *DI = dyn_cast(Dag->getArg(i))) { + // Physical register reference. Explicit check for the special case + // "zero_reg" definition. + if (DI->getDef()->isSubClassOf("Register") || + DI->getDef()->getName() == "zero_reg") { + DEBUG(dbgs() << " Found Physical register at index'" << i << ": " + << *DI << "'\n"); + // Check if the constant register belongs to the Register class. + bool Match = + matchRegisterClass(DI->getDef(), Insn.Operands[TiedCount + i].Rec); + if (!Match) + PrintFatalError(Rec->getLoc(), + "Register: '" + DI->getDef()->getName() + + "' is not in register class '" + + Insn.Operands[TiedCount + i].Rec->getName() + + "'"); + OperandMap[/*BaseIdx +*/ TiedCount + i].Kind = OpData::Reg; + OperandMap[/*BaseIdx +*/ TiedCount + i].Data.Reg = DI->getDef(); + ++OpsAdded; + continue; + } + + // Normal operands should always have the same type, or we have a + // problem. + // FIXME: We probably shouldn't ever get a non-zero BaseIdx here. + // assert(BaseIdx == 0 && "Named subargument in compress transform?!"); + // If this Inst operand is a tied operand it means that we have less dag + // args than Inst Args and that the current Inst argument is tied to a + // previous argument that got checked. + int TiedOpIdx = + Insn.Operands[/*BaseIdx + */ TiedCount + i].getTiedRegister(); + if (-1 != TiedOpIdx) { + // Set the entry in OperandMap for the tied operand we're skipping. + OperandMap[/*BaseIdx + */ TiedCount + i].Kind = + OperandMap[TiedOpIdx].Kind; + OperandMap[/*BaseIdx + */ TiedCount + i].Data = + OperandMap[TiedOpIdx].Data; + TiedCount++; + } + + bool Match = + matchTypes(DI->getDef(), Insn.Operands[TiedCount + i].Rec, IsSource); + if (!Match) { + PrintFatalError( + Rec->getLoc(), + "Input operand type in dag'" + DI->getDef()->getName() + + "' does not match Inst operand type '" + + Insn.Operands[/*BaseIdx +*/ i + TiedCount].Rec->getName() + + "'"); + } + // Source operand maps to destination operand. The Data element + // will be filled in later, just set the Kind for now. Do it + // for each corresponding MachineInstr operand, not just the first. + for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I) + OperandMap[/*BaseIdx + */ TiedCount + i + I].Kind = OpData::Operand; + OpsAdded += Insn.Operands[i].MINumOperands; + } else if (IntInit *II = dyn_cast(Dag->getArg(i))) { + DEBUG(dbgs() << " Found immediate at index " << /*BaseIdx +*/ i << ": '" + << II->getValue() << "'\n"); + OperandMap[/*BaseIdx*/ TiedCount + i].Kind = OpData::Imm; + OperandMap[/*BaseIdx*/ TiedCount + i].Data.Imm = II->getValue(); + ++OpsAdded; + } else if (DagInit *SubDag = dyn_cast(Dag->getArg(i))) { + // Just add the operands recursively. This is almost certainly + // a constant value for a complex operand (> 1 MI operand). + unsigned NewOps = + addDagOperandMapping(Rec, SubDag, Insn, OperandMap, + /*BaseIdx +*/ TiedCount + i, IsSource); + OpsAdded += NewOps; + // Since we added more than one, we also need to adjust the base. + BaseIdx += NewOps - 1; + } else + llvm_unreachable("Unhandled compress-transform argument type!"); + } + return OpsAdded; +} + +unsigned getNumOperands(Record *R) { + return R->getValueAsDag("OutOperandList")->getNumArgs() + + R->getValueAsDag("InOperandList")->getNumArgs(); +} + +// Make sure that the dag has enough arguments to fill the instruction +// that it refers to in the operator. +// TODO: this can be merged with addOperandMapping. +bool matchInsDag(CodeGenInstruction &Inst, DagInit *dag, bool IsSource) { + + // Number of operands in the dag and the Inst match. + if (dag->getNumArgs() == Inst.Operands.size()) + return true; + + if (IsSource) + PrintFatalError("Source operands for Inst '" + Inst.TheDef->getName() + + "' and dag operand count mismatch"); + + // The dag can't have more arguments than the Instruction. + if (dag->getNumArgs() > Inst.Operands.size()) + PrintFatalError("Inst '" + Inst.TheDef->getName() + + "' and dag operand count mismatch"); + + DEBUG(dbgs() << "Inst = : " << Inst.AsmString << "\n"); + DEBUG(dbgs() << "Inst.Operands.size = : " << Inst.Operands.size() << "\n"); + DEBUG(dbgs() << "Dag->getNumArgs(): " << dag->getNumArgs() << "\n"); + + // The Instruction might have tied operands so the number of operands + // so the dag might have a fewer operand count. We need to check for that. + unsigned InstOperandNeedCount = Inst.Operands.size(); + for (unsigned i = 0; i < Inst.Operands.size(); i++) { + if (Inst.Operands[i].getTiedRegister() != -1) { + DEBUG(dbgs() << " Tied Operand Register found: " << Inst.Operands[i].Name + << "\n"); + InstOperandNeedCount--; + } + } + + if (dag->getNumArgs() != InstOperandNeedCount) + PrintFatalError("Inst '" + Inst.TheDef->getName() + + "' and dag operand count mismatch"); + return true; +} + +static bool matchArgTypes(Init *Arg1, Init *Arg2) { + DefInit *Def1 = dyn_cast(Arg1); + DefInit *Def2 = dyn_cast(Arg2); + assert(Def1 && ("Arg type not found\n")); + assert(Def2 && ("Arg2 type not found\n")); + Record *Rec1 = Def1->getDef(); + Record *Rec2 = Def2->getDef(); + return Rec1 == Rec2; +} + +// Map the Input instruction arguments to the output instruction arguments. +void RISCVCompressEmitter::evaluateCompressTransform(Record *Rec) { + + // Read the input Instruction first: + DagInit *InputDag = Rec->getValueAsDag("Input"); + assert(InputDag && "Missing Input in compress transform!"); + DEBUG(dbgs() << "Input: " << *InputDag << "\n"); + + DefInit *OpDef = dyn_cast(InputDag->getOperator()); + if (!OpDef) + PrintFatalError(Rec->getLoc(), + Rec->getName() + " has unexpected operator type!"); + Record *Operator = OpDef->getDef(); + if (!Operator->isSubClassOf("RVInst")) + PrintFatalError(Rec->getLoc(), "Compression input '" + Operator->getName() + + "' is not a 32 bit width instruction!"); + CodeGenInstruction SourceInsn(Operator); + matchInsDag(SourceInsn, InputDag, true); + + DagInit *CompressDag = Rec->getValueAsDag("Output"); + assert(InputDag && "Missing Output in compress transform!"); + DEBUG(dbgs() << "Output: " << *CompressDag << "\n"); + + DefInit *CompressOpDef = dyn_cast(CompressDag->getOperator()); + if (!CompressOpDef) + PrintFatalError(Rec->getLoc(), + Rec->getName() + " has unexpected operator type!"); + + Record *CompressOperator = CompressOpDef->getDef(); + if (!CompressOperator->isSubClassOf("RVInst16")) + PrintFatalError(Rec->getLoc(), "Compression result '" + + CompressOperator->getName() + + "' is not a 16 but width instruction!"); + CodeGenInstruction CompressInsn(CompressOperator); + matchInsDag(CompressInsn, CompressDag, false); + + unsigned NumMIOperands = 0; + for (unsigned i = 0, e = CompressInsn.Operands.size(); i != e; ++i) + NumMIOperands += CompressInsn.Operands[i].MINumOperands; + + IndexedMap CompressOperandMap; + CompressOperandMap.grow(NumMIOperands); + addDagOperandMapping(Rec, CompressDag, CompressInsn, CompressOperandMap, 0, + false); + for (unsigned i = 0, e = CompressInsn.Operands.size(); i != e; ++i) + NumMIOperands += CompressInsn.Operands[i].MINumOperands; + + IndexedMap SourceOperandMap; + NumMIOperands = 0; + for (unsigned i = 0, e = SourceInsn.Operands.size(); i != e; ++i) + NumMIOperands += SourceInsn.Operands[i].MINumOperands; + SourceOperandMap.grow(NumMIOperands); + addDagOperandMapping(Rec, InputDag, SourceInsn, SourceOperandMap, 0, true); + StringMap CompressOperands; + for (unsigned i = 0; i < CompressDag->getNumArgs(); i++) + CompressOperands[CompressDag->getArgNameStr(i)] = i; + + // Validate that each result pattern argument has a matching (by name) + // argument in the source instruction. Also check that the type of the + // arguments match. + StringMap SourceOperands; + + std::pair MatchPair; + for (unsigned i = 0; i < InputDag->getNumArgs(); ++i) { + if ("" == InputDag->getArgNameStr(i)) + continue; + + StringMap::iterator it = + SourceOperands.find(InputDag->getArgNameStr(i)); + if (it != SourceOperands.end()) { + DEBUG(dbgs() << " Operands " << i << " and " << it->getValue() + << "with token: " << InputDag->getArgNameStr(i) + << " in the source Instruction" + << " must be checked for equality\n"); + MatchPair = std::make_pair(i, it->getValue()); + bool MatchedArgs = + matchArgTypes(InputDag->getArg(it->getValue()), InputDag->getArg(i)); + if (!MatchedArgs) + PrintFatalError(Rec->getLoc(), + "Operand '" + InputDag->getArgNameStr(i) + + "' has a mismatched tied operand!\n"); + } + + it = CompressOperands.find(InputDag->getArgNameStr(i)); + if (it == CompressOperands.end()) + PrintFatalError(Rec->getLoc(), + "Operand " + InputDag->getArgNameStr(i) + + " defined in input Instruction but not used in" + " compressed instruction\n"); + SourceOperands[InputDag->getArgNameStr(i)] = i; + } + + unsigned TiedCount = 0; + DEBUG(dbgs() << " Operand mapping:\n Source Dest\n"); + for (unsigned i = 0, e = CompressInsn.Operands.size(); i != e; ++i) { + // We've already handled constant values. Just map instruction operands + // here. + if (CompressOperandMap[CompressInsn.Operands[i].MIOperandNo].Kind != + OpData::Operand) { + if (CompressInsn.Operands[i].getTiedRegister() >= 0) + TiedCount++; + continue; + } + + int NonTiedOpIdx = CompressInsn.Operands[i].getTiedRegister(); + if (NonTiedOpIdx < 0) + NonTiedOpIdx = i - TiedCount; + else + TiedCount++; + + StringMap::iterator SourceOp = + SourceOperands.find(CompressDag->getArgNameStr(NonTiedOpIdx)); + + if (SourceOp == SourceOperands.end()) + PrintFatalError(Rec->getLoc(), + "Compress output operand '" + + CompressDag->getArgNameStr(NonTiedOpIdx) + + "' has no matching source operand."); + bool MatchedArgs = matchArgTypes(CompressDag->getArg(NonTiedOpIdx), + InputDag->getArg(SourceOp->getValue())); + if (!MatchedArgs) + PrintFatalError(Rec->getLoc(), + "Type mismatch between input and " + "output operand '" + + CompressDag->getArgNameStr(NonTiedOpIdx) + "'"); + + assert(CompressDag->getArgNameStr(NonTiedOpIdx) == + InputDag->getArgNameStr(SourceOp->getValue()) && + "Incorrect operand mapping\n"); + + // Map the source operand to the destination operand index for each + // MachineInstr operand. + for (unsigned I = 0, E = CompressInsn.Operands[i].MINumOperands; I != E; + ++I) { + CompressOperandMap[CompressInsn.Operands[i].MIOperandNo + I] + .Data.Operand = SourceOp->getValue(); + + SourceOperandMap[SourceOp->getValue()].Data.Operand = + CompressInsn.Operands[i].MIOperandNo + I; + // ToDo: Check the types from the output dag is compatible with the type + // from the input dag. Need to figure out limitations to check subclasses. + // areCompatibleTypes(CompressDag->getArg([NonTiedOpIdx]),InputDag->getArg[i]) + } + DEBUG(dbgs() << " " << SourceOp->getValue() << " ====> " << i << "\n"); + } + + // Get the target features for the CompressPat. + std::vector PatReqFeatures; + std::vector RF = Rec->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(PatReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + + Expansions.push_back(CompressTransform(SourceInsn, CompressInsn, + PatReqFeatures, SourceOperandMap, + CompressOperandMap, MatchPair)); +} + +static void getReqFeatures(std::map &FeaturesMap, + std::vector &ReqFeatures) { + for (auto &R : ReqFeatures) { + StringRef AsmCondString = R->getValueAsString("AssemblerCondString"); + + // AsmCondString has syntax [!]F(,[!]F)* + SmallVector Ops; + SplitString(AsmCondString, Ops, ","); + assert(!Ops.empty() && "AssemblerCondString cannot be empty"); + + for (auto &Op : Ops) { + assert(!Op.empty() && "Empty operator"); + if (FeaturesMap.find(Op) == FeaturesMap.end()) + FeaturesMap[Op] = FeaturesMap.size(); + } + } +} + +void RISCVCompressEmitter::emitCompressEmitter(raw_ostream &o, bool Compress) { + Record *AsmWriter = Target.getAsmWriter(); + bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); + std::string Namespace = Target.getName(); + + if (Compress) + std::stable_sort( + Expansions.begin(), Expansions.end(), + [](const CompressTransform &LHS, const CompressTransform &RHS) { + return (LHS.Source.TheDef->getName().str() < + RHS.Source.TheDef->getName().str()); + }); + else + std::stable_sort( + Expansions.begin(), Expansions.end(), + [](const CompressTransform &LHS, const CompressTransform &RHS) { + return (LHS.Dest.TheDef->getName().str() < + RHS.Dest.TheDef->getName().str()); + }); + + // A list of MCOperandPredicates for all operands in use, and the reverse map + std::vector MCOpPredicates; + DenseMap MCOpPredicateMap; + + // Emit file header. + if (Compress) + emitSourceFileHeader("Compress instruction Source Fragment", o); + + if (Compress) + // TODO:: clean this up, create a helper function to get the types and + // use a switch over the MCOperandType + o << "static bool " << Namespace + << "AreEqualOperands(const MCOperand& MCOp1,const MCOperand& " + "MCOp2) {\n" + " if (MCOp1.isReg()) {\n" + " if (MCOp2.isReg()) {\n" + " if (MCOp1.getReg() == MCOp2.getReg())\n" + " return true;\n" + " }\n" + " }\n" + " return false;\n" + "}\n\n"; + + o << "static bool " << Namespace + << "ValidateMCOperand(const MCOperand &MCOp,\n" + << " const MCSubtargetInfo &STI,\n" + << " unsigned PredicateIndex);\n"; + + if (Compress) { + o << "\n#ifdef GEN_COMPRESS_INSTR\n"; + o << "#undef GEN_COMPRESS_INSTR\n\n"; + } else { + o << "\n#ifdef GEN_UNCOMPRESS_INSTR\n"; + o << "#undef GEN_UNCOMPRESS_INSTR\n\n"; + } + + if (Compress) + o << "static bool " + << "compressInst(MCInst& OutInst,\n" + << " const MCInst &MI,\n" + << (PassSubtarget ? " const MCSubtargetInfo &STI,\n" + : "") + << " MCContext &Context) {\n" + << " const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n"; + else + o << "static bool " + << "uncompressInst(MCInst& OutInst,\n" + << " const MCInst &MI,\n" + << " const MCRegisterInfo &MRI" + << (PassSubtarget ? ",\n" : ") {\n") + << (PassSubtarget ? " const MCSubtargetInfo &STI) {\n" + : ""); + + std::stringstream CaseStream; + if (!Expansions.empty()) { + std::string PrevOp(""); + std::string CurOp(""); + CaseStream << " switch (MI.getOpcode()) {\n" + << " default: return false;\n"; + + for (auto &Expansion : Expansions) { + std::stringstream CondStream; + std::stringstream CodeStream; + CodeGenInstruction *SourcePtr = &Expansion.Source; + CodeGenInstruction *DestPtr = &Expansion.Dest; + IndexedMap *SourceOperandMapPtr = &Expansion.SourceOperandMap; + IndexedMap *DestOperandMapPtr = &Expansion.DestOperandMap; + if (!Compress) { + SourcePtr = &Expansion.Dest; + DestPtr = &Expansion.Source; + SourceOperandMapPtr = &Expansion.DestOperandMap; + DestOperandMapPtr = &Expansion.SourceOperandMap; + } + + // Fill into references. + CodeGenInstruction &Source = *SourcePtr; + CodeGenInstruction &Dest = *DestPtr; + IndexedMap &SourceOperandMap = *SourceOperandMapPtr; + IndexedMap &DestOperandMap = *DestOperandMapPtr; + + CurOp = Source.TheDef->getName().str(); + // Closing brace for the previous case + // If the entry in expansions is same opcode as the one before, don't + // close and break + if (CurOp == PrevOp) { + CaseStream << " // Case continues \n"; + } else { + if (PrevOp != "") + CaseStream << " break;\n } //case" << PrevOp << "\n"; + CaseStream << " case " << Namespace << "::" << CurOp << ": {\n"; + } + + std::map FeaturesMap; + // Check CompressPat required features. + getReqFeatures(FeaturesMap, Expansion.PatReqFeatures); + + // Start Dest Inst checks + std::vector ReqFeatures; + if (PassSubtarget) { + // We only consider ReqFeatures predicates if PassSubtarget + std::vector RF = + Dest.TheDef->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + } + + // Check Dest Inst required features. + getReqFeatures(FeaturesMap, ReqFeatures); + + // Emit checks for required features. + if (PassSubtarget) + for (auto &F : FeaturesMap) { + StringRef Op = F.first; + if (Op[0] == '!') + CondStream << (" !STI.getFeatureBits()[" + Namespace + + "::" + Op.substr(1) + "]") .str() << " &&\n"; + else + CondStream << (" STI.getFeatureBits()[" + Namespace + + "::" + Op + "]") .str() << " &&\n"; + } + + // Start source Inst checks\n"; + if (Expansion.MatchPair.first != Expansion.MatchPair.second) { + CondStream << " " + << Namespace << "AreEqualOperands(MI.getOperand(" + << Expansion.MatchPair.first << ")," + << " MI.getOperand(" << Expansion.MatchPair.second + << ")) &&\n"; + } + + // Start Dest Inst checks\n"; + // Check for fixed values in the source instruction: + unsigned MIOpNo = 0; + for (const auto &SourceOperand : Source.Operands) { + for (unsigned i = 0, e = SourceOperand.MINumOperands; i != e; ++i) { + switch (SourceOperandMap[MIOpNo + i].Kind) { + case OpData::Operand: + // If this is a captured operand we don't need to do anything + // for source checks. + break; + case OpData::Imm: + // CondStream << " // Operand: " << SourceOperand.Name << "\n"; + CondStream << " (MI.getOperand(" << MIOpNo << ").getImm() == " + << SourceOperandMap[MIOpNo + i].Data.Imm << ") &&\n"; + break; + case OpData::Reg: { + Record *Reg = SourceOperandMap[MIOpNo + i].Data.Reg; + // Check that the input MI has this value for the Register Operand + // CondStream << " // Operand: " << SourceOperand.Name << "\n"; + CondStream << " (MI.getOperand(" << MIOpNo << ").getReg() == "; + // "zero_reg" is special. + if (Reg->getName() == "zero_reg") + CondStream << "0"; + else + CondStream << Namespace << "::" << Reg->getName().str(); + CondStream << ") &&\n"; + // o << " return false;\n }\n"; + break; + } + } + } + MIOpNo += SourceOperand.MINumOperands; + } + CodeStream << " // " << Dest.AsmString << "\n"; + CodeStream << " OutInst.setOpcode(" << Namespace + << "::" << Dest.TheDef->getName().str() << ");\n"; + + MIOpNo = 0; + for (const auto &DestOperand : Dest.Operands) { + CodeStream << " // Operand: " << DestOperand.Name << "\n"; + for (unsigned i = 0, e = DestOperand.MINumOperands; i != e; ++i) { + switch (DestOperandMap[MIOpNo + i].Kind) { + case OpData::Operand: { + unsigned OpIdx = + Source.Operands[DestOperandMap[MIOpNo].Data.Operand] + .MIOperandNo + + i; + // Check that the operand coming from the Source instruction fits + // the type for the destination instruction. + if (DestOperand.Rec->isSubClassOf("RegisterClass")) { + // This is a register operand. Check the register class. + CondStream << " (MRI.getRegClass(" << Namespace + << "::" << DestOperand.Rec->getName().str() + << "RegClassID).contains(" + << "MI.getOperand(" << OpIdx << ").getReg())) &&\n"; + CodeStream << " OutInst.addOperand(MI.getOperand(" << OpIdx + << "));\n"; + } else { + unsigned Entry = MCOpPredicateMap[DestOperand.Rec]; + if (!Entry) { + if (!DestOperand.Rec->isValueUnset("MCOperandPredicate")) { + MCOpPredicates.push_back(DestOperand.Rec); + Entry = MCOpPredicates.size(); + MCOpPredicateMap[DestOperand.Rec] = Entry; + } else + llvm::errs() + << "No MCOperandPredicate on this operand at all: " + << DestOperand.Rec->getName().str() << '\n'; + } + if (Entry) + CondStream << " " << Namespace << "ValidateMCOperand(" + << "MI.getOperand(" << OpIdx << "), STI, " << Entry + << ") &&\n"; + + CodeStream << " OutInst.addOperand(MI.getOperand(" << OpIdx + << "));\n"; + } + break; + } + case OpData::Imm: + CodeStream << " OutInst.addOperand(MCOperand::createImm(" + << DestOperandMap[MIOpNo + i].Data.Imm << "));\n"; + break; + case OpData::Reg: { + Record *Reg = DestOperandMap[MIOpNo + i].Data.Reg; + CodeStream << " OutInst.addOperand(MCOperand::createReg("; + // "zero_reg" is special. + if (Reg->getName() == "zero_reg") + CodeStream << "0"; + else + CodeStream << Namespace << "::" << Reg->getName().str(); + CodeStream << "));\n"; + break; + } + } + } + MIOpNo += DestOperand.MINumOperands; + } + if (Dest.Operands.isVariadic) { + llvm_unreachable("Variadic operands not handled for CompressPat!"); + } + CaseStream << (" if (\n" + + CondStream.str().substr(0, CondStream.str().length() - 4) + + ") {\n") + << CodeStream.str() << " return true;\n" + << " } // if\n"; + PrevOp = CurOp; + } + // Close the last brace for the last case + CaseStream << " } // Case" << CurOp << "\n"; + } + o << CaseStream.str() << " } // switch\n return false;\n}\n"; + + if (!MCOpPredicates.empty()) { + o << "static bool " << Namespace + << "ValidateMCOperand(const MCOperand &MCOp,\n" + << " const MCSubtargetInfo &STI,\n" + << " unsigned PredicateIndex) {\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" + << " break;\n"; + + for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { + Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); + if (CodeInit *SI = dyn_cast(MCOpPred)) { + o << " case " << i + 1 << ": {\n" + << " // " << MCOpPredicates[i]->getName().str() << SI->getValue() + << "\n" + << " }\n"; + } else + llvm_unreachable("Unexpected MCOperandPredicate field!"); + } + o << " }\n" + << "}\n\n"; + } + + if (Compress) + o << "\n#endif //GEN_COMPRESS_INSTR\n"; + else + o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; +} + +void RISCVCompressEmitter::run(raw_ostream &o) { + Record *CompressClass = Records.getClass("CompressPat"); + assert(CompressClass && "Compress class definition missing!"); + // Record *InstructionClass = Records.getClass("Instruction"); + // assert(InstructionClass && "Instruction class definition missing!"); + + std::vector Insts; + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(CompressClass)) + Insts.push_back(D.second.get()); + } + + // Process the CompressPat definitions, validating them as we do so. + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + evaluateCompressTransform(Insts[i]); + + // Generate compressed instructions. + emitCompressEmitter(o, true); + // Generate uncompressed instructions. + emitCompressEmitter(o, false); +} + +namespace llvm { + +void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS) { + RISCVCompressEmitter(RK).run(OS); +} + +} // namespace llvm Index: utils/TableGen/TableGen.cpp =================================================================== --- utils/TableGen/TableGen.cpp +++ utils/TableGen/TableGen.cpp @@ -32,6 +32,7 @@ GenAsmMatcher, GenDisassembler, GenPseudoLowering, + GenCompressInst, GenCallingConv, GenDAGISel, GenDFAPacketizer, @@ -72,6 +73,8 @@ "Generate disassembler"), clEnumValN(GenPseudoLowering, "gen-pseudo-lowering", "Generate pseudo instruction lowering"), + clEnumValN(GenCompressInst, "gen-compress-emitter", + "Generate RISCV compressed instructions."), clEnumValN(GenAsmMatcher, "gen-asm-matcher", "Generate assembly instruction matcher"), clEnumValN(GenDAGISel, "gen-dag-isel", @@ -144,6 +147,9 @@ case GenPseudoLowering: EmitPseudoLowering(Records, OS); break; + case GenCompressInst: + EmitCompressInst(Records, OS); + break; case GenDAGISel: EmitDAGISel(Records, OS); break; Index: utils/TableGen/TableGenBackends.h =================================================================== --- utils/TableGen/TableGenBackends.h +++ utils/TableGen/TableGenBackends.h @@ -74,6 +74,7 @@ void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS); void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS); void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS); +void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS); void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS); void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);