This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG46f83caebc8f: [InlineAsm] Add support for address operands 
("p"). (authored by jonpa).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Changed prior to commit:
  https://reviews.llvm.org/D122220?vs=420424&id=422459#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122220/new/

https://reviews.llvm.org/D122220

Files:
  clang/lib/Basic/Targets/SystemZ.h
  clang/lib/Basic/Targets/X86.cpp
  clang/test/CodeGen/SystemZ/systemz-inline-asm-03.c
  clang/test/CodeGen/asm.c
  llvm/docs/LangRef.rst
  llvm/include/llvm/CodeGen/TargetLowering.h
  llvm/include/llvm/IR/InlineAsm.h
  llvm/lib/CodeGen/CodeGenPrepare.cpp
  llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
  llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
  llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
  llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
  llvm/test/CodeGen/SystemZ/inline-asm-addr.ll
  llvm/test/CodeGen/X86/inline-asm-p-constraint.ll

Index: llvm/test/CodeGen/X86/inline-asm-p-constraint.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/X86/inline-asm-p-constraint.ll
@@ -0,0 +1,11 @@
+; RUN: llc -mtriple=x86_64-unknown-unknown -no-integrated-as < %s 2>&1 | FileCheck %s
+
+define i8* @foo(i8* %ptr) {
+; CHECK-LABEL: foo:
+  %1 = tail call i8* asm "lea $1, $0", "=r,p,~{dirflag},~{fpsr},~{flags}"(i8* %ptr)
+; CHECK:      #APP
+; CHECK-NEXT: lea (%rdi), %rax
+; CHECK-NEXT: #NO_APP
+  ret i8* %1
+; CHECK-NEXT: retq
+}
Index: llvm/test/CodeGen/SystemZ/inline-asm-addr.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/SystemZ/inline-asm-addr.ll
@@ -0,0 +1,57 @@
+; RUN: llc -mtriple=s390x-linux-gnu < %s | FileCheck %s
+
+@Addr = global i64 0, align 8
+@A = global i64* null, align 8
+@Idx = global i64 0, align 8
+
+define i64 @fun_BD12_p() {
+; CHECK-LABEL: fun_BD12_p:
+; CHECK: #APP
+; CHECK: lay	%r2, 800(%r1)
+entry:
+  %0 = load i64*, i64** @A
+  %arrayidx = getelementptr inbounds i64, i64* %0, i64 100
+  %1 = tail call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx)
+  store i64 %1, i64* @Addr
+  ret i64 %1
+}
+
+define i64 @fun_BDX12_p() {
+; CHECK-LABEL: fun_BDX12_p:
+; CHECK: #APP
+; CHECK: lay	%r2, 800(%r1,%r2)
+entry:
+  %0 = load i64*, i64** @A
+  %1 = load i64, i64* @Idx
+  %add = add nsw i64 %1, 100
+  %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
+  %2 = tail call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx)
+  store i64 %2, i64* @Addr
+  ret i64 %2
+}
+
+define i64 @fun_BD20_p() {
+; CHECK-LABEL: fun_BD20_p:
+; CHECK: #APP
+; CHECK: lay	%r2, 8000(%r1)
+entry:
+  %0 = load i64*, i64** @A
+  %arrayidx = getelementptr inbounds i64, i64* %0, i64 1000
+  %1 = tail call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx)
+  store i64 %1, i64* @Addr
+  ret i64 %1
+}
+
+define i64 @fun_BDX20_p() {
+; CHECK-LABEL: fun_BDX20_p:
+; CHECK: #APP
+; CHECK: lay	%r2, 8000(%r1,%r2)
+entry:
+  %0 = load i64*, i64** @A
+  %1 = load i64, i64* @Idx
+  %add = add nsw i64 %1, 1000
+  %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
+  %2 = tail call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx)
+  store i64 %2, i64* @Addr
+  ret i64 %2
+}
Index: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
===================================================================
--- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -6176,6 +6176,7 @@
   case InlineAsm::Constraint_v: // not offsetable    ??
   case InlineAsm::Constraint_m: // memory
   case InlineAsm::Constraint_X:
