[clang] [llvm] Support the inline asm 'a' constraint on PowerPC (PR #141604)

Kamau Bridgeman via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 8 11:18:39 PDT 2025


https://github.com/kamaub updated https://github.com/llvm/llvm-project/pull/141604

>From e4102e3c4ec77e98c9a5efd3c79cd6a7690ba6a1 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.bridgeman at ibm.com>
Date: Tue, 27 May 2025 09:39:07 -0400
Subject: [PATCH 1/5] [WIP] Support the inline asm 'a' constraint on PowerPC

This patch adds backend and frontend support for address operand
constraint `a` for GCC style inline assembly. It allows the user
to specify X-FORM addressing mode operations in inline assmebly
without doing a [0 + Reg] index using the y constraint modifier.
---
 clang/lib/Basic/Targets/PPC.h                 |   4 +-
 .../PowerPC/inline-asm-constraints-error.c    |  12 +-
 .../CodeGen/PowerPC/inline-asm-constraints.c  |  66 +++++++++
 llvm/include/llvm/IR/InlineAsm.h              |   3 +
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp     |   8 ++
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp   |   1 +
 llvm/lib/Target/PowerPC/PPCISelLowering.cpp   |   2 +
 llvm/lib/Target/PowerPC/PPCISelLowering.h     |  16 +--
 .../PowerPC/inline-asm-constraints-error.ll   |  26 ++++
 .../CodeGen/PowerPC/inline-asm-constraints.ll | 127 ++++++++++++++++++
 10 files changed, 250 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/CodeGen/PowerPC/inline-asm-constraints.c
 create mode 100644 llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
 create mode 100644 llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll

diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 17057cef97a57..76fb24ed40050 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -303,8 +303,8 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
       break;
     case 'a': // Address operand that is an indexed or indirect from a
               // register (`p' is preferable for asm statements)
-              // TODO: Add full support for this constraint
-      return false;
+      Info.setAllowsRegister();
+      break;
     case 'R': // AIX TOC entry
     case 'S': // Constant suitable as a 64-bit mask operand
     case 'T': // Constant suitable as a 32-bit mask operand
diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
index 2f35e52fc0b77..c1bb59ee3c22a 100644
--- a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
@@ -1,9 +1,13 @@
 // RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff -verify %s
 // RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff -verify %s
-// This test case exist to test marking the 'a' inline assembly constraint as
-// unsupported because powerpc previously marked it as supported.
-int foo(int arg){
-  asm goto ("bc 12,2,%l[TEST_LABEL]" : : "a"(&&TEST_LABEL) : : TEST_LABEL); //expected-error {{invalid input constraint 'a' in asm}}
+
+ int labelConstraintError(int arg){
+  asm goto ("bc 12,2,%l[TEST_LABEL]" : : "s"(&&TEST_LABEL) : : TEST_LABEL); //expected-error {{invalid input constraint 's' in asm}}
   return 0;
 TEST_LABEL: return arg + 1;
 }
+
+char wrongAddrConstraint(char* result) {
+  asm ("stb %1,%0" : "a"(result) : "r"('E') :); //expected-error {{invalid output constraint 'a' in asm}}
+  return *result;
+}
diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
new file mode 100644
index 0000000000000..ca5a9ffcee0cc
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -emit-llvm -triple powerpc64-ibm-aix-xcoff \
+// RUN:   %s -o - | FileCheck %s
+
+char loadAddressAConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @loadAddressAConstrained(ptr noundef %ptr)
+// CHECK:  %1 = call ptr asm "addi $0,$1, 0", "=r,a"(ptr %0)
+  char* result;
+  asm ("addi %0,%1, 0" : "=r"(result) : "a"(ptr) :);
+  return *result;
+}
+
+char loadAddressZyConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @loadAddressZyConstrained(ptr noundef %ptr)
+// CHECK:  %1 = call ptr asm "add $0,${1:y}", "=r,*Z"(ptr elementtype(i8) %0)
+  char* result;
+  asm ("add %0,%y1" : "=r"(result) : "Z"(*ptr) :);
+  return *result;
+}
+
+char xFormRegImmLoadAConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @xFormRegImmLoadAConstrained(ptr noundef %ptr)
+// CHECK:  %1 = call ptr asm "addi $0,$1,$2", "=r,a,I"(ptr %0, i32 10000)
+  char* result;
+  asm ("addi %0,%1,%2" : "=r"(result) : "a"(ptr), "I"(10000) :);
+  return *result;
+}
+
+char loadIndirectAddressZConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressZConstrained(ptr noundef %ptr)
+// CHECK:  %1 = call ptr asm "ld $0,$1", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+  char* result;
+  asm ("ld %0,%1" : "=r"(result) : "Z"(ptr[100]) :);
+  return *result;
+}
+
+char loadIndirectAddressAConstrained(char** ptr, unsigned index) {
+// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK:  %2 = call ptr asm "ldx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
+  char* result;
+  asm ("ldx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
+  return *result;
+}
+
+char dFormLoadZConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @dFormLoadZConstrained(ptr noundef %ptr)
+// CHECK:  %1 = call i8 asm "lbz $0,$1", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+  char result;
+  asm ("lbz %0,%1" : "=r"(result) : "Z"(ptr[8]) :);
+  return result;
+}
+
+char xFormRegRegLoadZyConstrained(char* ptr, unsigned index) {
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadZyConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK:  %2 = call i8 asm "lbzx $0, ${1:y}", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+  char result;
+  asm("lbzx %0, %y1" : "=r"(result) : "Z"(ptr[index]) :);
+  return result;
+}
+
+char xFormRegRegLoadAConstrained(char* ptr, unsigned index) {
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK:  %2 = call i8 asm "lbzx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
+  char result;
+  asm ("lbzx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
+  return result;
+}
diff --git a/llvm/include/llvm/IR/InlineAsm.h b/llvm/include/llvm/IR/InlineAsm.h
index e5f506e5694da..87d68acde624b 100644
--- a/llvm/include/llvm/IR/InlineAsm.h
+++ b/llvm/include/llvm/IR/InlineAsm.h
@@ -264,6 +264,7 @@ class InlineAsm final : public Value {
 
     // Address constraints
     p,
+    a,
     ZQ,
     ZR,
     ZS,
@@ -514,6 +515,8 @@ class InlineAsm final : public Value {
       return "Zy";
     case ConstraintCode::p:
       return "p";
+    case ConstraintCode::a:
+      return "a";
     case ConstraintCode::ZQ:
       return "ZQ";
     case ConstraintCode::ZR:
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 79e52635a3675..0c02b90747806 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -442,6 +442,14 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
   }
 
   assert(MI->getOperand(OpNo).isReg());
+  const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
+  if (!FlagsOP.isImm())
+    return true;
+  const InlineAsm::Flag Flags(FlagsOP.getImm());
+  if (Flags.getMemoryConstraintID() == InlineAsm::ConstraintCode::a) {
+    printOperand(MI, OpNo, O);
+    return false;
+  }
   O << "0(";
   printOperand(MI, OpNo, O);
   O << ")";
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 0907239153226..e4029d3612b9f 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -392,6 +392,7 @@ namespace {
         errs() << "ConstraintID: "
                << InlineAsm::getMemConstraintName(ConstraintID) << "\n";
         llvm_unreachable("Unexpected asm memory constraint");
+      case InlineAsm::ConstraintCode::a:
       case InlineAsm::ConstraintCode::es:
       case InlineAsm::ConstraintCode::m:
       case InlineAsm::ConstraintCode::o:
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index ab78f33f5a630..843aec1ae4b99 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -17184,6 +17184,8 @@ PPCTargetLowering::getConstraintType(StringRef Constraint) const {
   if (Constraint.size() == 1) {
     switch (Constraint[0]) {
     default: break;
+    case 'a':
+      return C_Address;
     case 'b':
     case 'r':
     case 'f':
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 1f22aa16a89be..0ecb54dcf2f39 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -997,15 +997,13 @@ namespace llvm {
 
     InlineAsm::ConstraintCode
     getInlineAsmMemConstraint(StringRef ConstraintCode) const override {
-      if (ConstraintCode == "es")
-        return InlineAsm::ConstraintCode::es;
-      else if (ConstraintCode == "Q")
-        return InlineAsm::ConstraintCode::Q;
-      else if (ConstraintCode == "Z")
-        return InlineAsm::ConstraintCode::Z;
-      else if (ConstraintCode == "Zy")
-        return InlineAsm::ConstraintCode::Zy;
-      return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
+      return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
+        .Case("es", InlineAsm::ConstraintCode::es)
+        .Case("Q", InlineAsm::ConstraintCode::Q)
+        .Case("Z", InlineAsm::ConstraintCode::Z)
+        .Case("Zy", InlineAsm::ConstraintCode::Zy)
+        .Case("a", InlineAsm::ConstraintCode::a)
+        .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
     }
 
     void CollectTargetIntrinsicOperands(const CallInst &I,
diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
new file mode 100644
index 0000000000000..d7fbdfed89ce3
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
@@ -0,0 +1,26 @@
+; RUN: not llc -mcpu=pwr8 -mtriple=powerpc64-ibm-aix-xcoff  -filetype=null %s 2>&1 | FileCheck %s
+; XFAIL: *
+
+; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
+define i8 @charLoadAConstrained(i8 zeroext %ptr, i32 %index) {
+entry:
+  %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i8 %ptr, i32 %index)
+  %conv = trunc i16 %0 to i8
+  ret i8 %conv
+}
+
+define i8 @shortLoadAConstrained(i16 zeroext %ptr, i32 %index) {
+; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
+entry:
+  %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i16 %ptr, i32 %index)
+  %conv = trunc i16 %0 to i8
+  ret i8 %conv
+}
+
+define i8 @intLoadAConstrained(i32 zeroext %ptr, i32 %index) {
+; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
+entry:
+  %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i32 %ptr, i32 %index)
+  %conv = trunc i16 %0 to i8
+  ret i8 %conv
+}
diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
new file mode 100644
index 0000000000000..4781bd7d0b235
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN:  -mtriple=powerpc64-ibm-aix-xcoff | FileCheck %s
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN:  -mtriple=powerpc-ibm-aix-xcoff | FileCheck %s
+
+define signext i8 @loadAddressAConstrained(ptr %ptr) {
+; CHECK-LABEL: loadAddressAConstrained:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    addi 3,3, 0
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lbz 3, 0(3)
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call ptr asm "addi $0,$1, 0", "=r,a"(ptr %ptr)
+  %1 = load i8, ptr %0, align 1
+  ret i8 %1
+}
+
+define signext i8 @xFormRegImmLoadAConstrained(ptr %ptr) {
+; CHECK-LABEL: xFormRegImmLoadAConstrained:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    addi 3,3,10000
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lbz 3, 0(3)
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call ptr asm "addi $0,$1,$2", "=r,a,I"(ptr %ptr, i32 10000)
+  %1 = load i8, ptr %0, align 1
+  ret i8 %1
+}
+
+define signext i8 @loadIndirectAddressZConstrained(ptr %ptr) {
+; CHECK-LABEL: loadIndirectAddressZConstrained:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    addi 3, 3, 800
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    ld 3,0(3)
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lbz 3, 0(3)
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+entry:
+  %arrayidx = getelementptr inbounds nuw i8, ptr %ptr, i64 800
+  %0 = tail call ptr asm "ld $0,$1", "=r,*Z"(ptr nonnull elementtype(ptr) %arrayidx)
+  %1 = load i8, ptr %0, align 1
+  ret i8 %1
+}
+
+define signext i8 @loadIndirectAddressAConstrained(ptr %ptr, i32 zeroext %index) {
+; CHECK-LABEL: loadIndirectAddressAConstrained:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    ldx 3,3,4
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lbz 3, 0(3)
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call ptr asm "ldx $0,$1,$2", "=r,a,r"(ptr %ptr, i32 zeroext %index)
+  %1 = load i8, ptr %0, align 1
+  ret i8 %1
+}
+
+define signext i8 @dFormLoadZConstrained(ptr %ptr) {
+; CHECK-LABEL: dFormLoadZConstrained:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    addi 3, 3, 8
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    lbz 3,0(3)
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+entry:
+  %arrayidx = getelementptr inbounds nuw i8, ptr %ptr, i64 8
+  %0 = tail call i8 asm "lbz $0,$1", "=r,*Z"(ptr nonnull elementtype(i8) %arrayidx)
+  ret i8 %0
+}
+
+define signext i8 @xFormRegRegLoadZyConstrained(ptr %ptr, i32 zeroext %index) {
+; CHECK-LABEL: xFormRegRegLoadZyConstrained:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    add 3, 3, 4
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    lbzx 3, 0, 3
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+entry:
+  %idxprom = zext i32 %index to i64
+  %arrayidx = getelementptr inbounds nuw i8, ptr %ptr, i64 %idxprom
+  %0 = tail call i8 asm "lbzx $0, ${1:y}", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+  ret i8 %0
+}
+
+define signext i8 @xFormRegRegLoadAConstrained(ptr %ptr, i32 zeroext %index) {
+; CHECK-LABEL: xFormRegRegLoadAConstrained:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    lbzx 3,3,4
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call i8 asm "lbzx $0,$1,$2", "=r,a,r"(ptr %ptr, i32 %index)
+  ret i8 %0
+}
+
+define i8 @implicitRegImmToRegRegConversion(ptr readnone %ptr, i32 zeroext %index) {
+; CHECK-LABEL: implicitRegImmToRegRegConversion:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    add 3, 3, 4
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    lbzx 3, 0, 3
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    blr
+entry:
+  %idx.ext = zext i32 %index to i64
+  %add.ptr = getelementptr inbounds nuw i8, ptr %ptr, i64 %idx.ext
+  %0 = tail call i8 asm "lbzx $0, ${1:y}", "=r,a"(ptr %add.ptr)
+  ret i8 %0
+}
+

>From a0357a963865beed4ed8af215e2dc99fbd941b59 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.bridgeman at ibm.com>
Date: Wed, 28 May 2025 09:32:04 -0400
Subject: [PATCH 2/5] Removing the backend type promotion test case file

The backend test case file detailing type promotion errors when
using this constraint has been identified as a separate issue
that is exposed by this patch. A separate issue, and PR will
resolve this problem.
---
 .../PowerPC/inline-asm-constraints-error.ll   | 26 -------------------
 1 file changed, 26 deletions(-)
 delete mode 100644 llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll

diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
deleted file mode 100644
index d7fbdfed89ce3..0000000000000
--- a/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
+++ /dev/null
@@ -1,26 +0,0 @@
-; RUN: not llc -mcpu=pwr8 -mtriple=powerpc64-ibm-aix-xcoff  -filetype=null %s 2>&1 | FileCheck %s
-; XFAIL: *
-
-; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
-define i8 @charLoadAConstrained(i8 zeroext %ptr, i32 %index) {
-entry:
-  %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i8 %ptr, i32 %index)
-  %conv = trunc i16 %0 to i8
-  ret i8 %conv
-}
-
-define i8 @shortLoadAConstrained(i16 zeroext %ptr, i32 %index) {
-; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
-entry:
-  %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i16 %ptr, i32 %index)
-  %conv = trunc i16 %0 to i8
-  ret i8 %conv
-}
-
-define i8 @intLoadAConstrained(i32 zeroext %ptr, i32 %index) {
-; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
-entry:
-  %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i32 %ptr, i32 %index)
-  %conv = trunc i16 %0 to i8
-  ret i8 %conv
-}

>From 9890270ec4e9e9b42f74a9204757cf63c625e870 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.bridgeman at ibm.com>
Date: Wed, 28 May 2025 11:23:45 -0400
Subject: [PATCH 3/5] Applying git clang format NFC

---
 llvm/lib/Target/PowerPC/PPCISelLowering.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 0ecb54dcf2f39..d0e272403c978 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -998,12 +998,12 @@ namespace llvm {
     InlineAsm::ConstraintCode
     getInlineAsmMemConstraint(StringRef ConstraintCode) const override {
       return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
-        .Case("es", InlineAsm::ConstraintCode::es)
-        .Case("Q", InlineAsm::ConstraintCode::Q)
-        .Case("Z", InlineAsm::ConstraintCode::Z)
-        .Case("Zy", InlineAsm::ConstraintCode::Zy)
-        .Case("a", InlineAsm::ConstraintCode::a)
-        .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
+          .Case("es", InlineAsm::ConstraintCode::es)
+          .Case("Q", InlineAsm::ConstraintCode::Q)
+          .Case("Z", InlineAsm::ConstraintCode::Z)
+          .Case("Zy", InlineAsm::ConstraintCode::Zy)
+          .Case("a", InlineAsm::ConstraintCode::a)
+          .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
     }
 
     void CollectTargetIntrinsicOperands(const CallInst &I,

>From fa7236e77a2d52b07cdd9d91f01a88c01002b623 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 8 Oct 2025 14:11:27 -0400
Subject: [PATCH 4/5] Addressing Review comments

Adding comments and additional test case run lines to the change-set.
---
 .../PowerPC/inline-asm-constraints-error.c       |  2 ++
 .../CodeGen/PowerPC/inline-asm-constraints.c     | 11 ++++++++---
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp        |  6 ++++++
 llvm/lib/Target/PowerPC/PPCISelLowering.cpp      |  1 +
 .../CodeGen/PowerPC/inline-asm-constraints.ll    | 16 ++++++++--------
 5 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
index c1bb59ee3c22a..6d1101dc81bee 100644
--- a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff -verify %s
 // RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff -verify %s
+// This test file validates that we diagnose inline assembly constraint error
+// in the clang front-end as expected.
 
  int labelConstraintError(int arg){
   asm goto ("bc 12,2,%l[TEST_LABEL]" : : "s"(&&TEST_LABEL) : : TEST_LABEL); //expected-error {{invalid input constraint 's' in asm}}
diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
index ca5a9ffcee0cc..365c2fb3a4dac 100644
--- a/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
@@ -1,5 +1,10 @@
 // RUN: %clang_cc1 -emit-llvm -triple powerpc64-ibm-aix-xcoff \
 // RUN:   %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple powerpc-ibm-aix-xcoff \
+// RUN:   %s -o - | FileCheck %s
+// This test file checks that we represent common C inline assembly
+// PowerPC load address mode operations accureately in the platform
+// agnostic LLVM IR.
 
 char loadAddressAConstrained(char* ptr) {
 // CHECK-LABEL: define{{.*}} i8 @loadAddressAConstrained(ptr noundef %ptr)
@@ -34,7 +39,7 @@ char loadIndirectAddressZConstrained(char* ptr) {
 }
 
 char loadIndirectAddressAConstrained(char** ptr, unsigned index) {
-// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressAConstrained(ptr noundef %ptr, i32 noundef{{[ zeroext]*}} %index)
 // CHECK:  %2 = call ptr asm "ldx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
   char* result;
   asm ("ldx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
@@ -50,7 +55,7 @@ char dFormLoadZConstrained(char* ptr) {
 }
 
 char xFormRegRegLoadZyConstrained(char* ptr, unsigned index) {
-// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadZyConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadZyConstrained(ptr noundef %ptr, i32 noundef{{[ zeroext]*}} %index)
 // CHECK:  %2 = call i8 asm "lbzx $0, ${1:y}", "=r,*Z"(ptr elementtype(i8) %arrayidx)
   char result;
   asm("lbzx %0, %y1" : "=r"(result) : "Z"(ptr[index]) :);
@@ -58,7 +63,7 @@ char xFormRegRegLoadZyConstrained(char* ptr, unsigned index) {
 }
 
 char xFormRegRegLoadAConstrained(char* ptr, unsigned index) {
-// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadAConstrained(ptr noundef %ptr, i32 noundef{{[ zeroext]*}} %index)
 // CHECK:  %2 = call i8 asm "lbzx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
   char result;
   asm ("lbzx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 0c02b90747806..8dff8c4954a0b 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -441,11 +441,17 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
     }
   }
 
+  // Assert that this an register input operand to an inline asm statement.
   assert(MI->getOperand(OpNo).isReg());
+  // The ConstraintInfo for this Operand is encounted in Op - 1 operand
+  // as a part of the InlineAsm Flags.
   const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
   if (!FlagsOP.isImm())
     return true;
   const InlineAsm::Flag Flags(FlagsOP.getImm());
+  // Address operand is a Register for an X-form instruction, similar to the
+  // 'y' Extra Code. Constraint 'a' allows reg+reg Addressing without using
+  // a 'y' input modifier in Extended GCC ASM.
   if (Flags.getMemoryConstraintID() == InlineAsm::ConstraintCode::a) {
     printOperand(MI, OpNo, O);
     return false;
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 843aec1ae4b99..c1ac8986fa982 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -17185,6 +17185,7 @@ PPCTargetLowering::getConstraintType(StringRef Constraint) const {
     switch (Constraint[0]) {
     default: break;
     case 'a':
+      // 'a' constraints inputs to address operands.
       return C_Address;
     case 'b':
     case 'r':
diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
index 4781bd7d0b235..6d84bed509afd 100644
--- a/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
+++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
@@ -1,14 +1,14 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 \
 ; RUN:  -mtriple=powerpc64-ibm-aix-xcoff | FileCheck %s
-; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 \
 ; RUN:  -mtriple=powerpc-ibm-aix-xcoff | FileCheck %s
 
 define signext i8 @loadAddressAConstrained(ptr %ptr) {
 ; CHECK-LABEL: loadAddressAConstrained:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    addi 3,3, 0
+; CHECK-NEXT:    addi 3, 3, 0
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:    lbz 3, 0(3)
 ; CHECK-NEXT:    extsb 3, 3
@@ -23,7 +23,7 @@ define signext i8 @xFormRegImmLoadAConstrained(ptr %ptr) {
 ; CHECK-LABEL: xFormRegImmLoadAConstrained:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    addi 3,3,10000
+; CHECK-NEXT:    addi 3, 3, 10000
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:    lbz 3, 0(3)
 ; CHECK-NEXT:    extsb 3, 3
@@ -39,7 +39,7 @@ define signext i8 @loadIndirectAddressZConstrained(ptr %ptr) {
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    addi 3, 3, 800
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    ld 3,0(3)
+; CHECK-NEXT:    ld 3, 0(3)
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:    lbz 3, 0(3)
 ; CHECK-NEXT:    extsb 3, 3
@@ -55,7 +55,7 @@ define signext i8 @loadIndirectAddressAConstrained(ptr %ptr, i32 zeroext %index)
 ; CHECK-LABEL: loadIndirectAddressAConstrained:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    ldx 3,3,4
+; CHECK-NEXT:    ldx 3, 3, 4
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:    lbz 3, 0(3)
 ; CHECK-NEXT:    extsb 3, 3
@@ -71,7 +71,7 @@ define signext i8 @dFormLoadZConstrained(ptr %ptr) {
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    addi 3, 3, 8
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    lbz 3,0(3)
+; CHECK-NEXT:    lbz 3, 0(3)
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:    extsb 3, 3
 ; CHECK-NEXT:    blr
@@ -101,7 +101,7 @@ define signext i8 @xFormRegRegLoadAConstrained(ptr %ptr, i32 zeroext %index) {
 ; CHECK-LABEL: xFormRegRegLoadAConstrained:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    #APP
-; CHECK-NEXT:    lbzx 3,3,4
+; CHECK-NEXT:    lbzx 3, 3, 4
 ; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:    extsb 3, 3
 ; CHECK-NEXT:    blr

>From cc03557676e67887aa2f39270b82d5924c634476 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 8 Oct 2025 14:14:38 -0400
Subject: [PATCH 5/5] Apply suggestion from @kamaub

---
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 8dff8c4954a0b..7649fb7d00cc7 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -443,7 +443,7 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
 
   // Assert that this an register input operand to an inline asm statement.
   assert(MI->getOperand(OpNo).isReg());
-  // The ConstraintInfo for this Operand is encounted in Op - 1 operand
+  // The ConstraintInfo for this Operand is encoded in Op - 1 operand
   // as a part of the InlineAsm Flags.
   const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
   if (!FlagsOP.isImm())



More information about the llvm-commits mailing list