[LoongArch] AsmParser support for the li.[wd] pseudo instructions
authorwanglei <wanglei@loongson.cn>
Mon, 21 Nov 2022 07:36:28 +0000 (15:36 +0800)
committerwanglei <wanglei@loongson.cn>
Mon, 21 Nov 2022 08:33:47 +0000 (16:33 +0800)
The `li.[wd]` pseudo instructions are used to load an immediate value
into a GPR. These expand directly during asm parsing. As the result,
only real MC instructions are emitted to the MCStreamer. The actual
expansion to real instructions is similar to the expansion performed by
the GAS.

Note: The `li.w` always treats the imm operand as a 32-bit signed value.

Reviewed By: SixWeining

Differential Revision: https://reviews.llvm.org/D138086

llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
llvm/test/MC/LoongArch/Macros/macros-li-bad.s [new file with mode: 0644]
llvm/test/MC/LoongArch/Macros/macros-li.s [new file with mode: 0644]

index b33be3e..43941fb 100644 (file)
@@ -9,6 +9,7 @@
 #include "MCTargetDesc/LoongArchInstPrinter.h"
 #include "MCTargetDesc/LoongArchMCExpr.h"
 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
+#include "MCTargetDesc/LoongArchMatInt.h"
 #include "TargetInfo/LoongArchTargetInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstBuilder.h"
@@ -117,6 +118,9 @@ class LoongArchAsmParser : public MCTargetAsmParser {
   // Helper to emit pseudo instruction "la.tls.gd $rd, $rj, sym".
   void emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
 
+  // Helper to emit pseudo instruction "li.w/d $rd, $imm".
+  void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
+
 public:
   enum LoongArchMatchResultTy {
     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
@@ -409,6 +413,8 @@ public:
                      IsValidKind;
   }
 
+  bool isImm32() const { return isSImm<32>() || isUImm<32>(); }
+
   /// Gets location of the first token of this operand.
   SMLoc getStartLoc() const override { return StartLoc; }
   /// Gets location of the last token of this operand.
@@ -1059,6 +1065,28 @@ void LoongArchAsmParser::emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc,
   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
 }
 
+void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc,
+                                     MCStreamer &Out) {
+  MCRegister DestReg = Inst.getOperand(0).getReg();
+  int64_t Imm = Inst.getOperand(1).getImm();
+  MCRegister SrcReg = LoongArch::R0;
+
+  if (Inst.getOpcode() == LoongArch::PseudoLI_W)
+    Imm = SignExtend64<32>(Imm);
+
+  for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
+    unsigned Opc = Inst.Opc;
+    if (Opc == LoongArch::LU12I_W)
+      Out.emitInstruction(MCInstBuilder(Opc).addReg(DestReg).addImm(Inst.Imm),
+                          getSTI());
+    else
+      Out.emitInstruction(
+          MCInstBuilder(Opc).addReg(DestReg).addReg(SrcReg).addImm(Inst.Imm),
+          getSTI());
+    SrcReg = DestReg;
+  }
+}
+
 bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
                                             OperandVector &Operands,
                                             MCStreamer &Out) {
@@ -1103,6 +1131,10 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
   case LoongArch::PseudoLA_TLS_GD_LARGE:
     emitLoadAddressTLSGDLarge(Inst, IDLoc, Out);
     return false;
+  case LoongArch::PseudoLI_W:
+  case LoongArch::PseudoLI_D:
+    emitLoadImm(Inst, IDLoc, Out);
+    return false;
   }
   Out.emitInstruction(Inst, getSTI());
   return false;
@@ -1342,6 +1374,10 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
         Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
         "operand must be a bare symbol name or an immediate must be a multiple "
         "of 4 in the range");