+  case InlineAsm::Constraint_p: // address
     if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4))
       return true;
     break;
Index: llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
===================================================================
--- llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -1700,6 +1700,7 @@
   case InlineAsm::Constraint_T:
   case InlineAsm::Constraint_m:
   case InlineAsm::Constraint_o:
+  case InlineAsm::Constraint_p:
     // Accept an address with a long displacement and an index.
     // m works the same as T, as this is the most general case.
     // We don't really have any special handling of "offsettable"
Index: llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -4908,13 +4908,14 @@
     case 'o': // offsetable
     case 'V': // not offsetable
       return C_Memory;
+    case 'p': // Address.
+      return C_Address;
     case 'n': // Simple Integer
     case 'E': // Floating Point Constant
     case 'F': // Floating Point Constant
       return C_Immediate;
     case 'i': // Simple Integer or Relocatable Constant
     case 's': // Relocatable Constant
-    case 'p': // Address.
     case 'X': // Allow ANY value.
     case 'I': // Target registers.
     case 'J':
@@ -5288,6 +5289,7 @@
   case TargetLowering::C_RegisterClass:
     return 2;
   case TargetLowering::C_Memory:
+  case TargetLowering::C_Address:
     return 3;
   }
   llvm_unreachable("Invalid constraint type");
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -8506,8 +8506,9 @@
   SmallVector<unsigned, 4> Regs;
   const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
 
-  // No work to do for memory operations.
-  if (OpInfo.ConstraintType == TargetLowering::C_Memory)
+  // No work to do for memory/address operands.
+  if (OpInfo.ConstraintType == TargetLowering::C_Memory ||
+      OpInfo.ConstraintType == TargetLowering::C_Address)
     return None;
 
   // If this is a constraint for a single physreg, or a constraint for a
@@ -8765,8 +8766,9 @@
     // Compute the constraint code and ConstraintType to use.
     TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG);
 
-    if (OpInfo.ConstraintType == TargetLowering::C_Memory &&
-        OpInfo.Type == InlineAsm::isClobber)
+    if ((OpInfo.ConstraintType == TargetLowering::C_Memory &&
+         OpInfo.Type == InlineAsm::isClobber) ||
+        OpInfo.ConstraintType == TargetLowering::C_Address)
       continue;
 
     // If this is a memory input, and if the operand is not indirect, do what we
@@ -8841,6 +8843,10 @@
       }
       return false;
     };
+    assert((OpInfo.ConstraintType != TargetLowering::C_Address ||
+            (OpInfo.Type == InlineAsm::isInput &&
+             !OpInfo.isMatchingInputConstraint())) &&
+           "Only address as input operand is allowed.");
 
     switch (OpInfo.Type) {
     case InlineAsm::isOutput:
@@ -8973,8 +8979,11 @@
         break;
       }
 
-      if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
-        assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!");
+      if (OpInfo.ConstraintType == TargetLowering::C_Memory ||
+          OpInfo.ConstraintType == TargetLowering::C_Address) {
+        assert((OpInfo.isIndirect ||
+                OpInfo.ConstraintType != TargetLowering::C_Memory) &&
+               "Operand must be indirect to be a mem!");
         assert(InOperandVal.getValueType() ==
                    TLI.getPointerTy(DAG.getDataLayout()) &&
                "Memory operands expect pointer values");
@@ -9112,6 +9121,8 @@
         break;
       case TargetLowering::C_Memory:
         break; // Already handled.
+      case TargetLowering::C_Address:
+        break; // Silence warning.
       case TargetLowering::C_Unknown:
         assert(false && "Unexpected unknown constraint");
       }
Index: llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
===================================================================
--- llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -145,6 +145,7 @@
   case TargetLowering::C_RegisterClass:
     return 2;
   case TargetLowering::C_Memory:
