#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"
// 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,
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.
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) {
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;
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");
// 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>;
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
//===----------------------------------------------------------------------===//
--- /dev/null
+# 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