Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -15,6 +15,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" @@ -22,8 +23,11 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" +#include + using namespace llvm; namespace { @@ -51,6 +55,9 @@ bool ParseDirective(AsmToken DirectiveID) override; + bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + // Auto-generated instruction matching functions #define GET_ASSEMBLER_HEADER #include "RISCVGenAsmMatcher.inc" @@ -206,6 +213,16 @@ return RISCVFPRndMode::stringToRoundingMode(Str) != RISCVFPRndMode::Invalid; } + bool isSImmXLen() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + if (!isImm()) + return false; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + bool IsInRange = isRV64() ? true : isInt<32>(Imm); + return IsConstantImm && IsInRange && VK == RISCVMCExpr::VK_RISCV_None; + } + bool isUImmLog2XLen() const { int64_t Imm; RISCVMCExpr::VariantKind VK; @@ -581,9 +598,7 @@ default: break; case Match_Success: - Inst.setLoc(IDLoc); - Out.EmitInstruction(Inst, getSTI()); - return false; + return processInstruction(Inst, IDLoc, Out, STI); case Match_MissingFeature: return Error(IDLoc, "instruction use requires an option to be enabled"); case Match_MnemonicFail: @@ -600,6 +615,11 @@ } return Error(ErrorLoc, "invalid operand for instruction"); } + case Match_InvalidSImmXLen: + assert(!isRV64() && "immediate can not be out of range on RV64"); + return generateImmOutOfRangeError(Operands, ErrorInfo, + std::numeric_limits::min(), + std::numeric_limits::max()); case Match_InvalidUImmLog2XLen: if (isRV64()) return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1); @@ -938,6 +958,54 @@ return Kind != RISCVMCExpr::VK_RISCV_Invalid; } +bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI) { + Inst.setLoc(IDLoc); + + switch (Inst.getOpcode()) { + case RISCV::PseudoLI: { + const MCOperand &DstRegOp = Inst.getOperand(0); + const MCOperand &ImmOp = Inst.getOperand(1); + assert(DstRegOp.isReg() && "expected register operand kind"); + assert(ImmOp.isImm() && "expected immediate operand kind"); + + if (!isInt<32>(ImmOp.getImm())) + return Error(IDLoc, "TODO: li for immediates with more than 32 bits is " + "currently not implemented"); + + // Note that ADDI, which is used for generating the low part, performs a + // sign extended addition. + int64_t high = ((ImmOp.getImm() + 0x800) >> 12) & 0xFFFFF; + int64_t low = SignExtend64<12>(ImmOp.getImm() & 0xFFF); + if (high && low) { + Out.EmitInstruction( + MCInstBuilder(RISCV::LUI).addOperand(DstRegOp).addImm(high), + getSTI()); + Out.EmitInstruction(MCInstBuilder(RISCV::ADDI) + .addOperand(DstRegOp) + .addOperand(DstRegOp) + .addImm(low), + getSTI()); + } else if (high) { + Out.EmitInstruction( + MCInstBuilder(RISCV::LUI).addOperand(DstRegOp).addImm(high), + getSTI()); + } else { + Out.EmitInstruction(MCInstBuilder(RISCV::ADDI) + .addOperand(DstRegOp) + .addReg(RISCV::X0) + .addImm(low), + getSTI()); + } + return false; + } + } + + Out.EmitInstruction(Inst, getSTI()); + return false; +} + bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } extern "C" void LLVMInitializeRISCVAsmParser() { Index: lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- lib/Target/RISCV/RISCVInstrFormats.td +++ lib/Target/RISCV/RISCVInstrFormats.td @@ -102,10 +102,11 @@ } // Pseudo instructions -class Pseudo pattern> - : RVInst { +class Pseudo pattern, string opcodestr = ""> + : RVInst { let isPseudo = 1; - let isCodeGenOnly = 1; + let isCodeGenOnly = !eq(opcodestr,""); + let isAsmParserOnly = !eq(opcodestr,""); } // Instruction formats are listed in the order they appear in the RISC-V Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -43,6 +43,12 @@ // Operand and SDNode transformation definitions. //===----------------------------------------------------------------------===// +class ImmXLenAsmOperand : AsmOperandClass { + let Name = prefix # "ImmXLen" # suffix; + let RenderMethod = "addImmOperands"; + let DiagnosticType = !strconcat("Invalid", Name); +} + class ImmAsmOperand : AsmOperandClass { let Name = prefix # "Imm" # width # suffix; let RenderMethod = "addImmOperands"; @@ -122,7 +128,9 @@ } // A parameterized register class alternative to i32imm/i64imm from Target.td. -def ixlenimm : Operand; +def ixlenimm : Operand { + let ParserMatchClass = ImmXLenAsmOperand<"S">; +} // Standalone (codegen-only) immleaf patterns. def simm32 : ImmLeaf(Imm);}]>; @@ -386,7 +394,10 @@ // TODO RV64I: sd def : InstAlias<"nop", (ADDI X0, X0, 0)>; -// TODO li + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def PseudoLI : Pseudo<(outs GPR:$rd), (ins ixlenimm:$imm), [], "li $rd, $imm">; + 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)>; Index: test/MC/RISCV/rv32i-aliases-invalid.s =================================================================== --- test/MC/RISCV/rv32i-aliases-invalid.s +++ test/MC/RISCV/rv32i-aliases-invalid.s @@ -4,5 +4,7 @@ # TODO ld # TODO sd +li x0, 0x100000000 # CHECK: :[[@LINE]]:8: error: immediate must be an integer in the range [-2147483648, 2147483647] + negw x1, x2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled sext.w x3, x4 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled Index: test/MC/RISCV/rv64i-aliases-invalid.s =================================================================== --- test/MC/RISCV/rv64i-aliases-invalid.s +++ test/MC/RISCV/rv64i-aliases-invalid.s @@ -1,6 +1,8 @@ # RUN: not llvm-mc %s -triple=riscv64 -riscv-no-aliases 2>&1 | FileCheck %s # RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s +li x0, 0x100000000 # CHECK: :[[@LINE]]:1: error: TODO: li for immediates with more than 32 bits is currently not implemented + rdinstreth x29 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled rdcycleh x27 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled rdtimeh x28 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled Index: test/MC/RISCV/rvi-aliases-valid.s =================================================================== --- test/MC/RISCV/rvi-aliases-valid.s +++ test/MC/RISCV/rvi-aliases-valid.s @@ -1,23 +1,23 @@ # RUN: llvm-mc %s -triple=riscv32 -riscv-no-aliases \ -# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s # RUN: llvm-mc %s -triple=riscv32 \ -# RUN: | FileCheck -check-prefix=CHECK-ALIAS %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s # RUN: llvm-mc %s -triple=riscv64 -riscv-no-aliases\ -# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s # RUN: llvm-mc %s -triple=riscv64 \ -# RUN: | FileCheck -check-prefix=CHECK-ALIAS %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s # RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ # RUN: | llvm-objdump -d -riscv-no-aliases - \ -# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s # RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ # RUN: | llvm-objdump -d - \ -# RUN: | FileCheck -check-prefix=CHECK-ALIAS %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s # RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ # RUN: | llvm-objdump -d -riscv-no-aliases - \ -# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s # RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ # RUN: | llvm-objdump -d - \ -# RUN: | FileCheck -check-prefix=CHECK-ALIAS %s +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s # TODO la # TODO lb lh lw @@ -26,7 +26,27 @@ # CHECK-INST: addi zero, zero, 0 # CHECK-ALIAS: nop nop -# TODO li + +# CHECK-INST: addi a0, zero, 0 +# CHECK-ALIAS: mv a0, zero +li x10, 0 +# CHECK: addi a0, zero, 2047 +li x10, 2047 +# CHECK: lui a1, 1 +# CHECK: addi a1, a1, -2048 +li x11, 2048 +# CHECK: lui a1, 1 +# CHECK: addi a1, a1, -1 +li x11, 4095 +# CHECK: lui a2, 1 +li x12, 4096 +# CHECK: lui a2, 1 +# CHECK: addi a2, a2, 1 +li x12, 4097 +# CHECK: lui a2, 524288 +# CHECK: addi a2, a2, -1 +li x12, 2147483647 + # CHECK-INST: addi t6, zero, 0 # CHECK-ALIAS: mv t6, zero mv x31, zero