+  case TargetLowering::C_Address:
     return 3;
   }
   llvm_unreachable("Invalid constraint type");
@@ -644,6 +645,8 @@
       return false;
     case TargetLowering::C_Memory:
       break; // Already handled.
+    case TargetLowering::C_Address:
+      break; // Silence warning.
     case TargetLowering::C_Unknown:
       LLVM_DEBUG(dbgs() << "Unexpected unknown constraint\n");
       return false;
Index: llvm/lib/CodeGen/CodeGenPrepare.cpp
===================================================================
--- llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -4835,7 +4835,7 @@
     TLI.ComputeConstraintToUse(OpInfo, SDValue());
 
     // If this asm operand is our Value*, and if it isn't an indirect memory
-    // operand, we can't fold it!
+    // operand, we can't fold it!  TODO: Also handle C_Address?
     if (OpInfo.CallOperandVal == OpVal &&
         (OpInfo.ConstraintType != TargetLowering::C_Memory ||
          !OpInfo.isIndirect))
@@ -5618,6 +5618,7 @@
     // Compute the constraint code and ConstraintType to use.
     TLI->ComputeConstraintToUse(OpInfo, SDValue());
 
+    // TODO: Also handle C_Address?
     if (OpInfo.ConstraintType == TargetLowering::C_Memory &&
         OpInfo.isIndirect) {
       Value *OpVal = CS->getArgOperand(ArgNo++);
Index: llvm/include/llvm/IR/InlineAsm.h
===================================================================
--- llvm/include/llvm/IR/InlineAsm.h
+++ llvm/include/llvm/IR/InlineAsm.h
@@ -240,12 +240,15 @@
     Kind_RegDefEarlyClobber = 3, // Early-clobber output register, "=&r".
     Kind_Clobber = 4,            // Clobbered register, "~r".
     Kind_Imm = 5,                // Immediate.
-    Kind_Mem = 6,                // Memory operand, "m".
+    Kind_Mem = 6,                // Memory operand, "m", or an address, "p".
 
     // Memory constraint codes.
     // These could be tablegenerated but there's little need to do that since
     // there's plenty of space in the encoding to support the union of all
     // constraint codes for all targets.
+    // Addresses are included here as they need to be treated the same by the
+    // backend, the only difference is that they are not used to actaully
+    // access memory by the instruction.
     Constraint_Unknown = 0,
     Constraint_es,
     Constraint_i,
@@ -268,7 +271,11 @@
     Constraint_Z,
     Constraint_ZC,
     Constraint_Zy,
-    Constraints_Max = Constraint_Zy,
+
+    // Address constraints
+    Constraint_p,
+
+    Constraints_Max = Constraint_p,
     Constraints_ShiftAmount = 16,
 
     Flag_MatchingOperand = 0x80000000
@@ -453,6 +460,8 @@
       return "ZC";
     case InlineAsm::Constraint_Zy:
       return "Zy";
+    case InlineAsm::Constraint_p:
+      return "p";
     default:
       llvm_unreachable("Unknown memory constraint");
     }
Index: llvm/include/llvm/CodeGen/TargetLowering.h
===================================================================
--- llvm/include/llvm/CodeGen/TargetLowering.h
+++ llvm/include/llvm/CodeGen/TargetLowering.h
@@ -4336,6 +4336,7 @@
     C_Register,            // Constraint represents specific register(s).
     C_RegisterClass,       // Constraint represents any of register(s) in class.
     C_Memory,              // Memory constraint.
+    C_Address,             // Address constraint.
     C_Immediate,           // Requires an immediate.
     C_Other,               // Something else.
     C_Unknown              // Unsupported constraint.
@@ -4440,6 +4441,8 @@
       return InlineAsm::Constraint_o;
     if (ConstraintCode == "X")
       return InlineAsm::Constraint_X;
+    if (ConstraintCode == "p")
+      return InlineAsm::Constraint_p;
     return InlineAsm::Constraint_Unknown;
   }
 
