[llvm] 7335cd0 - [M68k] Add support for basic memory constraints in inline asm

Min-Yih Hsu via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 8 13:53:54 PST 2023


Author: Min-Yih Hsu
Date: 2023-03-08T13:52:34-08:00
New Revision: 7335cd05137076c69ce4716ac8f30a99fc95c406

URL: https://github.com/llvm/llvm-project/commit/7335cd05137076c69ce4716ac8f30a99fc95c406
DIFF: https://github.com/llvm/llvm-project/commit/7335cd05137076c69ce4716ac8f30a99fc95c406.diff

LOG: [M68k] Add support for basic memory constraints in inline asm

This patch adds support for 'm', 'Q', and 'U' memory constraints.

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

Added: 
    

Modified: 
    clang/lib/Basic/Targets/M68k.cpp
    clang/test/Sema/inline-asm-validate-m68k.c
    llvm/lib/Target/M68k/M68kAsmPrinter.cpp
    llvm/lib/Target/M68k/M68kAsmPrinter.h
    llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
    llvm/lib/Target/M68k/M68kISelLowering.cpp
    llvm/lib/Target/M68k/M68kISelLowering.h
    llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
    llvm/test/CodeGen/M68k/inline-asm.ll

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp
index cbc7c79837792..c83c5389e3b9d 100644
--- a/clang/lib/Basic/Targets/M68k.cpp
+++ b/clang/lib/Basic/Targets/M68k.cpp
@@ -192,6 +192,12 @@ bool M68kTargetInfo::validateAsmConstraint(
       break;
     }
     break;
+  case 'Q': // address register indirect addressing
+  case 'U': // address register indirect w/ constant offset addressing
+    // TODO: Handle 'S' (basically 'm' when pc-rel is enforced) when
+    // '-mpcrel' flag is properly handled by the driver.
+    info.setAllowsMemory();
+    return true;
   default:
     break;
   }

diff  --git a/clang/test/Sema/inline-asm-validate-m68k.c b/clang/test/Sema/inline-asm-validate-m68k.c
index a0b75304eba00..3abe638324452 100644
--- a/clang/test/Sema/inline-asm-validate-m68k.c
+++ b/clang/test/Sema/inline-asm-validate-m68k.c
@@ -82,5 +82,13 @@ void a(int x) {
 void d(int x) {
   asm ("" :: "d"(x));
 }
+
+// Memory constraints
+void mem() {
+  int x;
+  asm ("" :: "m"(x));
+  asm ("" :: "Q"(x));
+  asm ("" :: "U"(x));
+}
 #endif
 

diff  --git a/llvm/lib/Target/M68k/M68kAsmPrinter.cpp b/llvm/lib/Target/M68k/M68kAsmPrinter.cpp
index 4933d40f33885..f748450c170aa 100644
--- a/llvm/lib/Target/M68k/M68kAsmPrinter.cpp
+++ b/llvm/lib/Target/M68k/M68kAsmPrinter.cpp
@@ -76,6 +76,90 @@ bool M68kAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
   return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS);
 }
 
