[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