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..1464500359046 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -emit-llvm -triple powerpc64-ibm-aix-xcoff \ +// RUN: %s -o - | FileCheck %s + +#include + +// Test Atomic Memory Operation Support: +// This test case takes an address and performs an atomic load at that address. +// The purpose is to test the Q machine constraint and P machine constraint +// argument modifier together. +// These constraints on the pointer `ptr` read as: constrain (uint32_t*)ptr to +// read and writeable X-Form Addressed Memory operands. +static __attribute__((noinline)) +uint32_t atomic_load(uint32_t *ptr, uint32_t val) +{ +// CHECK-LABEL: define{{.*}} i32 @atomic_load(ptr noundef %ptr, i32 noundef zeroext %val) +// CHECK: %3 = call { i128, i32 } asm sideeffect "mr ${1:L},$3\0A\09 lwat $1,${0:P},$4\0A\09 mr $2,$1\0A", "=*Q,=&r,=r,r,n,0"(ptr elementtype(i32) %arrayidx, i32 %2, i32 0, i32 %1) + unsigned __int128 tmp; + uint32_t ret; + __asm__ volatile ("mr %L1,%3\n" + "\t lwat %1,%P0,%4\n" + "\t mr %2,%1\n" + : "+Q" (ptr[0]), "=&r" (tmp), "=r" (ret) + : "r" (val), "n" (0x00)); + return ret; +} + +int main(int argc, char **argv) { + return atomic_load((uint32_t*)argv[1], (uint32_t)*(argv[2])); +} \ No newline at end of file diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index bcb3f507e98d6..448b03ee25bb9 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -411,11 +411,26 @@ bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) { + auto reportAsmMemError = [&](StringRef errMsg) { + const char *AsmStr = MI->getOperand(0).getSymbolName(); + const MDNode *LocMD = MI->getLocCookieMD(); + uint64_t LocCookie = + LocMD ? mdconst::extract(LocMD->getOperand(0)) + ->getZExtValue() + : 0; + const Function &Fn = MI->getMF()->getFunction(); + Fn.getContext().diagnose( + DiagnosticInfoInlineAsm(LocCookie, errMsg + Twine(AsmStr) + "'")); + return true; + }; if (ExtraCode && ExtraCode[0]) { - if (ExtraCode[1] != 0) return true; // Unknown modifier. + if (ExtraCode[1] != 0) + return reportAsmMemError("Unknown modifier in inline asm:"); switch (ExtraCode[0]) { - default: return true; // Unknown modifier. + default: { + return reportAsmMemError("Unknown modifier in inline asm:"); + } case 'L': // A memory reference to the upper word of a double word op. O << getDataLayout().getPointerSize() << "("; printOperand(MI, OpNo, O); @@ -425,6 +440,9 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, O << "0, "; printOperand(MI, OpNo, O); return false; + case 'P': // A memory reference for an single inout to an X-form instr. + printOperand(MI, OpNo, O); + return false; case 'I': // Write 'i' if an integer constant, otherwise nothing. Used to print // addi vs add, etc. diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 8bf0d118da575..de26677c161d1 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -17882,6 +17882,7 @@ PPCTargetLowering::getConstraintType(StringRef Constraint) const { case 'y': return C_RegisterClass; case 'Z': + case 'Q': // FIXME: While Z does indicate a memory constraint, it specifically // indicates an r+r address (used in conjunction with the 'y' modifier // in the replacement string). Currently, we're forcing the base 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..72d370ce8567f --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll @@ -0,0 +1,21 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 \ +; RUN: -mtriple=powerpc64-ibm-aix-xcoff | FileCheck %s + +define zeroext i32 @atomic_load(ptr %ptr, i32 zeroext range(i32 0, 256) %val) { +; CHECK-LABEL: atomic_load: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: mr 6, 4 +; CHECK-NEXT: lwat 5, 3, 0 +; CHECK-NEXT: mr 3, 5 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: clrldi 3, 3, 32 +; CHECK-NEXT: blr +entry: + %0 = load i32, ptr %ptr, align 4 + %1 = tail call { i128, i32 } asm sideeffect "mr ${1:L},$3\0A\09 lwat $1,${0:P},$4\0A\09 mr $2,$1\0A", "=*Q,=&r,=r,r,n,0"(ptr nonnull elementtype(i32) %ptr, i32 %val, i32 0, i32 %0) + %asmresult1 = extractvalue { i128, i32 } %1, 1 + ret i32 %asmresult1 +}