]> granicus.if.org Git - llvm/commitdiff
[RISCV] Lower inline asm constraints I, J & K for RISC-V
authorLewis Revill <lewis.revill@embecosm.com>
Tue, 11 Jun 2019 12:42:13 +0000 (12:42 +0000)
committerLewis Revill <lewis.revill@embecosm.com>
Tue, 11 Jun 2019 12:42:13 +0000 (12:42 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363054 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/RISCV/RISCVISelLowering.cpp
lib/Target/RISCV/RISCVISelLowering.h
test/CodeGen/RISCV/inline-asm.ll

index 2da0e319dddf91d8583366280ff6065def7ae1d2..eef7af53faef7183e7e2a7bbc2708ca17aa8ef47 100644 (file)
@@ -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<SDValue> &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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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 8e756a1c522b6e2a0c3772b9c09c5f6baca04d75..f3bf4410686eab26e909ac2060caa76e45559f09 100644 (file)
@@ -93,6 +93,10 @@ public:
   getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
                                StringRef Constraint, MVT VT) const override;
 
+  void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint,
+                                    std::vector<SDValue> &Ops,
+                                    SelectionDAG &DAG) const override;
+
   MachineBasicBlock *
   EmitInstrWithCustomInserter(MachineInstr &MI,
                               MachineBasicBlock *BB) const override;
index 5096d45e3ca08eb2671f16d360af6e0df583df6a..58fabf868f8cc319bedd2f176ff07b1a8bb0346a 100644 (file)
@@ -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