+void M68kAsmPrinter::printDisp(const MachineInstr *MI, unsigned opNum,
+                               raw_ostream &O) {
+  // Print immediate displacement without the '#' predix
+  const MachineOperand &Op = MI->getOperand(opNum);
+  if (Op.isImm()) {
+    O << Op.getImm();
+    return;
+  }
+  // Displacement is relocatable, so we're pretty permissive about what
+  // can be put here.
+  printOperand(MI, opNum, O);
+}
+
+void M68kAsmPrinter::printAbsMem(const MachineInstr *MI, unsigned OpNum,
+                                 raw_ostream &O) {
+  const MachineOperand &MO = MI->getOperand(OpNum);
+  if (MO.isImm())
+    O << format("$%0" PRIx64, (uint64_t)MO.getImm());
+  else
+    PrintAsmMemoryOperand(MI, OpNum, nullptr, O);
+}
+
+bool M68kAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+                                           unsigned OpNo, const char *ExtraCode,
+                                           raw_ostream &OS) {
+  const MachineOperand &MO = MI->getOperand(OpNo);
+  switch (MO.getType()) {
+  case MachineOperand::MO_Immediate:
+    // Immediate value that goes here is the addressing mode kind we set
+    // in M68kDAGToDAGISel::SelectInlineAsmMemoryOperand.
+    using namespace M68k;
+    // Skip the addressing mode kind operand.
+    ++OpNo;
+    // Decode MemAddrModeKind.
+    switch (static_cast<MemAddrModeKind>(MO.getImm())) {
+    case MemAddrModeKind::j:
+      printARIMem(MI, OpNo, OS);
+      break;
+    case MemAddrModeKind::o:
+      printARIPIMem(MI, OpNo, OS);
+      break;
+    case MemAddrModeKind::e:
+      printARIPDMem(MI, OpNo, OS);
+      break;
+    case MemAddrModeKind::p:
+      printARIDMem(MI, OpNo, OS);
+      break;
+    case MemAddrModeKind::f:
+    case MemAddrModeKind::F:
+      printARIIMem(MI, OpNo, OS);
+      break;
+    case MemAddrModeKind::k:
+      printPCIMem(MI, 0, OpNo, OS);
+      break;
+    case MemAddrModeKind::q:
+      printPCDMem(MI, 0, OpNo, OS);
+      break;
+    case MemAddrModeKind::b:
+      printAbsMem(MI, OpNo, OS);
+      break;
+    default:
+      llvm_unreachable("Unrecognized memory addressing mode");
+    }
+    return false;
+  case MachineOperand::MO_GlobalAddress:
+    PrintSymbolOperand(MO, OS);
+    return false;
+  case MachineOperand::MO_BlockAddress:
+    GetBlockAddressSymbol(MO.getBlockAddress())->print(OS, MAI);
+    return false;
+  case MachineOperand::MO_Register:
+    // This is a special case where it is treated as a memory reference, with
+    // the register holding the address value. Thus, we print it as ARI here.
+    if (M68kII::isAddressRegister(MO.getReg())) {
+      printARIMem(MI, OpNo, OS);
+      return false;
+    }
+    break;
+  default:
+    break;
+  }
+  return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
+}
+
 void M68kAsmPrinter::emitInstruction(const MachineInstr *MI) {
   M68k_MC::verifyInstructionPredicates(MI->getOpcode(),
                                        getSubtargetInfo().getFeatureBits());

diff  --git a/llvm/lib/Target/M68k/M68kAsmPrinter.h b/llvm/lib/Target/M68k/M68kAsmPrinter.h
index 1a76e3bf4e276..7b4dbfef58c57 100644
--- a/llvm/lib/Target/M68k/M68kAsmPrinter.h
+++ b/llvm/lib/Target/M68k/M68kAsmPrinter.h
@@ -16,6 +16,7 @@
 
 #include "M68kMCInstLower.h"
 #include "M68kTargetMachine.h"
+#include "MCTargetDesc/M68kMemOperandPrinter.h"
 
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/MC/MCStreamer.h"
@@ -34,12 +35,19 @@ class raw_ostream;
 class M68kSubtarget;
 class M68kMachineFunctionInfo;
 
-class LLVM_LIBRARY_VISIBILITY M68kAsmPrinter : public AsmPrinter {
+class LLVM_LIBRARY_VISIBILITY M68kAsmPrinter
+    : public AsmPrinter,
+      public M68kMemOperandPrinter<M68kAsmPrinter, MachineInstr> {
+
+  friend class M68kMemOperandPrinter;
 
   void EmitInstrWithMacroNoAT(const MachineInstr *MI);
 
   void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS);
 
+  void printDisp(const MachineInstr *MI, unsigned OpNum, raw_ostream &OS);
+  void printAbsMem(const MachineInstr *MI, unsigned OpNum, raw_ostream &OS);
+
 public:
   const M68kSubtarget *Subtarget;
   const M68kMachineFunctionInfo *MMFI;
@@ -57,6 +65,8 @@ class LLVM_LIBRARY_VISIBILITY M68kAsmPrinter : public AsmPrinter {
 
   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                        const char *ExtraCode, raw_ostream &OS) override;
+  bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+                             const char *ExtraCode, raw_ostream &OS) override;
 
   void emitInstruction(const MachineInstr *MI) override;
   void emitFunctionBodyStart() override;

diff  --git a/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp b/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
index f8335f3dcd770..346470ed60d80 100644
--- a/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
+++ b/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
@@ -227,6 +227,9 @@ class M68kDAGToDAGISel : public SelectionDAGISel {
   bool SelectPCD(SDNode *Parent, SDValue N, SDValue &Imm);
   bool SelectPCI(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Index);
 
+  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
+                                    std::vector<SDValue> &OutOps) override;
+
   // If Address Mode represents Frame Index store FI in Disp and
   // Displacement bit size in Base. These values are read symmetrically by
   // M68kRegisterInfo::eliminateFrameIndex method
@@ -931,3 +934,74 @@ bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
 
   return false;
 }
