[llvm] dc2d0d5 - [Xtensa] Add basic support for inline asm constraints. (#108986)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 25 04:03:02 PDT 2024


Author: Andrei Safronov
Date: 2024-09-25T14:02:58+03:00
New Revision: dc2d0d5e1a4e7a7524f68aa9739acf22bee13b9e

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

LOG: [Xtensa] Add basic support for inline asm constraints. (#108986)

Added: 
    llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll
    llvm/test/CodeGen/Xtensa/inline-asm-mem-constraint.ll
    llvm/test/CodeGen/Xtensa/inline-asm.ll

Modified: 
    llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
    llvm/lib/Target/Xtensa/XtensaAsmPrinter.h
    llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
    llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
    llvm/lib/Target/Xtensa/XtensaISelLowering.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
index 3f99387f759d93..db86637ecf83f3 100644
--- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "XtensaAsmPrinter.h"
+#include "MCTargetDesc/XtensaInstPrinter.h"
 #include "MCTargetDesc/XtensaMCExpr.h"
 #include "MCTargetDesc/XtensaTargetStreamer.h"
 #include "TargetInfo/XtensaTargetInfo.h"
@@ -157,6 +158,57 @@ void XtensaAsmPrinter::emitConstantPool() {
   OutStreamer->popSection();
 }
 
+void XtensaAsmPrinter::printOperand(const MachineInstr *MI, int OpNo,
+                                    raw_ostream &O) {
+  const MachineOperand &MO = MI->getOperand(OpNo);
+
+  switch (MO.getType()) {
+  case MachineOperand::MO_Register:
+  case MachineOperand::MO_Immediate: {
+    MCOperand MC = lowerOperand(MI->getOperand(OpNo));
+    XtensaInstPrinter::printOperand(MC, O);
+    break;
+  }
+  default:
+    llvm_unreachable("unknown operand type");
+  }
+}
+
+bool XtensaAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+                                       const char *ExtraCode, raw_ostream &O) {
+  // Print the operand if there is no operand modifier.
+  if (!ExtraCode || !ExtraCode[0]) {
+    printOperand(MI, OpNo, O);
+    return false;
+  }
+
+  // Fallback to the default implementation.
+  return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
+}
+
+bool XtensaAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+                                             unsigned OpNo,
+                                             const char *ExtraCode,
+                                             raw_ostream &OS) {
+  if (ExtraCode && ExtraCode[0])
+    return true; // Unknown modifier.
+
+  assert(OpNo + 1 < MI->getNumOperands() && "Insufficient operands");
+
+  const MachineOperand &Base = MI->getOperand(OpNo);
+  const MachineOperand &Offset = MI->getOperand(OpNo + 1);
+
+  assert(Base.isReg() &&
+         "Unexpected base pointer for inline asm memory operand.");
+  assert(Offset.isImm() && "Unexpected offset for inline asm memory operand.");
+
+  OS << XtensaInstPrinter::getRegisterName(Base.getReg());
+  OS << ", ";
+  OS << Offset.getImm();
+
+  return false;
+}
+
 MCSymbol *
 XtensaAsmPrinter::GetConstantPoolIndexSymbol(const MachineOperand &MO) const {
   // Create a symbol for the name.

diff  --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h
index f9cf5ae8c9f656..1137309cd9a450 100644
--- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h
+++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h
@@ -42,6 +42,14 @@ class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter {
 
   void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
 
+  void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
+
+  bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+                       const char *ExtraCode, raw_ostream &O) override;
+
+  bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+                             const char *ExtraCode, raw_ostream &OS) override;
+
   MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const;
 
   MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const;

