[RISCV] Implement assembler pseudo instructions for RV32I and RV64I
Adds the assembler pseudo instructions of RV32I and RV64I which can
be mapped to a single canonical instruction. The missing pseudo
instructions (e.g., call, tail, ...) are marked as TODO. Other
things, like for example PCREL_LO, have to be implemented first.
Currently, alias emission is disabled by default to keep the patch
minimal. Alias emission by default will be enabled in a subsequent
patch which also updates all affected tests. Note that this patch
should actually break the floating point MC tests. However, the
used FileCheck configuration is not tight enought to detect the
breakage.
Differential Revision: https://reviews.llvm.org/D40902
Patch by Mario Werner.
llvm-svn: 320487
diff --git a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
index a396025..d21c48e 100644
--- a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
+++ b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
@@ -18,6 +18,7 @@
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
@@ -28,9 +29,17 @@
#define PRINT_ALIAS_INSTR
#include "RISCVGenAsmWriter.inc"
+// Alias instruction emission is disabled by default. A subsequent patch will
+// change this default and fix all affected tests.
+static cl::opt<bool>
+NoAliases("riscv-no-aliases",
+ cl::desc("Disable the emission of assembler pseudo instructions"),
+ cl::init(true),
+ cl::Hidden);
+
void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot, const MCSubtargetInfo &STI) {
- if (!printAliasInstr(MI, O))
+ if (NoAliases || !printAliasInstr(MI, O))
printInstruction(MI, O);
printAnnotation(O, Annot);
}
diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td
index be33977..c74d560b 100644
--- a/llvm/lib/Target/RISCV/RISCV.td
+++ b/llvm/lib/Target/RISCV/RISCV.td
@@ -49,6 +49,8 @@
: SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">;
def IsRV64 : Predicate<"Subtarget->is64Bit()">,
AssemblerPredicate<"Feature64Bit">;
+def IsRV32 : Predicate<"!Subtarget->is64Bit()">,
+ AssemblerPredicate<"!Feature64Bit">;
def RV64 : HwMode<"+64bit">;
def RV32 : HwMode<"-64bit">;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index dcfcccf..b445002 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -376,6 +376,90 @@
}
//===----------------------------------------------------------------------===//
+// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
+//===----------------------------------------------------------------------===//
+
+// TODO la
+// TODO lb lh lw
+// TODO RV64I: ld
+// TODO sb sh sw
+// TODO RV64I: sd
+
+def : InstAlias<"nop", (ADDI X0, X0, 0)>;
+// TODO li
+def : InstAlias<"mv $rd, $rs", (ADDI GPR:$rd, GPR:$rs, 0)>;
+def : InstAlias<"not $rd, $rs", (XORI GPR:$rd, GPR:$rs, -1)>;
+def : InstAlias<"neg $rd, $rs", (SUB GPR:$rd, X0, GPR:$rs)>;
+
+let Predicates = [IsRV64] in {
+def : InstAlias<"negw $rd, $rs", (SUBW GPR:$rd, X0, GPR:$rs)>;
+def : InstAlias<"sext.w $rd, $rs", (ADDIW GPR:$rd, GPR:$rs, 0)>;
+} // Predicates = [IsRV64]
+
+def : InstAlias<"seqz $rd, $rs", (SLTIU GPR:$rd, GPR:$rs, 1)>;
+def : InstAlias<"snez $rd, $rs", (SLTU GPR:$rd, X0, GPR:$rs)>;
+def : InstAlias<"sltz $rd, $rs", (SLT GPR:$rd, GPR:$rs, X0)>;
+def : InstAlias<"sgtz $rd, $rs", (SLT GPR:$rd, X0, GPR:$rs)>;
+
+def : InstAlias<"beqz $rs, $offset",
+ (BEQ GPR:$rs, X0, simm13_lsb0:$offset)>;
+def : InstAlias<"bnez $rs, $offset",
+ (BNE GPR:$rs, X0, simm13_lsb0:$offset)>;
+def : InstAlias<"blez $rs, $offset",
+ (BGE X0, GPR:$rs, simm13_lsb0:$offset)>;
+def : InstAlias<"bgez $rs, $offset",
+ (BGE GPR:$rs, X0, simm13_lsb0:$offset)>;
+def : InstAlias<"bltz $rs, $offset",
+ (BLT GPR:$rs, X0, simm13_lsb0:$offset)>;
+def : InstAlias<"bgtz $rs, $offset",
+ (BLT X0, GPR:$rs, simm13_lsb0:$offset)>;
+
+// Always output the canonical mnemonic for the pseudo branch instructions.
+// The GNU tools emit the canonical mnemonic for the branch pseudo instructions
+// as well (e.g. "bgt" will be recognised by the assembler but never printed by
+// objdump). Match this behaviour by setting a zero weight.
+def : InstAlias<"bgt $rs, $rt, $offset",
+ (BLT GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
+def : InstAlias<"ble $rs, $rt, $offset",
+ (BGE GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
+def : InstAlias<"bgtu $rs, $rt, $offset",
+ (BLTU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
+def : InstAlias<"bleu $rs, $rt, $offset",
+ (BGEU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
+
+// "ret" has more weight since "ret" and "jr" alias the same "jalr" instruction.
+def : InstAlias<"j $offset", (JAL X0, simm21_lsb0:$offset)>;
+def : InstAlias<"jal $offset", (JAL X1, simm21_lsb0:$offset)>;
+def : InstAlias<"jr $rs", (JALR X0, GPR:$rs, 0)>;
+def : InstAlias<"jalr $rs", (JALR X1, GPR:$rs, 0)>;
+def : InstAlias<"ret", (JALR X0, X1, 0), 2>;
+// TODO call
+// TODO tail
+
+def : InstAlias<"fence", (FENCE 0xF, 0xF)>; // 0xF == iorw
+
+// CSR Addresses: 0xC00 == cycle, 0xC01 == time, 0xC02 == instret
+// 0xC80 == cycleh, 0xC81 == timeh, 0xC82 == instreth
+def : InstAlias<"rdinstret $rd", (CSRRS GPR:$rd, 0xC02, X0)>;
+def : InstAlias<"rdcycle $rd", (CSRRS GPR:$rd, 0xC00, X0)>;
+def : InstAlias<"rdtime $rd", (CSRRS GPR:$rd, 0xC01, X0)>;
+
+let Predicates = [IsRV32] in {
+def : InstAlias<"rdinstreth $rd", (CSRRS GPR:$rd, 0xC82, X0)>;
+def : InstAlias<"rdcycleh $rd", (CSRRS GPR:$rd, 0xC80, X0)>;
+def : InstAlias<"rdtimeh $rd", (CSRRS GPR:$rd, 0xC81, X0)>;
+} // Predicates = [IsRV32]
+
+def : InstAlias<"csrr $rd, $csr", (CSRRS GPR:$rd, uimm12:$csr, X0)>;
+def : InstAlias<"csrw $csr, $rs", (CSRRW X0, uimm12:$csr, GPR:$rs)>;
+def : InstAlias<"csrs $csr, $rs", (CSRRS X0, uimm12:$csr, GPR:$rs)>;
+def : InstAlias<"csrc $csr, $rs", (CSRRC X0, uimm12:$csr, GPR:$rs)>;
+
+def : InstAlias<"csrwi $csr, $imm", (CSRRWI X0, uimm12:$csr, uimm5:$imm)>;
+def : InstAlias<"csrsi $csr, $imm", (CSRRSI X0, uimm12:$csr, uimm5:$imm)>;
+def : InstAlias<"csrci $csr, $imm", (CSRRCI X0, uimm12:$csr, uimm5:$imm)>;
+
+//===----------------------------------------------------------------------===//
// Pseudo-instructions and codegen patterns
//
// Naming convention: For 'generic' pattern classes, we use the naming