[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