+
+bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
+    const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
+  // In order to tell AsmPrinter the exact addressing mode we select here, which
+  // might comprise of multiple SDValues (hence MachineOperands), a 32-bit
+  // immediate value is prepended to the list of selected SDValues to indicate
+  // the addressing mode kind.
+  using AMK = M68k::MemAddrModeKind;
+  auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {
+    Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);
+    return true;
+  };
+
+  switch (ConstraintID) {
+  // Generic memory operand.
+  case InlineAsm::Constraint_m: {
+    // Try every supported (memory) addressing modes.
+    SDValue Operands[4];
+
+    // TODO: The ordering of the following SelectXXX is relatively...arbitrary,
+    // right now we simply sort them by descending complexity. Maybe we should
+    // adjust this by code model and/or relocation mode in the future.
+    if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&
+        addKind(Operands[0], AMK::f)) {
+      OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
+      return false;
+    }
+
+    if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&
+         addKind(Operands[0], AMK::k)) ||
+        (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&
+         addKind(Operands[0], AMK::p))) {
+      OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
+      return false;
+    }
+
+    if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
+        (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
+        (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
+      OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
+      return false;
+    }
+
+    return true;
+  }
+  // 'Q': Address register indirect addressing.
+  case InlineAsm::Constraint_Q: {
+    SDValue AMKind, Base;
+    // 'j' addressing mode.
+    // TODO: Add support for 'o' and 'e' after their
+    // select functions are implemented.
+    if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {
+      OutOps.insert(OutOps.end(), {AMKind, Base});
+      return false;
+    }
+    return true;
+  }
+  // 'U': Address register indirect w/ constant offset addressing.
+  case InlineAsm::Constraint_Um: {
+    SDValue AMKind, Base, Offset;
+    // 'p' addressing mode.
+    if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {
+      OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
+      return false;
+    }
+    return true;
+  }
+  default:
+    return true;
+  }
+}

diff  --git a/llvm/lib/Target/M68k/M68kISelLowering.cpp b/llvm/lib/Target/M68k/M68kISelLowering.cpp
index c9bbb23f31df8..8fce8bcba548e 100644
--- a/llvm/lib/Target/M68k/M68kISelLowering.cpp
+++ b/llvm/lib/Target/M68k/M68kISelLowering.cpp
@@ -201,6 +201,14 @@ M68kTargetLowering::getExceptionSelectorRegister(const Constant *) const {
   return M68k::D1;
 }
 
+unsigned
+M68kTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const {
+  return StringSwitch<unsigned>(ConstraintCode)
+      .Case("Q", InlineAsm::Constraint_Q)
+      .Case("U", InlineAsm::Constraint_Um) // We borrow Constraint_Um for 'U'.
+      .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
+}
+
 EVT M68kTargetLowering::getSetCCResultType(const DataLayout &DL,
                                            LLVMContext &Context, EVT VT) const {
   // M68k SETcc producess either 0x00 or 0xFF
@@ -2764,6 +2772,9 @@ M68kTargetLowering::getConstraintType(StringRef Constraint) const {
           break;
         }
       break;
+    case 'Q':
+    case 'U':
+      return C_Memory;
     default:
       break;
     }