diff  --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
index 6f6d3342fcd7f2..af1110487b4274 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
@@ -33,6 +33,10 @@ class XtensaDAGToDAGISel : public SelectionDAGISel {
 
   void Select(SDNode *Node) override;
 
+  bool SelectInlineAsmMemoryOperand(const SDValue &Op,
+                                    InlineAsm::ConstraintCode ConstraintID,
+                                    std::vector<SDValue> &OutOps) override;
+
   // For load/store instructions generate (base+offset) pair from
   // memory address. The offset must be a multiple of scale argument.
   bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset,
@@ -212,3 +216,22 @@ void XtensaDAGToDAGISel::Select(SDNode *Node) {
 
   SelectCode(Node);
 }
+
+bool XtensaDAGToDAGISel::SelectInlineAsmMemoryOperand(
+    const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
+    std::vector<SDValue> &OutOps) {
+  switch (ConstraintID) {
+  default:
+    llvm_unreachable("Unexpected asm memory constraint");
+  case InlineAsm::ConstraintCode::m: {
+    SDValue Base, Offset;
+
+    selectMemRegAddr(Op, Base, Offset, 4);
+    OutOps.push_back(Base);
+    OutOps.push_back(Offset);
+
+    return false;
+  }
+  }
+  return false;
+}

diff  --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index bc1360e2123075..670930e99334f2 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -142,6 +142,74 @@ bool XtensaTargetLowering::isOffsetFoldingLegal(
   return false;
 }
 
+//===----------------------------------------------------------------------===//
+// Inline asm support
+//===----------------------------------------------------------------------===//
+TargetLowering::ConstraintType
+XtensaTargetLowering::getConstraintType(StringRef Constraint) const {
+  if (Constraint.size() == 1) {
+    switch (Constraint[0]) {
+    case 'r':
+      return C_RegisterClass;
+    default:
+      break;
+    }
+  }
+  return TargetLowering::getConstraintType(Constraint);
+}
+
+TargetLowering::ConstraintWeight
+XtensaTargetLowering::getSingleConstraintMatchWeight(
+    AsmOperandInfo &Info, const char *Constraint) const {
+  ConstraintWeight Weight = CW_Invalid;
+  Value *CallOperandVal = Info.CallOperandVal;
+  // If we don't have a value, we can't do a match,
+  // but allow it at the lowest weight.
+  if (!CallOperandVal)
+    return CW_Default;
+
+  Type *Ty = CallOperandVal->getType();
+
+  // Look at the constraint type.
+  switch (*Constraint) {
+  default:
+    Weight = TargetLowering::getSingleConstraintMatchWeight(Info, Constraint);
+    break;
+  case 'r':
+    if (Ty->isIntegerTy())
+      Weight = CW_Register;
+    break;
+  }
+  return Weight;
+}
+
+std::pair<unsigned, const TargetRegisterClass *>
+XtensaTargetLowering::getRegForInlineAsmConstraint(
+    const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
+  if (Constraint.size() == 1) {
+    // GCC Constraint Letters
+    switch (Constraint[0]) {
+    default:
+      break;
+    case 'r': // General-purpose register
+      return std::make_pair(0U, &Xtensa::ARRegClass);
+    }
+  }
+  return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
+}
+
+void XtensaTargetLowering::LowerAsmOperandForConstraint(
+    SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
+    SelectionDAG &DAG) const {
+  SDLoc DL(Op);
+
+  // Only support length 1 constraints for now.
+  if (Constraint.size() > 1)
+    return;
+
+  TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
+}
+
 //===----------------------------------------------------------------------===//
 // Calling conventions
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
index 2a878e45047d21..f1cd00c41437a4 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
@@ -76,6 +76,21 @@ class XtensaTargetLowering : public TargetLowering {
 
   const char *getTargetNodeName(unsigned Opcode) const override;
 
+  std::pair<unsigned, const TargetRegisterClass *>
+  getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+                               StringRef Constraint, MVT VT) const override;
+
+  TargetLowering::ConstraintType
+  getConstraintType(StringRef Constraint) const override;
+
+  TargetLowering::ConstraintWeight
+  getSingleConstraintMatchWeight(AsmOperandInfo &Info,
+                                 const char *Constraint) const override;
+
+  void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint,
+                                    std::vector<SDValue> &Ops,
+                                    SelectionDAG &DAG) const override;
+
   SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
 
   SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,

diff  --git a/llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll b/llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll
new file mode 100644
index 00000000000000..2a436dd156dd77
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: not llc --mtriple=xtensa < %s 2>&1 | FileCheck %s
+
+define void @constraint_f() nounwind {
+; CHECK: error: unknown asm constraint 'f'
+  tail call void asm "addi a1, a1, $0", "f"(i32 1)
+  ret void
+}
+
+define i32 @register_a100(i32 %a) nounwind {
+; CHECK: error: couldn't allocate input reg for constraint '{$a100}'
+  %1 = tail call i32 asm "addi $0, $1, 1", "=r,{$a100}"(i32 %a)
+  ret i32 %1
+}

