[llvm] [Xtensa] Add basic support for inline asm constraints. (PR #108986)
Andrei Safronov via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 17 08:02:18 PDT 2024
https://github.com/andreisfr created https://github.com/llvm/llvm-project/pull/108986
None
>From 9ee86ede127e9ed51d6a2dace2e3221eaaa97b83 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Tue, 17 Sep 2024 17:51:31 +0300
Subject: [PATCH] [Xtensa] Add basic support for inline asm constraints.
---
llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 52 ++++++++++++++
llvm/lib/Target/Xtensa/XtensaAsmPrinter.h | 8 +++
llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 22 ++++++
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 68 +++++++++++++++++++
llvm/lib/Target/Xtensa/XtensaISelLowering.h | 15 ++++
.../Xtensa/inline-asm-mem-constraint.ll | 23 +++++++
llvm/test/CodeGen/Xtensa/inline-asm.ll | 29 ++++++++
7 files changed, 217 insertions(+)
create mode 100644 llvm/test/CodeGen/Xtensa/inline-asm-mem-constraint.ll
create mode 100644 llvm/test/CodeGen/Xtensa/inline-asm.ll
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..6b56016063d49d 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,21 @@ 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..3e7064be4096f8 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 == NULL)
+ 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-mem-constraint.ll b/llvm/test/CodeGen/Xtensa/inline-asm-mem-constraint.ll
new file mode 100644
index 00000000000000..73c731f3acd123
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/inline-asm-mem-constraint.ll
@@ -0,0 +1,23 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=xtensa --verify-machineinstrs < %s | FileCheck %s --check-prefix=LA32
+
+define i32 @m_offset_0(ptr %p) nounwind {
+; LA32-LABEL: m_offset_0:
+; LA32: #APP
+; LA32-NEXT: l32i a2, a2, 0
+; LA32-NEXT: #NO_APP
+; LA32-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 {
+; LA32-LABEL: m_offset_1020:
+; LA32: #APP
+; LA32-NEXT: l32i a2, a2, 1020
+; LA32-NEXT: #NO_APP
+; LA32-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
+}
diff --git a/llvm/test/CodeGen/Xtensa/inline-asm.ll b/llvm/test/CodeGen/Xtensa/inline-asm.ll
new file mode 100644
index 00000000000000..e080d01197843c
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/inline-asm.ll
@@ -0,0 +1,29 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=xtensa -verify-machineinstrs < %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, i32* @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, i32* @gi
+ %2 = tail call i32 asm "addi $0, $1, $2", "=r,r,i"(i32 %a, i32 113)
+ ret i32 %2
+}
More information about the llvm-commits
mailing list