diff  --git a/llvm/lib/Target/M68k/M68kISelLowering.h b/llvm/lib/Target/M68k/M68kISelLowering.h
index e6242f76c56fb..f998f60f4c9d9 100644
--- a/llvm/lib/Target/M68k/M68kISelLowering.h
+++ b/llvm/lib/Target/M68k/M68kISelLowering.h
@@ -187,6 +187,8 @@ class M68kTargetLowering : public TargetLowering {
   Register
   getExceptionSelectorRegister(const Constant *PersonalityFn) const override;
 
+  unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override;
+
 private:
   unsigned GetAlignedArgumentStackSize(unsigned StackSize,
                                        SelectionDAG &DAG) const;

diff  --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h b/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
index bd2964ab84b19..3703d86519de6 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
@@ -48,6 +48,32 @@ enum { MemDisp = 0, MemBase = 1, MemIndex = 2, MemOuter = 3 };
 /// ([bd,PC,Xn],od)
 enum { PCRelDisp = 0, PCRelIndex = 1, PCRelOuter = 2 };
 
+enum class MemAddrModeKind : unsigned {
+  j = 1, // (An)
+  o,     // (An)+
+  e,     // -(An)
+  p,     // (d,An)
+  f,     // (d,An,Xn.L)
+  F,     // (d,An,Xn.W)
+  g,     // (d,An,Xn.L,SCALE)
+  G,     // (d,An,Xn.W,SCALE)
+  u,     // ([bd,An],Xn.L,SCALE,od)
+  U,     // ([bd,An],Xn.W,SCALE,od)
+  v,     // ([bd,An,Xn.L,SCALE],od)
+  V,     // ([bd,An,Xn.W,SCALE],od)
+  b,     // abs.L
+  B,     // abs.W
+  q,     // (d,PC)
+  k,     // (d,PC,Xn.L)
+  K,     // (d,PC,Xn.W)
+  l,     // (d,PC,Xn.L,SCALE)
+  L,     // (d,PC,Xn.W,SCALE)
+  x,     // ([bd,PC],Xn.L,SCALE,od)
+  X,     // ([bd,PC],Xn.W,SCALE,od)
+  y,     // ([bd,PC,Xn.L,SCALE],od)
+  Y      // ([bd,PC,Xn.W,SCALE],od)
+};
+
 // On a LE host:
 // MSB                   LSB    MSB                   LSB
 // | 0x12 0x34 | 0xAB 0xCD | -> | 0xAB 0xCD | 0x12 0x34 |

diff  --git a/llvm/test/CodeGen/M68k/inline-asm.ll b/llvm/test/CodeGen/M68k/inline-asm.ll
index 6f9260f23cff6..72cdfb78e82d3 100644
--- a/llvm/test/CodeGen/M68k/inline-asm.ll
+++ b/llvm/test/CodeGen/M68k/inline-asm.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=m68k < %s -o - | FileCheck %s
 
+ at g = internal global i32 10, align 4
+
 ; This function is primarily testing constant constraints that can NOT
 ; be easily checked by Clang. For example, 'K' and 'M' are both
 ; constraints for values that are outside certain numerical range.
@@ -120,3 +122,33 @@ entry:
   ret void
 }
 
+define void @memory_constraints() {
+; CHECK-LABEL: memory_constraints:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    .cfi_def_cfa_offset -8
+; CHECK-NEXT:    ;APP
+; CHECK-NEXT:    move.l (0,%sp), %d1
+; CHECK-NEXT:    ;NO_APP
+; CHECK-NEXT:    ;APP
+; CHECK-NEXT:    move.l (g,%pc), %d2
+; CHECK-NEXT:    ;NO_APP
+; CHECK-NEXT:    lea (0,%sp), %a0
+; CHECK-NEXT:    ;APP
+; CHECK-NEXT:    move.l (%a0), %d3
+; CHECK-NEXT:    ;NO_APP
+; CHECK-NEXT:    ;APP
+; CHECK-NEXT:    move.l (0,%sp), %d4
+; CHECK-NEXT:    ;NO_APP
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+  %x = alloca i32, align 4
+  call void asm sideeffect "move.l $0, %d1", "*m"(ptr elementtype(i32) %x)
+  call void asm sideeffect "move.l $0, %d2", "*m"(ptr elementtype(i32) @g)
+  call void asm sideeffect "move.l $0, %d3", "*Q"(ptr elementtype(i32) %x)
+  call void asm sideeffect "move.l $0, %d4", "*U"(ptr elementtype(i32) %x)
+  ret void
+}
+


        


More information about the llvm-commits mailing list