diff  --git a/llvm/test/CodeGen/Xtensa/inline-asm-mem-constraint.ll b/llvm/test/CodeGen/Xtensa/inline-asm-mem-constraint.ll
new file mode 100644
index 00000000000000..4b27ba9337f880
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/inline-asm-mem-constraint.ll
@@ -0,0 +1,46 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=xtensa < %s | FileCheck %s --check-prefix=XTENSA
+
+define i32 @m_offset_0(ptr %p) nounwind {
+; XTENSA-LABEL: m_offset_0:
+; XTENSA:         #APP
+; XTENSA-NEXT:    l32i a2, a2, 0
+; XTENSA-NEXT:    #NO_APP
+; XTENSA-NEXT:    ret
+  %1 = call i32 asm "l32i $0, $1", "=r,*m"(ptr elementtype(i32) %p)
+  ret i32 %1
+}
+
+define i32 @m_offset_1020(ptr %p) nounwind {
+; XTENSA-LABEL: m_offset_1020:
+; XTENSA:         #APP
+; XTENSA-NEXT:    l32i a2, a2, 1020
+; XTENSA-NEXT:    #NO_APP
+; XTENSA-NEXT:    ret
+  %1 = getelementptr inbounds i8, ptr %p, i32 1020
+  %2 = call i32 asm "l32i $0, $1", "=r,*m"(ptr elementtype(i32) %1)
+  ret i32 %2
+}
+
+define i8 @m_i8_offset_7(ptr %p) nounwind {
+; XTENSA-LABEL: m_i8_offset_7:
+; XTENSA:         addi a8, a2, 7
+; XTENSA-NEXT:    #APP
+; XTENSA-NEXT:    l8ui a2, a8, 0
+; XTENSA-NEXT:    #NO_APP
+; XTENSA-NEXT:    ret
+  %1 = getelementptr inbounds i8, ptr %p, i32 7
+  %2 = call i8 asm "l8ui $0, $1", "=r,*m"(ptr elementtype(i8) %1)
+  ret i8 %2
+}
+
+define i16 @m_i16_offset_10(ptr %p) nounwind {
+; XTENSA-LABEL: m_i16_offset_10:
+; XTENSA:         #APP
+; XTENSA-NEXT:    l16si a2, a2, 20
+; XTENSA-NEXT:    #NO_APP
+; XTENSA-NEXT:    ret
+  %1 = getelementptr inbounds i16, ptr %p, i32 10
+  %2 = call i16 asm "l16si $0, $1", "=r,*m"(ptr elementtype(i16) %1)
+  ret i16 %2
+}

diff  --git a/llvm/test/CodeGen/Xtensa/inline-asm.ll b/llvm/test/CodeGen/Xtensa/inline-asm.ll
new file mode 100644
index 00000000000000..748f5f857acfd8
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/inline-asm.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=xtensa < %s \
+; RUN: | FileCheck -check-prefix=XTENSA %s
+
+ at gi = external global i32
+
+define i32 @constraint_r(i32 %a) {
+; XTENSA-LABEL: constraint_r:
+; XTENSA:         l32r a8, .LCPI0_0
+; XTENSA-NEXT:    l32i a8, a8, 0
+; XTENSA-NEXT:    #APP
+; XTENSA-NEXT:    add a2, a2, a8
+; XTENSA-NEXT:    #NO_APP
+; XTENSA-NEXT:    ret
+  %1 = load i32, ptr @gi
+  %2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 %a, i32 %1)
+  ret i32 %2
+}
+
+define i32 @constraint_i(i32 %a) {
+; XTENSA-LABEL: constraint_i:
+; XTENSA:         #APP
+; XTENSA-NEXT:    addi a2, a2, 113
+; XTENSA-NEXT:    #NO_APP
+; XTENSA-NEXT:    ret
+  %1 = load i32, ptr @gi
+  %2 = tail call i32 asm "addi $0, $1, $2", "=r,r,i"(i32 %a, i32 113)
+  ret i32 %2
+}
+
+define i32 @explicit_register_a3(i32 %a) nounwind {
+; XTENSA-LABEL: explicit_register_a3:
+; XTENSA:         or a3, a2, a2
+; XTENSA-NEXT:    #APP
+; XTENSA-NEXT:    addi a2, a3, 1
+; XTENSA-NEXT:    #NO_APP
+; XTENSA-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 1", "=r,{a3}"(i32 %a)
+  ret i32 %1
+}


        


More information about the llvm-commits mailing list