From 28a5cadb3ae0dfed9530dcbee8a0ec154f3f9f91 Mon Sep 17 00:00:00 2001 From: Lewis Revill Date: Tue, 11 Jun 2019 12:42:13 +0000 Subject: [PATCH] [RISCV] Lower inline asm constraints I, J & K for RISC-V This validates and lowers arguments to inline asm nodes which have the constraints I, J & K, with the following semantics (equivalent to GCC): I: Any 12-bit signed immediate. J: Immediate integer zero only. K: Any 5-bit unsigned immediate. Differential Revision: https://reviews.llvm.org/D54093 llvm-svn: 363054 --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 38 ++++++++++++ llvm/lib/Target/RISCV/RISCVISelLowering.h | 4 ++ llvm/test/CodeGen/RISCV/inline-asm.ll | 68 +++++++++++++++++++++ 3 files changed, 110 insertions(+) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 2da0e319dddf..eef7af53faef 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2151,6 +2151,44 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, 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 { diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 8e756a1c522b..f3bf4410686e 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -93,6 +93,10 @@ public: 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; diff --git a/llvm/test/CodeGen/RISCV/inline-asm.ll b/llvm/test/CodeGen/RISCV/inline-asm.ll index 5096d45e3ca0..58fabf868f8c 100644 --- a/llvm/test/CodeGen/RISCV/inline-asm.ll +++ b/llvm/test/CodeGen/RISCV/inline-asm.ll @@ -82,4 +82,72 @@ define i32 @constraint_m2(i32* %a) nounwind { 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