+  case Match_InvalidImm32: {
+    SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
+    return Error(ErrorLoc, "operand must be a 32 bit immediate");
+  }
   case Match_InvalidBareSymbol: {
     SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
     return Error(ErrorLoc, "operand must be a bare symbol name");
index 71bf6b5..e2bb260 100644 (file)
@@ -101,6 +101,9 @@ class UImmAsmOperand<int width, string suffix = "">
 
 // A parameterized register class alternative to i32imm/i64imm from Target.td.
 def grlenimm : Operand<GRLenVT>;
+def imm32 : Operand<GRLenVT> {
+  let ParserMatchClass = ImmAsmOperand<"", 32, "">;
+}
 
 def uimm2 : Operand<GRLenVT> {
   let ParserMatchClass = UImmAsmOperand<2>;
@@ -1492,6 +1495,15 @@ def : InstAlias<"blez $rj, $imm16",
 def : InstAlias<"bgez $rd, $imm16",
                 (BGE GPR:$rd, R0, simm16_lsl2_br:$imm16), 0>;
 
+// Load immediate.
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0,
+    isAsmParserOnly = 1 in {
+def PseudoLI_W : Pseudo<(outs GPR:$rd), (ins imm32:$imm), [],
+                        "li.w", "$rd, $imm">;
+def PseudoLI_D : Pseudo<(outs GPR:$rd), (ins grlenimm:$imm), [],
+                        "li.d", "$rd, $imm">, Requires<[IsLA64]>;
+}
+
 //===----------------------------------------------------------------------===//
 // Basic Floating-Point Instructions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/test/MC/LoongArch/Macros/macros-li-bad.s b/llvm/test/MC/LoongArch/Macros/macros-li-bad.s
new file mode 100644 (file)
index 0000000..194b86b
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: not llvm-mc --triple=loongarch64 %s 2>&1 | FileCheck %s
+
+li.w $a0, 0x100000000
+# CHECK: :[[#@LINE-1]]:11: error: operand must be a 32 bit immediate
+
+li.d $a0, 0x10000000000000000
+# CHECK: :[[#@LINE-1]]:11: error: unknown operand
diff --git a/llvm/test/MC/LoongArch/Macros/macros-li.s b/llvm/test/MC/LoongArch/Macros/macros-li.s
new file mode 100644 (file)
index 0000000..994aa43
--- /dev/null
@@ -0,0 +1,90 @@
+# RUN: llvm-mc --triple=loongarch64 %s | FileCheck %s
+
+li.w $a0, 0x0
+# CHECK:      ori $a0, $zero, 0
+li.d $a0, 0x0
+# CHECK-NEXT: ori $a0, $zero, 0
+
+li.w $a0, 0xfff
+# CHECK:      ori $a0, $zero, 4095
+li.d $a0, 0xfff
+# CHECK-NEXT: ori $a0, $zero, 4095
+
+li.w $a0, 0x7ffff000
+# CHECK:      lu12i.w $a0, 524287
+li.d $a0, 0x7ffff000
+# CHECK-NEXT:  lu12i.w $a0, 524287
+
+li.w $a0, 0x80000000
+# CHECK:      lu12i.w $a0, -524288
+li.d $a0, 0x80000000
+# CHECK-NEXT: lu12i.w $a0, -524288
+# CHECK-NEXT: lu32i.d $a0, 0
+
+li.w $a0, 0xfffff800
+# CHECK:      addi.w $a0, $zero, -2048
+li.d $a0, 0xfffff800
+# CHECK-NEXT: addi.w $a0, $zero, -2048
+# CHECK-NEXT: lu32i.d $a0, 0
+
+li.w $a0, 0xfffffffffffff800
+# CHECK:      addi.w $a0, $zero, -2048
+li.d $a0, 0xfffffffffffff800
+# CHECK-NEXT: addi.w $a0, $zero, -2048
+
+li.w $a0, 0xffffffff80000800
+# CHECK:      lu12i.w $a0, -524288
+# CHECK-NEXT: ori $a0, $a0, 2048
+li.d $a0, 0xffffffff80000800
+# CHECK-NEXT: lu12i.w $a0, -524288
+# CHECK-NEXT: ori $a0, $a0, 2048
+
+li.d $a0, 0x7ffff00000800
+# CHECK:      ori $a0, $zero, 2048
+# CHECK-NEXT: lu32i.d $a0, 524287
+
+li.d $a0, 0x8000000000fff
+# CHECK:      ori $a0, $zero, 4095
+# CHECK-NEXT: lu32i.d $a0, -524288
+# CHECK-NEXT: lu52i.d $a0, $a0, 0
+
+li.d $a0, 0x8000080000800
+# CHECK:      lu12i.w $a0, -524288
+# CHECK-NEXT: ori $a0, $a0, 2048
+# CHECK-NEXT: lu32i.d $a0, -524288
+# CHECK-NEXT: lu52i.d $a0, $a0, 0
+
+li.d $a0, 0x80000fffff800
+# CHECK:      addi.w $a0, $zero, -2048
+# CHECK-NEXT: lu32i.d $a0, -524288
+# CHECK-NEXT: lu52i.d $a0, $a0, 0
+
+li.d $a0, 0xffffffffff000
+# CHECK:      lu12i.w $a0, -1
+# CHECK-NEXT: lu52i.d $a0, $a0, 0
+
+li.d $a0, 0xffffffffff800
+# CHECK:      addi.w $a0, $zero, -2048
+# CHECK-NEXT: lu52i.d $a0, $a0, 0
+
+li.d $a0, 0x7ff0000000000000
+# CHECK:      lu52i.d $a0, $zero, 2047
+
+li.d $a0, 0x7ff0000080000000
+# CHECK:      lu12i.w $a0, -524288
+# CHECK-NEXT: lu32i.d $a0, 0
+# CHECK-NEXT: lu52i.d $a0, $a0, 2047
+
+li.d $a0, 0x7fffffff800007ff
+# CHECK:      lu12i.w $a0, -524288
+# CHECK-NEXT: ori $a0, $a0, 2047
+# CHECK-NEXT: lu52i.d $a0, $a0, 2047
+
+li.d $a0, 0xfff0000000000fff
+# CHECK:      ori $a0, $zero, 4095
+# CHECK-NEXT: lu52i.d $a0, $a0, -1
+
+li.d $a0, 0xffffffff7ffff800
+# CHECK:      lu12i.w $a0, 524287
+# CHECK-NEXT: ori $a0, $a0, 2048
+# CHECK-NEXT: lu32i.d $a0, -1