[llvm] 91063cf - [GlobalISel][InlineAsm] Add support for basic input operand constraints

Konstantin Schwarz via llvm-commits llvm-commits at lists.llvm.org
Thu May 14 01:43:49 PDT 2020


Author: Konstantin Schwarz
Date: 2020-05-14T10:43:37+02:00
New Revision: 91063cf85a4038537731f582a27936187fb0759c

URL: https://github.com/llvm/llvm-project/commit/91063cf85a4038537731f582a27936187fb0759c
DIFF: https://github.com/llvm/llvm-project/commit/91063cf85a4038537731f582a27936187fb0759c.diff

LOG: [GlobalISel][InlineAsm] Add support for basic input operand constraints

Reviewers: arsenm, dsanders, aemerson, volkan, t.p.northover, paquette

Reviewed By: arsenm

Subscribers: gargaroff, wdng, rovka, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D78319

Added: 
    

Modified: 
    llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h
    llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
    llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h b/llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h
index 689b6dcc938c..ac6184877b93 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h
@@ -20,6 +20,7 @@
 namespace llvm {
 class CallBase;
 class MachineIRBuilder;
+class MachineOperand;
 class Register;
 class TargetLowering;
 class Value;
@@ -30,10 +31,23 @@ class InlineAsmLowering {
   virtual void anchor();
 
 public:
+  /// Lower the given inline asm call instruction
+  /// \p GetOrCreateVRegs is a callback to materialize a register for the
+  /// input and output operands of the inline asm
+  /// \return True if the lowering succeeds, false otherwise.
   bool lowerInlineAsm(MachineIRBuilder &MIRBuilder, const CallBase &CB,
                       std::function<ArrayRef<Register>(const Value &Val)>
                           GetOrCreateVRegs) const;
 
+  /// Lower the specified operand into the Ops vector.
+  /// \p Val is the IR input value to be lowered
+  /// \p Constraint is the user supplied constraint string
+  /// \p Ops is the vector to be filled with the lowered operands
+  /// \return True if the lowering succeeds, false otherwise.
+  virtual bool lowerAsmOperandForConstraint(Value *Val, StringRef Constraint,
+                                            std::vector<MachineOperand> &Ops,
+                                            MachineIRBuilder &MIRBuilder) const;
+
 protected:
   /// Getter for generic TargetLowering class.
   const TargetLowering *getTLI() const { return TLI; }

diff  --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index 41615e0697bd..e9ceaee83c39 100644
--- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -252,6 +252,7 @@ bool InlineAsmLowering::lowerInlineAsm(
       TLI->ParseConstraints(DL, TRI, Call);
 
   ExtraFlags ExtraInfo(Call);
+  unsigned ArgNo = 0; // ArgNo - The argument of the CallInst.
   unsigned ResNo = 0; // ResNo - The result number of the next output.
   for (auto &T : TargetConstraints) {
     ConstraintOperands.push_back(GISelAsmOperandInfo(T));
@@ -261,9 +262,32 @@ bool InlineAsmLowering::lowerInlineAsm(
     if (OpInfo.Type == InlineAsm::isInput ||
         (OpInfo.Type == InlineAsm::isOutput && OpInfo.isIndirect)) {
 
-      LLVM_DEBUG(dbgs() << "Input operands and indirect output operands are "
-                           "not supported yet\n");
-      return false;
+      OpInfo.CallOperandVal = const_cast<Value *>(Call.getArgOperand(ArgNo++));
+
+      if (const auto *BB = dyn_cast<BasicBlock>(OpInfo.CallOperandVal)) {
+        LLVM_DEBUG(dbgs() << "Basic block input operands not supported yet\n");
+        return false;
+      }
+
+      Type *OpTy = OpInfo.CallOperandVal->getType();
+
+      // If this is an indirect operand, the operand is a pointer to the
+      // accessed type.
+      if (OpInfo.isIndirect) {
+        PointerType *PtrTy = dyn_cast<PointerType>(OpTy);
+        if (!PtrTy)
+          report_fatal_error("Indirect operand for inline asm not a pointer!");
+        OpTy = PtrTy->getElementType();
+      }
+
+      // FIXME: Support aggregate input operands
+      if (!OpTy->isSingleValueType()) {
+        LLVM_DEBUG(
+            dbgs() << "Aggregate input operands are not supported yet\n");
+        return false;
+      }
+
+      OpInfo.ConstraintVT = TLI->getValueType(DL, OpTy, true).getSimpleVT();
 
     } else if (OpInfo.Type == InlineAsm::isOutput && !OpInfo.isIndirect) {
       assert(!Call.getType()->isVoidTy() && "Bad inline asm!");
@@ -363,8 +387,97 @@ bool InlineAsmLowering::lowerInlineAsm(
       }
 
       break;
-    case InlineAsm::isInput:
-      return false;
+    case InlineAsm::isInput: {
+      if (OpInfo.isMatchingInputConstraint()) {
+        LLVM_DEBUG(dbgs() << "Tied input operands not supported yet\n");
+        return false;
+      }
+
+      if (OpInfo.ConstraintType == TargetLowering::C_Other &&
+          OpInfo.isIndirect) {
+        LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint "
+                             "not supported yet\n");
+        return false;
+      }
+
+      if (OpInfo.ConstraintType == TargetLowering::C_Immediate ||
+          OpInfo.ConstraintType == TargetLowering::C_Other) {
+
+        std::vector<MachineOperand> Ops;
+        if (!lowerAsmOperandForConstraint(OpInfo.CallOperandVal,
+                                          OpInfo.ConstraintCode, Ops,
+                                          MIRBuilder)) {
+          LLVM_DEBUG(dbgs() << "Don't support constraint: "
+                            << OpInfo.ConstraintCode << " yet\n");
+          return false;
+        }
+
+        assert(Ops.size() > 0 &&
+               "Expected constraint to be lowered to at least one operand");
+
+        // Add information to the INLINEASM node to know about this input.
+        unsigned OpFlags =
+            InlineAsm::getFlagWord(InlineAsm::Kind_Imm, Ops.size());
+        Inst.addImm(OpFlags);
+        Inst.add(Ops);
+        break;
+      }
+
+      if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
+        assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!");
+
+        unsigned ConstraintID =
+            TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);
+        unsigned OpFlags = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, 1);
+        OpFlags = InlineAsm::getFlagWordForMem(OpFlags, ConstraintID);
+        Inst.addImm(OpFlags);
+        ArrayRef<Register> SourceRegs =
+            GetOrCreateVRegs(*OpInfo.CallOperandVal);
+        assert(
+            SourceRegs.size() == 1 &&
+            "Expected the memory input to fit into a single virtual register");
+        Inst.addReg(SourceRegs[0]);
+        break;
+      }
+
+      assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass ||
+              OpInfo.ConstraintType == TargetLowering::C_Register) &&
+             "Unknown constraint type!");
+
+      if (OpInfo.isIndirect) {
+        LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet "
+                             "for constraint '"
+                          << OpInfo.ConstraintCode << "'\n");
+        return false;
+      }
+
+      // Copy the input into the appropriate registers.
+      if (OpInfo.Regs.empty()) {
+        LLVM_DEBUG(
+            dbgs()
+            << "Couldn't allocate input register for register constraint\n");
+        return false;
+      }
+
+      unsigned NumRegs = OpInfo.Regs.size();
+      ArrayRef<Register> SourceRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);
+      assert(NumRegs == SourceRegs.size() &&
+             "Expected the number of input registers to match the number of "
+             "source registers");
+
+      if (NumRegs > 1) {
+        LLVM_DEBUG(dbgs() << "Input operands with multiple input registers are "
+                             "not supported yet\n");
+        return false;
+      }
+
+      unsigned Flag = InlineAsm::getFlagWord(InlineAsm::Kind_RegUse, NumRegs);
+      Inst.addImm(Flag);
+      MIRBuilder.buildCopy(OpInfo.Regs[0], SourceRegs[0]);
+      Inst.addReg(OpInfo.Regs[0]);
+      break;
+    }
+
     case InlineAsm::isClobber: {
 
       unsigned NumRegs = OpInfo.Regs.size();
@@ -441,3 +554,27 @@ bool InlineAsmLowering::lowerInlineAsm(
 
   return true;
 }
+
+bool InlineAsmLowering::lowerAsmOperandForConstraint(
+    Value *Val, StringRef Constraint, std::vector<MachineOperand> &Ops,
+    MachineIRBuilder &MIRBuilder) const {
+  if (Constraint.size() > 1)
+    return false;
+
+  char ConstraintLetter = Constraint[0];
+  switch (ConstraintLetter) {
+  default:
+    return false;
+  case 'i': // Simple Integer or Relocatable Constant
+    if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
+      assert(CI->getBitWidth() <= 64 &&
+             "expected immediate to fit into 64-bits");
+      // Boolean constants should be zero-extended, others are sign-extended
+      bool IsBool = CI->getBitWidth() == 1;
+      int64_t ExtVal = IsBool ? CI->getZExtValue() : CI->getSExtValue();
+      Ops.push_back(MachineOperand::CreateImm(ExtVal));
+      return true;
+    }
+    return false;
+  }
+}