Index: llvm/docs/LangRef.rst
===================================================================
--- llvm/docs/LangRef.rst
+++ llvm/docs/LangRef.rst
@@ -4658,6 +4658,8 @@
 - ``m``: A memory address operand. It is target-specific what addressing modes
   are supported, typical examples are register, or register + register offset,
   or register + immediate offset (of some target-specific size).
+- ``p``: An address operand. Similar to ``m``, but used by "load address"
+  type instructions without touching memory.
 - ``i``: An integer constant (of target-specific width). Allows either a simple
   immediate, or a relocatable value.
 - ``n``: An integer constant -- *not* including relocatable values.
Index: clang/test/CodeGen/asm.c
===================================================================
--- clang/test/CodeGen/asm.c
+++ clang/test/CodeGen/asm.c
@@ -274,3 +274,13 @@
 label_true:
   return 1;
 }
+
+void *t33(void *ptr)
+{
+  void *ret;
+  asm ("lea %1, %0" : "=r" (ret) : "p" (ptr));
+  return ret;
+
+  // CHECK: @t33
+  // CHECK: %1 = call i8* asm "lea $1, $0", "=r,p,~{dirflag},~{fpsr},~{flags}"(i8* %0)
+}
Index: clang/test/CodeGen/SystemZ/systemz-inline-asm-03.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/SystemZ/systemz-inline-asm-03.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -no-opaque-pointers -triple s390x-linux-gnu -O2 -emit-llvm \
+// RUN:   -o - %s 2>&1 | FileCheck %s
+// REQUIRES: systemz-registered-target
+
+long *A;
+long Idx;
+unsigned long Addr;
+
+unsigned long fun_BD12_p() {
+// CHECK-LABEL: define{{.*}} i64 @fun_BD12_p()
+// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx)
+  asm("lay %0, %1" : "=r" (Addr) : "p" (&A[100]));
+  return Addr;
+}
+
+unsigned long fun_BDX12_p() {
+// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_p()
+// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx)
+  asm("lay %0, %1" : "=r" (Addr) : "p" (&A[Idx + 100]));
+  return Addr;
+}
+
+unsigned long fun_BD20_p() {
+// CHECK-LABEL: define{{.*}} i64 @fun_BD20_p()
+// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx)
+  asm("lay %0, %1" : "=r" (Addr) : "p" (&A[1000]));
+  return Addr;
+}
+
+unsigned long fun_BDX20_p() {
+// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_p()
+// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx)
+  asm("lay %0, %1" : "=r" (Addr) : "p" (&A[Idx + 1000]));
+  return Addr;
+}
Index: clang/lib/Basic/Targets/X86.cpp
===================================================================
--- clang/lib/Basic/Targets/X86.cpp
+++ clang/lib/Basic/Targets/X86.cpp
@@ -1490,8 +1490,8 @@
     return std::string("{si}");
   case 'D':
     return std::string("{di}");
-  case 'p': // address
-    return std::string("im");
+  case 'p': // Keep 'p' constraint (address).
+    return std::string("p");
   case 't': // top of floating point stack.
     return std::string("{st}");
   case 'u':                        // second from top of floating point stack.
Index: clang/lib/Basic/Targets/SystemZ.h
===================================================================
--- clang/lib/Basic/Targets/SystemZ.h
+++ clang/lib/Basic/Targets/SystemZ.h
@@ -82,6 +82,16 @@
   bool validateAsmConstraint(const char *&Name,
                              TargetInfo::ConstraintInfo &info) const override;
 
+  std::string convertConstraint(const char *&Constraint) const override {
+    switch (Constraint[0]) {
+    case 'p': // Keep 'p' constraint.
+      return std::string("p");
+    default:
+      break;
+    }
+    return TargetInfo::convertConstraint(Constraint);
+  }
+
   const char *getClobbers() const override {
     // FIXME: Is this really right?
     return "";
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D122220: [InlineAsm... Jonas Paulsson via Phabricator via cfe-commits

Reply via email to