Index: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h +++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h @@ -93,6 +93,10 @@ getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; + void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, + std::vector &Ops, + SelectionDAG &DAG) const override; + MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const override; Index: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2151,6 +2151,44 @@ return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); } +void RISCVTargetLowering::LowerAsmOperandForConstraint( + SDValue Op, std::string &Constraint, std::vector &Ops, + SelectionDAG &DAG) const { + // Currently only support length 1 constraints. + if (Constraint.length() == 1) { + switch (Constraint[0]) { + case 'I': + // Validate & create a 12-bit signed immediate operand. + if (auto *C = dyn_cast(Op)) { + uint64_t CVal = C->getSExtValue(); + if (isInt<12>(CVal)) + Ops.push_back( + DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT())); + } + return; + case 'J': + // Validate & create an integer zero operand. + if (auto *C = dyn_cast(Op)) + if (C->getZExtValue() == 0) + Ops.push_back( + DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getXLenVT())); + return; + case 'K': + // Validate & create a 5-bit unsigned immediate operand. + if (auto *C = dyn_cast(Op)) { + uint64_t CVal = C->getZExtValue(); + if (isUInt<5>(CVal)) + Ops.push_back( + DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT())); + } + return; + default: + break; + } + } + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + Instruction *RISCVTargetLowering::emitLeadingFence(IRBuilder<> &Builder, Instruction *Inst, AtomicOrdering Ord) const { Index: llvm/trunk/test/CodeGen/RISCV/inline-asm.ll =================================================================== --- llvm/trunk/test/CodeGen/RISCV/inline-asm.ll +++ llvm/trunk/test/CodeGen/RISCV/inline-asm.ll @@ -82,4 +82,72 @@ ret i32 %1 } +define void @constraint_I() { +; RV32I-LABEL: constraint_I: +; RV32I: # %bb.0: +; RV32I-NEXT: #APP +; RV32I-NEXT: addi a0, a0, 2047 +; RV32I-NEXT: #NO_APP +; RV32I-NEXT: #APP +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: #NO_APP +; RV32I-NEXT: ret +; +; RV64I-LABEL: constraint_I: +; RV64I: # %bb.0: +; RV64I-NEXT: #APP +; RV64I-NEXT: addi a0, a0, 2047 +; RV64I-NEXT: #NO_APP +; RV64I-NEXT: #APP +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: #NO_APP +; RV64I-NEXT: ret + tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2047) + tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2048) + ret void +} + +define void @constraint_J() { +; RV32I-LABEL: constraint_J: +; RV32I: # %bb.0: +; RV32I-NEXT: #APP +; RV32I-NEXT: addi a0, a0, 0 +; RV32I-NEXT: #NO_APP +; RV32I-NEXT: ret +; +; RV64I-LABEL: constraint_J: +; RV64I: # %bb.0: +; RV64I-NEXT: #APP +; RV64I-NEXT: addi a0, a0, 0 +; RV64I-NEXT: #NO_APP +; RV64I-NEXT: ret + tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 0) + ret void +} + +define void @constraint_K() { +; RV32I-LABEL: constraint_K: +; RV32I: # %bb.0: +; RV32I-NEXT: #APP +; RV32I-NEXT: csrwi mstatus, 31 +; RV32I-NEXT: #NO_APP +; RV32I-NEXT: #APP +; RV32I-NEXT: csrwi mstatus, 0 +; RV32I-NEXT: #NO_APP +; RV32I-NEXT: ret +; +; RV64I-LABEL: constraint_K: +; RV64I: # %bb.0: +; RV64I-NEXT: #APP +; RV64I-NEXT: csrwi mstatus, 31 +; RV64I-NEXT: #NO_APP +; RV64I-NEXT: #APP +; RV64I-NEXT: csrwi mstatus, 0 +; RV64I-NEXT: #NO_APP +; RV64I-NEXT: ret + tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 31) + tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 0) + ret void +} + ; TODO: expend tests for more complex constraints, out of range immediates etc