diff  --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
index ed8f55e5509d..18540f1b8313 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
@@ -132,3 +132,66 @@ define float @test_vector_output() nounwind {
   %2 = extractelement <2 x float> %1, i32 0
   ret float %2
 }
+
+define void @test_input_register_imm() {
+  ; CHECK-LABEL: name: test_input_register_imm
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
+  ; CHECK:   [[COPY:%[0-9]+]]:gpr64common = COPY [[C]](s64)
+  ; CHECK:   INLINEASM &"mov x0, $0", 1 /* sideeffect attdialect */, 9 /* reguse */, [[COPY]]
+  ; CHECK:   RET_ReallyLR
+  call void asm sideeffect "mov x0, $0", "r"(i64 42)
+  ret void
+}
+
+; Make sure that boolean immediates are properly (zero) extended.
+define i32 @test_boolean_imm_ext() {
+  ; CHECK-LABEL: name: test_boolean_imm_ext
+  ; CHECK: bb.1.entry:
+  ; CHECK:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; CHECK:   INLINEASM &"#TEST 42 + ${0:c} - .\0A\09", 9 /* sideeffect mayload attdialect */, 13 /* imm */, 1
+  ; CHECK:   $w0 = COPY [[C]](s32)
+  ; CHECK:   RET_ReallyLR implicit $w0
+entry:
+  tail call void asm sideeffect "#TEST 42 + ${0:c} - .\0A\09", "i"(i1 true)
+  ret i32 1
+}
+
+define void @test_input_imm() {
+  ; CHECK-LABEL: name: test_input_imm
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK:   INLINEASM &"mov x0, $0", 9 /* sideeffect mayload attdialect */, 13 /* imm */, 42
+  ; CHECK:   RET_ReallyLR
+  call void asm sideeffect "mov x0, $0", "i"(i64 42)
+  ret void
+}
+
+define zeroext i8 @test_input_register(i8* %src) nounwind {
+  ; CHECK-LABEL: name: test_input_register
+  ; CHECK: bb.1.entry:
+  ; CHECK:   liveins: $x0
+  ; CHECK:   [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+  ; CHECK:   [[COPY1:%[0-9]+]]:gpr64common = COPY [[COPY]](p0)
+  ; CHECK:   INLINEASM &"ldtrb ${0:w}, [$1]", 0 /* attdialect */, 655370 /* regdef:GPR32common */, def %1, 9 /* reguse */, [[COPY1]]
+  ; CHECK:   [[COPY2:%[0-9]+]]:_(s32) = COPY %1
+  ; CHECK:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY2]](s32)
+  ; CHECK:   [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC]](s8)
+  ; CHECK:   $w0 = COPY [[ZEXT]](s32)
+  ; CHECK:   RET_ReallyLR implicit $w0
+entry:
+  %0 = tail call i8 asm "ldtrb ${0:w}, [$1]", "=r,r"(i8* %src) nounwind
+  ret i8 %0
+}
+
+define i32 @test_memory_constraint(i32* %a) nounwind {
+  ; CHECK-LABEL: name: test_memory_constraint
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK:   liveins: $x0
+  ; CHECK:   [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+  ; CHECK:   INLINEASM &"ldr $0, $1", 8 /* mayload attdialect */, 655370 /* regdef:GPR32common */, def %1, 196622 /* mem:m */, [[COPY]](p0)
+  ; CHECK:   [[COPY1:%[0-9]+]]:_(s32) = COPY %1
+  ; CHECK:   $w0 = COPY [[COPY1]](s32)
+  ; CHECK:   RET_ReallyLR implicit $w0
+  %1 = tail call i32 asm "ldr $0, $1", "=r,*m"(i32* %a)
+  ret i32 %1
+}


        


More information about the llvm-commits mailing list