aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Safronov <safronov@espressif.com>2024-04-24 01:00:59 +0300
committerGitHub <noreply@github.com>2024-04-24 00:00:59 +0200
commit36209d366d833263d71df328ecca75cf144b1893 (patch)
treeb77b2abda487df97e37871c81e739fd301dfb84a
parent418212089e95e2d39d2997699a149a09d4c5185c (diff)
downloadllvm-36209d366d833263d71df328ecca75cf144b1893.zip
llvm-36209d366d833263d71df328ecca75cf144b1893.tar.gz
llvm-36209d366d833263d71df328ecca75cf144b1893.tar.bz2
[Xtensa] Implement base CallConvention. (#83280)
Implement base Calling Convention functionality. Implement stack load/store register operations. Implement call lowering.
-rw-r--r--llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp131
-rw-r--r--llvm/lib/Target/Xtensa/CMakeLists.txt3
-rw-r--r--llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt1
-rw-r--r--llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp28
-rw-r--r--llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp119
-rw-r--r--llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h58
-rw-r--r--llvm/lib/Target/Xtensa/Xtensa.td6
-rw-r--r--llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp148
-rw-r--r--llvm/lib/Target/Xtensa/XtensaAsmPrinter.h13
-rw-r--r--llvm/lib/Target/Xtensa/XtensaCallingConv.td24
-rw-r--r--llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp207
-rw-r--r--llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h263
-rw-r--r--llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp20
-rw-r--r--llvm/lib/Target/Xtensa/XtensaFrameLowering.h4
-rw-r--r--llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp52
-rw-r--r--llvm/lib/Target/Xtensa/XtensaISelLowering.cpp501
-rw-r--r--llvm/lib/Target/Xtensa/XtensaISelLowering.h44
-rw-r--r--llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp137
-rw-r--r--llvm/lib/Target/Xtensa/XtensaInstrInfo.h29
-rw-r--r--llvm/lib/Target/Xtensa/XtensaInstrInfo.td55
-rw-r--r--llvm/lib/Target/Xtensa/XtensaOperands.td2
-rw-r--r--llvm/lib/Target/Xtensa/XtensaOperators.td36
-rw-r--r--llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp74
-rw-r--r--llvm/lib/Target/Xtensa/XtensaUtils.cpp59
-rw-r--r--llvm/lib/Target/Xtensa/XtensaUtils.h27
-rw-r--r--llvm/test/CodeGen/Xtensa/call.ll49
-rw-r--r--llvm/test/CodeGen/Xtensa/calling-conv.ll78
-rw-r--r--llvm/test/CodeGen/Xtensa/constantpool.ll28
-rw-r--r--llvm/test/CodeGen/Xtensa/stack-access.ll35
-rw-r--r--llvm/test/MC/Xtensa/Core/invalid.s4
-rw-r--r--llvm/test/MC/Xtensa/directive-literal.s42
-rw-r--r--llvm/test/MC/Xtensa/invalid-literal.s10
32 files changed, 2270 insertions, 17 deletions
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 1fa00af..eaf0466 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -8,7 +8,9 @@
//
//===----------------------------------------------------------------------===//
+#include "MCTargetDesc/XtensaMCExpr.h"
#include "MCTargetDesc/XtensaMCTargetDesc.h"
+#include "MCTargetDesc/XtensaTargetStreamer.h"
#include "TargetInfo/XtensaTargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -22,6 +24,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Casting.h"
@@ -35,6 +38,12 @@ class XtensaAsmParser : public MCTargetAsmParser {
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
+ XtensaTargetStreamer &getTargetStreamer() {
+ MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
+ return static_cast<XtensaTargetStreamer &>(TS);
+ }
+
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
@@ -45,6 +54,9 @@ class XtensaAsmParser : public MCTargetAsmParser {
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
unsigned Kind) override;
+ bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI);
+
// Auto-generated instruction matching functions
#define GET_ASSEMBLER_HEADER
#include "XtensaGenAsmMatcher.inc"
@@ -62,6 +74,7 @@ class XtensaAsmParser : public MCTargetAsmParser {
return ParseStatus::NoMatch;
}
ParseStatus parsePCRelTarget(OperandVector &Operands);
+ bool parseLiteralDirective(SMLoc L);
public:
enum XtensaMatchResultTy {
@@ -148,7 +161,8 @@ public:
bool isImm12() const { return isImm(-2048, 2047); }
- bool isImm12m() const { return isImm(-2048, 2047); }
+ // Convert MOVI to literal load, when immediate is not in range (-2048, 2047)
+ bool isImm12m() const { return Kind == Immediate; }
bool isOffset4m32() const {
return isImm(0, 60) &&
@@ -348,6 +362,69 @@ static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands,
return Loc;
}
+bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
+ MCStreamer &Out,
+ const MCSubtargetInfo *STI) {
+ Inst.setLoc(IDLoc);
+ const unsigned Opcode = Inst.getOpcode();
+ switch (Opcode) {
+ case Xtensa::L32R: {
+ const MCSymbolRefExpr *OpExpr =
+ static_cast<const MCSymbolRefExpr *>(Inst.getOperand(1).getExpr());
+ XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None;
+ const MCExpr *NewOpExpr = XtensaMCExpr::create(OpExpr, Kind, getContext());
+ Inst.getOperand(1).setExpr(NewOpExpr);
+ break;
+ }
+ case Xtensa::MOVI: {
+ XtensaTargetStreamer &TS = this->getTargetStreamer();
+
+ // Expand MOVI operand
+ if (!Inst.getOperand(1).isExpr()) {
+ uint64_t ImmOp64 = Inst.getOperand(1).getImm();
+ int32_t Imm = ImmOp64;
+ if (!isInt<12>(Imm)) {
+ XtensaTargetStreamer &TS = this->getTargetStreamer();
+ MCInst TmpInst;
+ TmpInst.setLoc(IDLoc);
+ TmpInst.setOpcode(Xtensa::L32R);
+ const MCExpr *Value = MCConstantExpr::create(ImmOp64, getContext());
+ MCSymbol *Sym = getContext().createTempSymbol();
+ const MCExpr *Expr = MCSymbolRefExpr::create(
+ Sym, MCSymbolRefExpr::VK_None, getContext());
+ const MCExpr *OpExpr = XtensaMCExpr::create(
+ Expr, XtensaMCExpr::VK_Xtensa_None, getContext());
+ TmpInst.addOperand(Inst.getOperand(0));
+ MCOperand Op1 = MCOperand::createExpr(OpExpr);
+ TmpInst.addOperand(Op1);
+ TS.emitLiteral(Sym, Value, true, IDLoc);
+ Inst = TmpInst;
+ }
+ } else {
+ MCInst TmpInst;
+ TmpInst.setLoc(IDLoc);
+ TmpInst.setOpcode(Xtensa::L32R);
+ const MCExpr *Value = Inst.getOperand(1).getExpr();
+ MCSymbol *Sym = getContext().createTempSymbol();
+ const MCExpr *Expr =
+ MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
+ const MCExpr *OpExpr = XtensaMCExpr::create(
+ Expr, XtensaMCExpr::VK_Xtensa_None, getContext());
+ TmpInst.addOperand(Inst.getOperand(0));
+ MCOperand Op1 = MCOperand::createExpr(OpExpr);
+ TmpInst.addOperand(Op1);
+ Inst = TmpInst;
+ TS.emitLiteral(Sym, Value, true, IDLoc);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out,
@@ -361,6 +438,7 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
default:
break;
case Match_Success:
+ processInstruction(Inst, IDLoc, Out, STI);
Inst.setLoc(IDLoc);
Out.emitInstruction(Inst, getSTI());
return false;
@@ -686,6 +764,57 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info,
return false;
}
+bool XtensaAsmParser::parseLiteralDirective(SMLoc L) {
+ MCAsmParser &Parser = getParser();
+ const MCExpr *Value;
+ SMLoc LiteralLoc = getLexer().getLoc();
+ XtensaTargetStreamer &TS = this->getTargetStreamer();
+
+ if (Parser.parseExpression(Value))
+ return true;
+
+ const MCSymbolRefExpr *SE = dyn_cast<MCSymbolRefExpr>(Value);
+
+ if (!SE)
+ return Error(LiteralLoc, "literal label must be a symbol");
+
+ if (Parser.parseComma())
+ return true;
+
+ SMLoc OpcodeLoc = getLexer().getLoc();
+ if (parseOptionalToken(AsmToken::EndOfStatement))
+ return Error(OpcodeLoc, "expected value");
+
+ if (Parser.parseExpression(Value))
+ return true;
+
+ if (parseEOL())
+ return true;
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(SE->getSymbol().getName());
+
+ TS.emitLiteral(Sym, Value, true, LiteralLoc);
+
+ return false;
+}
+
+ParseStatus XtensaAsmParser::parseDirective(AsmToken DirectiveID) {
+ StringRef IDVal = DirectiveID.getString();
+ SMLoc Loc = getLexer().getLoc();
+
+ if (IDVal == ".literal_position") {
+ XtensaTargetStreamer &TS = this->getTargetStreamer();
+ TS.emitLiteralPosition();
+ return parseEOL();
+ }
+
+ if (IDVal == ".literal") {
+ return parseLiteralDirective(Loc);
+ }
+
+ return ParseStatus::NoMatch;
+}
+
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmParser() {
RegisterMCAsmParser<XtensaAsmParser> X(getTheXtensaTarget());
diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt
index 2064511..726efad 100644
--- a/llvm/lib/Target/Xtensa/CMakeLists.txt
+++ b/llvm/lib/Target/Xtensa/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_TARGET_DEFINITIONS Xtensa.td)
tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer)
+tablegen(LLVM XtensaGenCallingConv.inc -gen-callingconv)
tablegen(LLVM XtensaGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info)
@@ -15,6 +16,7 @@ add_public_tablegen_target(XtensaCommonTableGen)
add_llvm_target(XtensaCodeGen
XtensaAsmPrinter.cpp
+ XtensaConstantPoolValue.cpp
XtensaFrameLowering.cpp
XtensaInstrInfo.cpp
XtensaISelDAGToDAG.cpp
@@ -22,6 +24,7 @@ add_llvm_target(XtensaCodeGen
XtensaRegisterInfo.cpp
XtensaSubtarget.cpp
XtensaTargetMachine.cpp
+ XtensaUtils.cpp
LINK_COMPONENTS
AsmPrinter
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt
index 6841b44..dc12863 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMXtensaDesc
XtensaMCCodeEmitter.cpp
XtensaMCExpr.cpp
XtensaMCTargetDesc.cpp
+ XtensaTargetStreamer.cpp
LINK_COMPONENTS
MC
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
index 48674d1..87ef66b 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
@@ -8,9 +8,10 @@
//
//===----------------------------------------------------------------------===//
#include "XtensaMCTargetDesc.h"
+#include "TargetInfo/XtensaTargetInfo.h"
#include "XtensaInstPrinter.h"
#include "XtensaMCAsmInfo.h"
-#include "TargetInfo/XtensaTargetInfo.h"
+#include "XtensaTargetStreamer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCInstrInfo.h"
@@ -63,16 +64,29 @@ createXtensaMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) {
return createXtensaMCSubtargetInfoImpl(TT, CPU, CPU, FS);
}
+static MCTargetStreamer *
+createXtensaAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
+ MCInstPrinter *InstPrint, bool isVerboseAsm) {
+ return new XtensaTargetAsmStreamer(S, OS);
+}
+
+static MCTargetStreamer *
+createXtensaObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+ return new XtensaTargetELFStreamer(S);
+}
+
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTargetMC() {
// Register the MCAsmInfo.
- TargetRegistry::RegisterMCAsmInfo(getTheXtensaTarget(), createXtensaMCAsmInfo);
+ TargetRegistry::RegisterMCAsmInfo(getTheXtensaTarget(),
+ createXtensaMCAsmInfo);
// Register the MCCodeEmitter.
TargetRegistry::RegisterMCCodeEmitter(getTheXtensaTarget(),
createXtensaMCCodeEmitter);
// Register the MCInstrInfo.
- TargetRegistry::RegisterMCInstrInfo(getTheXtensaTarget(), createXtensaMCInstrInfo);
+ TargetRegistry::RegisterMCInstrInfo(getTheXtensaTarget(),
+ createXtensaMCInstrInfo);
// Register the MCInstPrinter.
TargetRegistry::RegisterMCInstPrinter(getTheXtensaTarget(),
@@ -89,4 +103,12 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTargetMC() {
// Register the MCAsmBackend.
TargetRegistry::RegisterMCAsmBackend(getTheXtensaTarget(),
createXtensaMCAsmBackend);
+
+ // Register the asm target streamer.
+ TargetRegistry::RegisterAsmTargetStreamer(getTheXtensaTarget(),
+ createXtensaAsmTargetStreamer);
+
+ // Register the ELF target streamer.
+ TargetRegistry::RegisterObjectTargetStreamer(
+ getTheXtensaTarget(), createXtensaObjectTargetStreamer);
}
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
new file mode 100644
index 0000000..0ea70cf
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
@@ -0,0 +1,119 @@
+//===-- XtensaTargetStreamer.cpp - Xtensa Target Streamer Methods ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides Xtensa specific target streamer methods.
+//
+//===----------------------------------------------------------------------===//
+
+#include "XtensaTargetStreamer.h"
+#include "XtensaInstPrinter.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+static std::string getLiteralSectionName(StringRef CSectionName) {
+ std::size_t Pos = CSectionName.find(".text");
+ std::string SectionName;
+ if (Pos != std::string::npos) {
+ SectionName = CSectionName.substr(0, Pos);
+
+ if (Pos > 0)
+ SectionName += ".text";
+
+ CSectionName = CSectionName.drop_front(Pos);
+ CSectionName.consume_front(".text");
+
+ SectionName += ".literal";
+ SectionName += CSectionName;
+ } else {
+ SectionName = CSectionName;
+ SectionName += ".literal";
+ }
+ return SectionName;
+}
+
+XtensaTargetStreamer::XtensaTargetStreamer(MCStreamer &S)
+ : MCTargetStreamer(S) {}
+
+XtensaTargetAsmStreamer::XtensaTargetAsmStreamer(MCStreamer &S,
+ formatted_raw_ostream &OS)
+ : XtensaTargetStreamer(S), OS(OS) {}
+
+void XtensaTargetAsmStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value,
+ bool SwitchLiteralSection, SMLoc L) {
+ SmallString<60> Str;
+ raw_svector_ostream LiteralStr(Str);
+
+ LiteralStr << "\t.literal " << LblSym->getName() << ", ";
+
+ if (auto CE = dyn_cast<MCConstantExpr>(Value)) {
+ LiteralStr << CE->getValue() << "\n";
+ } else if (auto SRE = dyn_cast<MCSymbolRefExpr>(Value)) {
+ const MCSymbol &Sym = SRE->getSymbol();
+ LiteralStr << Sym.getName() << "\n";
+ } else {
+ llvm_unreachable("unexpected constant pool entry type");
+ }
+
+ OS << LiteralStr.str();
+}
+
+void XtensaTargetAsmStreamer::emitLiteralPosition() {
+ OS << "\t.literal_position\n";
+}
+
+void XtensaTargetAsmStreamer::startLiteralSection(MCSection *BaseSection) {
+ emitLiteralPosition();
+}
+
+XtensaTargetELFStreamer::XtensaTargetELFStreamer(MCStreamer &S)
+ : XtensaTargetStreamer(S) {}
+
+void XtensaTargetELFStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value,
+ bool SwitchLiteralSection, SMLoc L) {
+ MCStreamer &OutStreamer = getStreamer();
+ if (SwitchLiteralSection) {
+ MCContext &Context = OutStreamer.getContext();
+ auto *CS = static_cast<MCSectionELF *>(OutStreamer.getCurrentSectionOnly());
+ std::string SectionName = getLiteralSectionName(CS->getName());
+
+ MCSection *ConstSection = Context.getELFSection(
+ SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);
+
+ OutStreamer.pushSection();
+ OutStreamer.switchSection(ConstSection);
+ }
+
+ OutStreamer.emitLabel(LblSym, L);
+ OutStreamer.emitValue(Value, 4, L);
+
+ if (SwitchLiteralSection) {
+ OutStreamer.popSection();
+ }
+}
+
+void XtensaTargetELFStreamer::startLiteralSection(MCSection *BaseSection) {
+ MCContext &Context = getStreamer().getContext();
+
+ std::string SectionName = getLiteralSectionName(BaseSection->getName());
+
+ MCSection *ConstSection = Context.getELFSection(
+ SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);
+
+ ConstSection->setAlignment(Align(4));
+}
+
+MCELFStreamer &XtensaTargetELFStreamer::getStreamer() {
+ return static_cast<MCELFStreamer &>(Streamer);
+}
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h
new file mode 100644
index 0000000..817940e
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h
@@ -0,0 +1,58 @@
+//===-- XtensaTargetStreamer.h - Xtensa Target Streamer --------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_XTENSA_XTENSATARGETSTREAMER_H
+#define LLVM_LIB_TARGET_XTENSA_XTENSATARGETSTREAMER_H
+
+#include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/SMLoc.h"
+
+namespace llvm {
+class formatted_raw_ostream;
+
+class XtensaTargetStreamer : public MCTargetStreamer {
+public:
+ XtensaTargetStreamer(MCStreamer &S);
+
+ // Emit literal label and literal Value to the literal section. If literal
+ // section is not switched yet (SwitchLiteralSection is true) then switch to
+ // literal section.
+ virtual void emitLiteral(MCSymbol *LblSym, const MCExpr *Value,
+ bool SwitchLiteralSection, SMLoc L = SMLoc()) = 0;
+
+ virtual void emitLiteralPosition() = 0;
+
+ // Switch to the literal section. The BaseSection name is used to construct
+ // literal section name.
+ virtual void startLiteralSection(MCSection *BaseSection) = 0;
+};
+
+class XtensaTargetAsmStreamer : public XtensaTargetStreamer {
+ formatted_raw_ostream &OS;
+
+public:
+ XtensaTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
+ void emitLiteral(MCSymbol *LblSym, const MCExpr *Value,
+ bool SwitchLiteralSection, SMLoc L) override;
+ void emitLiteralPosition() override;
+ void startLiteralSection(MCSection *Section) override;
+};
+
+class XtensaTargetELFStreamer : public XtensaTargetStreamer {
+public:
+ XtensaTargetELFStreamer(MCStreamer &S);
+ MCELFStreamer &getStreamer();
+ void emitLiteral(MCSymbol *LblSym, const MCExpr *Value,
+ bool SwitchLiteralSection, SMLoc L) override;
+ void emitLiteralPosition() override {}
+ void startLiteralSection(MCSection *Section) override;
+};
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_XTENSA_XTENSATARGETSTREAMER_H
diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td
index b953540..460a15e 100644
--- a/llvm/lib/Target/Xtensa/Xtensa.td
+++ b/llvm/lib/Target/Xtensa/Xtensa.td
@@ -36,6 +36,12 @@ def : Proc<"generic", []>;
include "XtensaRegisterInfo.td"
//===----------------------------------------------------------------------===//
+// Calling Convention Description
+//===----------------------------------------------------------------------===//
+
+include "XtensaCallingConv.td"
+
+//===----------------------------------------------------------------------===//
// Instruction Descriptions
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
index 87dbf2e..e222919 100644
--- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
@@ -12,8 +12,13 @@
//===----------------------------------------------------------------------===//
#include "XtensaAsmPrinter.h"
+#include "MCTargetDesc/XtensaMCExpr.h"
+#include "MCTargetDesc/XtensaTargetStreamer.h"
#include "TargetInfo/XtensaTargetInfo.h"
+#include "XtensaConstantPoolValue.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/MC/MCExpr.h"
@@ -25,12 +30,152 @@
using namespace llvm;
+static MCSymbolRefExpr::VariantKind
+getModifierVariantKind(XtensaCP::XtensaCPModifier Modifier) {
+ switch (Modifier) {
+ case XtensaCP::no_modifier:
+ return MCSymbolRefExpr::VK_None;
+ case XtensaCP::TPOFF:
+ return MCSymbolRefExpr::VK_TPOFF;
+ }
+ report_fatal_error("Invalid XtensaCPModifier!");
+}
+
void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) {
MCInst LoweredMI;
lowerToMCInst(MI, LoweredMI);
EmitToStreamer(*OutStreamer, LoweredMI);
}
+void XtensaAsmPrinter::emitMachineConstantPoolValue(
+ MachineConstantPoolValue *MCPV) {
+ XtensaConstantPoolValue *ACPV = static_cast<XtensaConstantPoolValue *>(MCPV);
+ MCSymbol *MCSym;
+
+ assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
+
+ XtensaConstantPoolSymbol *XtensaSym = cast<XtensaConstantPoolSymbol>(ACPV);
+ const char *Sym = XtensaSym->getSymbol();
+ std::string SymName(Sym);
+
+ if (XtensaSym->isPrivateLinkage())
+ SymName = ".L" + SymName;
+
+ MCSym = GetExternalSymbolSymbol(StringRef(SymName));
+ MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId());
+ auto *TS =
+ static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
+ MCSymbolRefExpr::VariantKind VK = getModifierVariantKind(ACPV->getModifier());
+
+ if (ACPV->getModifier() != XtensaCP::no_modifier) {
+ std::string SymName(MCSym->getName());
+ StringRef Modifier = ACPV->getModifierText();
+ SymName += Modifier;
+ MCSym = GetExternalSymbolSymbol(StringRef(SymName));
+ }
+
+ const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext);
+ TS->emitLiteral(LblSym, Expr, false);
+}
+
+void XtensaAsmPrinter::emitMachineConstantPoolEntry(
+ const MachineConstantPoolEntry &CPE, int i) {
+ if (CPE.isMachineConstantPoolEntry()) {
+ XtensaConstantPoolValue *ACPV =
+ static_cast<XtensaConstantPoolValue *>(CPE.Val.MachineCPVal);
+ ACPV->setLabelId(i);
+ emitMachineConstantPoolValue(CPE.Val.MachineCPVal);
+ } else {
+ MCSymbol *LblSym = GetCPISymbol(i);
+ auto *TS =
+ static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
+ const Constant *C = CPE.Val.ConstVal;
+ const MCExpr *Value = nullptr;
+
+ Type *Ty = C->getType();
+ if (const auto *CFP = dyn_cast<ConstantFP>(C)) {
+ Value = MCConstantExpr::create(
+ CFP->getValueAPF().bitcastToAPInt().getSExtValue(), OutContext);
+ } else if (const auto *CI = dyn_cast<ConstantInt>(C)) {
+ Value = MCConstantExpr::create(CI->getValue().getSExtValue(), OutContext);
+ } else if (isa<PointerType>(Ty)) {
+ Value = lowerConstant(C);
+ } else {
+ llvm_unreachable("unexpected constant pool entry type");
+ }
+
+ TS->emitLiteral(LblSym, Value, false);
+ }
+}
+
+// EmitConstantPool - Print to the current output stream assembly
+// representations of the constants in the constant pool MCP. This is
+// used to print out constants which have been "spilled to memory" by
+// the code generator.
+void XtensaAsmPrinter::emitConstantPool() {
+ const Function &F = MF->getFunction();
+ const MachineConstantPool *MCP = MF->getConstantPool();
+ const std::vector<MachineConstantPoolEntry> &CP = MCP->getConstants();
+ if (CP.empty())
+ return;
+
+ OutStreamer->pushSection();
+
+ auto *TS =
+ static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
+ MCSection *CS = getObjFileLowering().SectionForGlobal(&F, TM);
+ TS->startLiteralSection(CS);
+
+ int CPIdx = 0;
+ for (const MachineConstantPoolEntry &CPE : CP) {
+ emitMachineConstantPoolEntry(CPE, CPIdx++);
+ }
+
+ OutStreamer->popSection();
+}
+
+MCSymbol *
+XtensaAsmPrinter::GetConstantPoolIndexSymbol(const MachineOperand &MO) const {
+ // Create a symbol for the name.
+ return GetCPISymbol(MO.getIndex());
+}
+
+MCOperand
+XtensaAsmPrinter::LowerSymbolOperand(const MachineOperand &MO,
+ MachineOperand::MachineOperandType MOTy,
+ unsigned Offset) const {
+ const MCSymbol *Symbol;
+ XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None;
+
+ switch (MOTy) {
+ case MachineOperand::MO_GlobalAddress:
+ Symbol = getSymbol(MO.getGlobal());
+ Offset += MO.getOffset();
+ break;
+ case MachineOperand::MO_ConstantPoolIndex:
+ Symbol = GetConstantPoolIndexSymbol(MO);
+ Offset += MO.getOffset();
+ break;
+ default:
+ report_fatal_error("<unknown operand type>");
+ }
+
+ const MCExpr *ME =
+ MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
+ ME = XtensaMCExpr::create(ME, Kind, OutContext);
+
+ if (Offset) {
+ // Assume offset is never negative.
+ assert(Offset > 0);
+
+ const MCConstantExpr *OffsetExpr =
+ MCConstantExpr::create(Offset, OutContext);
+ ME = MCBinaryExpr::createAdd(ME, OffsetExpr, OutContext);
+ }
+
+ return MCOperand::createExpr(ME);
+}
+
MCOperand XtensaAsmPrinter::lowerOperand(const MachineOperand &MO,
unsigned Offset) const {
MachineOperand::MachineOperandType MOTy = MO.getType();
@@ -45,6 +190,9 @@ MCOperand XtensaAsmPrinter::lowerOperand(const MachineOperand &MO,
return MCOperand::createImm(MO.getImm() + Offset);
case MachineOperand::MO_RegisterMask:
break;
+ case MachineOperand::MO_GlobalAddress:
+ case MachineOperand::MO_ConstantPoolIndex:
+ return LowerSymbolOperand(MO, MOTy, Offset);
default:
report_fatal_error("unknown operand type");
}
diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h
index dec2a1e..f3fec19 100644
--- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h
+++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h
@@ -15,6 +15,7 @@
#include "XtensaTargetMachine.h"
#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/Support/Compiler.h"
namespace llvm {
@@ -35,6 +36,18 @@ public:
StringRef getPassName() const override { return "Xtensa Assembly Printer"; }
void emitInstruction(const MachineInstr *MI) override;
+ void emitConstantPool() override;
+
+ void emitMachineConstantPoolEntry(const MachineConstantPoolEntry &CPE, int i);
+
+ void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
+
+ MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const;
+
+ MCOperand LowerSymbolOperand(const MachineOperand &MO,
+ MachineOperand::MachineOperandType MOTy,
+ unsigned Offset) const;
+
// Lower MachineInstr MI to MCInst OutMI.
void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) const;
diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
new file mode 100644
index 0000000..a348b4c
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
@@ -0,0 +1,24 @@
+//===- XtensaCallingConv.td - Xtensa Calling Conventions -*- tablegen ---*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This describes the calling conventions for the Xtensa ABI.
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Xtensa return value calling convention
+//===----------------------------------------------------------------------===//
+def RetCC_Xtensa : CallingConv<[
+ // First two return values go in a2, a3, a4, a5
+ CCIfType<[i32], CCAssignToReg<[A2, A3, A4, A5]>>,
+ CCIfType<[i64], CCAssignToRegWithShadow<[A2, A4], [A3, A5]>>
+]>;
+
+//===----------------------------------------------------------------------===//
+// Callee-saved register lists.
+//===----------------------------------------------------------------------===//
+
+def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>;
diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp
new file mode 100644
index 0000000..4e53aa5
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp
@@ -0,0 +1,207 @@
+//===- XtensaConstantPoolValue.cpp - Xtensa constantpool value ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Xtensa specific constantpool value class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "XtensaConstantPoolValue.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+using namespace llvm;
+
+XtensaConstantPoolValue::XtensaConstantPoolValue(
+ Type *Ty, unsigned ID, XtensaCP::XtensaCPKind Kind,
+ XtensaCP::XtensaCPModifier modifier)
+ : MachineConstantPoolValue(Ty), LabelId(ID), Kind(Kind),
+ Modifier(modifier) {}
+
+XtensaConstantPoolValue::XtensaConstantPoolValue(
+ LLVMContext &C, unsigned ID, XtensaCP::XtensaCPKind Kind,
+ XtensaCP::XtensaCPModifier Modifier)
+ : MachineConstantPoolValue((Type *)Type::getInt32Ty(C)), LabelId(ID),
+ Kind(Kind), Modifier(Modifier) {}
+
+XtensaConstantPoolValue::~XtensaConstantPoolValue() {}
+
+StringRef XtensaConstantPoolValue::getModifierText() const {
+ switch (Modifier) {
+ case XtensaCP::no_modifier:
+ return "";
+ case XtensaCP::TPOFF:
+ return "@TPOFF";
+ }
+ report_fatal_error("Unknown modifier!");
+}
+
+int XtensaConstantPoolValue::getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) {
+ report_fatal_error("Shouldn't be calling this directly!");
+}
+
+void XtensaConstantPoolValue::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
+ ID.AddInteger(LabelId);
+}
+
+bool XtensaConstantPoolValue::hasSameValue(XtensaConstantPoolValue *ACPV) {
+ if (ACPV->Kind == Kind) {
+ if (ACPV->LabelId == LabelId)
+ return true;
+ }
+ return false;
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void XtensaConstantPoolValue::dump() const { errs() << " " << *this; }
+#endif
+
+void XtensaConstantPoolValue::print(raw_ostream &O) const {}
+
+//===----------------------------------------------------------------------===//
+// XtensaConstantPoolConstant
+//===----------------------------------------------------------------------===//
+
+XtensaConstantPoolConstant::XtensaConstantPoolConstant(
+ const Constant *C, unsigned ID, XtensaCP::XtensaCPKind Kind)
+ : XtensaConstantPoolValue(C->getType(), ID, Kind), CVal(C) {}
+
+XtensaConstantPoolConstant *
+XtensaConstantPoolConstant::Create(const Constant *C, unsigned ID,
+ XtensaCP::XtensaCPKind Kind) {
+ return new XtensaConstantPoolConstant(C, ID, Kind);
+}
+
+const BlockAddress *XtensaConstantPoolConstant::getBlockAddress() const {
+ return dyn_cast_or_null<BlockAddress>(CVal);
+}
+
+int XtensaConstantPoolConstant::getExistingMachineCPValue(
+ MachineConstantPool *CP, Align Alignment) {
+ return getExistingMachineCPValueImpl<XtensaConstantPoolConstant>(CP,
+ Alignment);
+}
+
+bool XtensaConstantPoolConstant::hasSameValue(XtensaConstantPoolValue *ACPV) {
+ const XtensaConstantPoolConstant *ACPC =
+ dyn_cast<XtensaConstantPoolConstant>(ACPV);
+ return ACPC && ACPC->CVal == CVal &&
+ XtensaConstantPoolValue::hasSameValue(ACPV);
+}
+
+void XtensaConstantPoolConstant::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
+ ID.AddPointer(CVal);
+ XtensaConstantPoolValue::addSelectionDAGCSEId(ID);
+}
+
+void XtensaConstantPoolConstant::print(raw_ostream &O) const {
+ O << CVal->getName();
+ XtensaConstantPoolValue::print(O);
+}
+
+XtensaConstantPoolSymbol::XtensaConstantPoolSymbol(
+ LLVMContext &C, const char *Str, unsigned ID, bool PrivLinkage,
+ XtensaCP::XtensaCPModifier Modifier)
+ : XtensaConstantPoolValue(C, ID, XtensaCP::CPExtSymbol, Modifier), S(Str),
+ PrivateLinkage(PrivLinkage) {}
+
+XtensaConstantPoolSymbol *
+XtensaConstantPoolSymbol::Create(LLVMContext &C, const char *Str, unsigned ID,
+ bool PrivLinkage,
+ XtensaCP::XtensaCPModifier Modifier)
+
+{
+ return new XtensaConstantPoolSymbol(C, Str, ID, PrivLinkage, Modifier);
+}
+
+int XtensaConstantPoolSymbol::getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) {
+ return getExistingMachineCPValueImpl<XtensaConstantPoolSymbol>(CP, Alignment);
+}
+
+bool XtensaConstantPoolSymbol::hasSameValue(XtensaConstantPoolValue *ACPV) {
+ const XtensaConstantPoolSymbol *ACPS =
+ dyn_cast<XtensaConstantPoolSymbol>(ACPV);
+ return ACPS && ACPS->S == S && XtensaConstantPoolValue::hasSameValue(ACPV);
+}
+
+void XtensaConstantPoolSymbol::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
+ ID.AddString(S);
+ XtensaConstantPoolValue::addSelectionDAGCSEId(ID);
+}
+
+void XtensaConstantPoolSymbol::print(raw_ostream &O) const {
+ O << S;
+ XtensaConstantPoolValue::print(O);
+}
+
+XtensaConstantPoolMBB::XtensaConstantPoolMBB(LLVMContext &C,
+ const MachineBasicBlock *M,
+ unsigned Id)
+ : XtensaConstantPoolValue(C, 0, XtensaCP::CPMachineBasicBlock), MBB(M) {}
+
+XtensaConstantPoolMBB *XtensaConstantPoolMBB::Create(LLVMContext &C,
+ const MachineBasicBlock *M,
+ unsigned Idx) {
+ return new XtensaConstantPoolMBB(C, M, Idx);
+}
+
+int XtensaConstantPoolMBB::getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) {
+ return getExistingMachineCPValueImpl<XtensaConstantPoolMBB>(CP, Alignment);
+}
+
+bool XtensaConstantPoolMBB::hasSameValue(XtensaConstantPoolValue *ACPV) {
+ const XtensaConstantPoolMBB *ACPMBB = dyn_cast<XtensaConstantPoolMBB>(ACPV);
+ return ACPMBB && ACPMBB->MBB == MBB &&
+ XtensaConstantPoolValue::hasSameValue(ACPV);
+}
+
+void XtensaConstantPoolMBB::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
+ ID.AddPointer(MBB);
+ XtensaConstantPoolValue::addSelectionDAGCSEId(ID);
+}
+
+void XtensaConstantPoolMBB::print(raw_ostream &O) const {
+ O << "BB#" << MBB->getNumber();
+ XtensaConstantPoolValue::print(O);
+}
+
+XtensaConstantPoolJumpTable::XtensaConstantPoolJumpTable(LLVMContext &C,
+ unsigned Index)
+ : XtensaConstantPoolValue(C, 0, XtensaCP::CPJumpTable), Idx(Index) {}
+
+XtensaConstantPoolJumpTable *XtensaConstantPoolJumpTable::Create(LLVMContext &C,
+ unsigned Idx) {
+ return new XtensaConstantPoolJumpTable(C, Idx);
+}
+
+int XtensaConstantPoolJumpTable::getExistingMachineCPValue(
+ MachineConstantPool *CP, Align Alignment) {
+ return getExistingMachineCPValueImpl<XtensaConstantPoolJumpTable>(CP,
+ Alignment);
+}
+
+bool XtensaConstantPoolJumpTable::hasSameValue(XtensaConstantPoolValue *ACPV) {
+ const XtensaConstantPoolJumpTable *ACPJT =
+ dyn_cast<XtensaConstantPoolJumpTable>(ACPV);
+ return ACPJT && ACPJT->Idx == Idx &&
+ XtensaConstantPoolValue::hasSameValue(ACPV);
+}
+
+void XtensaConstantPoolJumpTable::addSelectionDAGCSEId(FoldingSetNodeID &ID) {}
+
+void XtensaConstantPoolJumpTable::print(raw_ostream &O) const {
+ O << "JT" << Idx;
+ XtensaConstantPoolValue::print(O);
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h
new file mode 100644
index 0000000..5580de4
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h
@@ -0,0 +1,263 @@
+//===- XtensaConstantPoolValue.h - Xtensa constantpool value ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Xtensa specific constantpool value class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H
+#define LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H
+
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstddef>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class BlockAddress;
+class Constant;
+class GlobalValue;
+class LLVMContext;
+class MachineBasicBlock;
+
+namespace XtensaCP {
+enum XtensaCPKind {
+ CPExtSymbol,
+ CPBlockAddress,
+ CPMachineBasicBlock,
+ CPJumpTable
+};
+
+enum XtensaCPModifier {
+ no_modifier, // None
+ TPOFF // Thread Pointer Offset
+};
+} // namespace XtensaCP
+
+/// XtensaConstantPoolValue - Xtensa specific constantpool value. This is used
+/// to represent PC-relative displacement between the address of the load
+/// instruction and the constant being loaded.
+class XtensaConstantPoolValue : public MachineConstantPoolValue {
+ unsigned LabelId; // Label id of the load.
+ XtensaCP::XtensaCPKind Kind; // Kind of constant.
+ XtensaCP::XtensaCPModifier Modifier; // Symbol name modifier
+ //(for example Global Variable name)
+
+protected:
+ XtensaConstantPoolValue(
+ Type *Ty, unsigned ID, XtensaCP::XtensaCPKind Kind,
+ XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier);
+
+ XtensaConstantPoolValue(
+ LLVMContext &C, unsigned id, XtensaCP::XtensaCPKind Kind,
+ XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier);
+
+ template <typename Derived>
+ int getExistingMachineCPValueImpl(MachineConstantPool *CP, Align Alignment) {
+ const std::vector<MachineConstantPoolEntry> &Constants = CP->getConstants();
+ for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
+ if (Constants[i].isMachineConstantPoolEntry() &&
+ (Constants[i].getAlign() >= Alignment)) {
+ auto *CPV = static_cast<XtensaConstantPoolValue *>(
+ Constants[i].Val.MachineCPVal);
+ if (Derived *APC = dyn_cast<Derived>(CPV))
+ if (cast<Derived>(this)->equals(APC))
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+public:
+ ~XtensaConstantPoolValue() override;
+
+ XtensaCP::XtensaCPModifier getModifier() const { return Modifier; }
+ bool hasModifier() const { return Modifier != XtensaCP::no_modifier; }
+ StringRef getModifierText() const;
+
+ unsigned getLabelId() const { return LabelId; }
+ void setLabelId(unsigned ID) { LabelId = ID; }
+
+ bool isExtSymbol() const { return Kind == XtensaCP::CPExtSymbol; }
+ bool isBlockAddress() const { return Kind == XtensaCP::CPBlockAddress; }
+ bool isMachineBasicBlock() const {
+ return Kind == XtensaCP::CPMachineBasicBlock;
+ }
+ bool isJumpTable() const { return Kind == XtensaCP::CPJumpTable; }
+
+ int getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) override;
+
+ void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
+
+ /// hasSameValue - Return true if this Xtensa constpool value can share the
+ /// same constantpool entry as another Xtensa constpool value.
+ virtual bool hasSameValue(XtensaConstantPoolValue *ACPV);
+
+ bool equals(const XtensaConstantPoolValue *A) const {
+ return this->LabelId == A->LabelId && this->Modifier == A->Modifier;
+ }
+
+ void print(raw_ostream &O) const override;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() const;
+#endif
+};
+
+inline raw_ostream &operator<<(raw_ostream &O,
+ const XtensaConstantPoolValue &V) {
+ V.print(O);
+ return O;
+}
+
+/// XtensaConstantPoolConstant - Xtensa-specific constant pool values for
+/// Constants (for example BlockAddresses).
+class XtensaConstantPoolConstant : public XtensaConstantPoolValue {
+ const Constant *CVal; // Constant being loaded.
+
+ XtensaConstantPoolConstant(const Constant *C, unsigned ID,
+ XtensaCP::XtensaCPKind Kind);
+
+public:
+ static XtensaConstantPoolConstant *Create(const Constant *C, unsigned ID,
+ XtensaCP::XtensaCPKind Kind);
+
+ const BlockAddress *getBlockAddress() const;
+
+ int getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) override;
+
+ /// hasSameValue - Return true if this Xtensa constpool value can share the
+ /// same constantpool entry as another Xtensa constpool value.
+ bool hasSameValue(XtensaConstantPoolValue *ACPV) override;
+
+ void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
+
+ void print(raw_ostream &O) const override;
+ static bool classof(const XtensaConstantPoolValue *APV) {
+ return APV->isBlockAddress();
+ }
+
+ bool equals(const XtensaConstantPoolConstant *A) const {
+ return CVal == A->CVal && XtensaConstantPoolValue::equals(A);
+ }
+};
+
+/// XtensaConstantPoolSymbol - Xtensa-specific constantpool values for external
+/// symbols.
+class XtensaConstantPoolSymbol : public XtensaConstantPoolValue {
+ const std::string S; // ExtSymbol being loaded.
+ bool PrivateLinkage;
+
+ XtensaConstantPoolSymbol(
+ LLVMContext &C, const char *S, unsigned Id, bool PrivLinkage,
+ XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier);
+
+public:
+ static XtensaConstantPoolSymbol *
+ Create(LLVMContext &C, const char *S, unsigned ID, bool PrivLinkage,
+ XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier);
+
+ const char *getSymbol() const { return S.c_str(); }
+
+ int getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) override;
+
+ void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
+
+ /// hasSameValue - Return true if this Xtensa constpool value can share the
+ /// same constantpool entry as another Xtensa constpool value.
+ bool hasSameValue(XtensaConstantPoolValue *ACPV) override;
+
+ bool isPrivateLinkage() { return PrivateLinkage; }
+
+ void print(raw_ostream &O) const override;
+
+ static bool classof(const XtensaConstantPoolValue *ACPV) {
+ return ACPV->isExtSymbol();
+ }
+
+ bool equals(const XtensaConstantPoolSymbol *A) const {
+ return S == A->S && XtensaConstantPoolValue::equals(A);
+ }
+};
+
+/// XtensaConstantPoolMBB - Xtensa-specific constantpool value of a machine
+/// basic block.
+class XtensaConstantPoolMBB : public XtensaConstantPoolValue {
+ const MachineBasicBlock *MBB; // Machine basic block.
+
+ XtensaConstantPoolMBB(LLVMContext &C, const MachineBasicBlock *M,
+ unsigned ID);
+
+public:
+ static XtensaConstantPoolMBB *Create(LLVMContext &C,
+ const MachineBasicBlock *M, unsigned ID);
+
+ const MachineBasicBlock *getMBB() const { return MBB; }
+
+ int getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) override;
+
+ void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
+
+ /// hasSameValue - Return true if this Xtensa constpool value can share the
+ /// same constantpool entry as another Xtensa constpool value.
+ bool hasSameValue(XtensaConstantPoolValue *ACPV) override;
+
+ void print(raw_ostream &O) const override;
+
+ static bool classof(const XtensaConstantPoolValue *ACPV) {
+ return ACPV->isMachineBasicBlock();
+ }
+
+ bool equals(const XtensaConstantPoolMBB *A) const {
+ return MBB == A->MBB && XtensaConstantPoolValue::equals(A);
+ }
+};
+
+/// XtensaConstantPoolJumpTable - Xtensa-specific constantpool values for Jump
+/// Table symbols.
+class XtensaConstantPoolJumpTable : public XtensaConstantPoolValue {
+ unsigned Idx; // Jump Table Index.
+
+ XtensaConstantPoolJumpTable(LLVMContext &C, unsigned Idx);
+
+public:
+ static XtensaConstantPoolJumpTable *Create(LLVMContext &C, unsigned Idx);
+
+ unsigned getIndex() const { return Idx; }
+
+ int getExistingMachineCPValue(MachineConstantPool *CP,
+ Align Alignment) override;
+
+ void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
+
+ /// hasSameValue - Return true if this Xtensa constpool value can share the
+ /// same constantpool entry as another Xtensa constpool value.
+ bool hasSameValue(XtensaConstantPoolValue *ACPV) override;
+
+ void print(raw_ostream &O) const override;
+
+ static bool classof(const XtensaConstantPoolValue *ACPV) {
+ return ACPV->isJumpTable();
+ }
+
+ bool equals(const XtensaConstantPoolJumpTable *A) const {
+ return Idx == A->Idx && XtensaConstantPoolValue::equals(A);
+ }
+};
+
+} // namespace llvm
+
+#endif /* LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H */
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index 2092a2d..ab37c09 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -37,3 +37,23 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {}
+
+// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
+MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
+ MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const {
+ const XtensaInstrInfo &TII =
+ *static_cast<const XtensaInstrInfo *>(MF.getSubtarget().getInstrInfo());
+
+ if (!hasReservedCallFrame(MF)) {
+ int64_t Amount = I->getOperand(0).getImm();
+
+ if (I->getOpcode() == Xtensa::ADJCALLSTACKDOWN)
+ Amount = -Amount;
+
+ unsigned SP = Xtensa::SP;
+ TII.adjustStackPtr(SP, Amount, MBB, I);
+ }
+
+ return MBB.erase(I);
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
index 19e52310..2da88ab1 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
@@ -25,6 +25,10 @@ public:
/// the function.
void emitPrologue(MachineFunction &, MachineBasicBlock &) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
+
+ MachineBasicBlock::iterator
+ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const override;
};
} // namespace llvm
diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
index 3007372..5ebedef 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
@@ -12,9 +12,11 @@
#include "Xtensa.h"
#include "XtensaTargetMachine.h"
+#include "XtensaUtils.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -37,9 +39,57 @@ public:
void Select(SDNode *Node) 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,
int Scale) {
- report_fatal_error("MemReg address is not implemented yet");
+ EVT ValTy = Addr.getValueType();
+
+ // if Address is FI, get the TargetFrameIndex.
+ if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
+ Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy);
+
+ return true;
+ }
+
+ if (TM.isPositionIndependent()) {
+ DiagnosticInfoUnsupported Diag(CurDAG->getMachineFunction().getFunction(),
+ "PIC relocations are not supported ",
+ Addr.getDebugLoc());
+ CurDAG->getContext()->diagnose(Diag);
+ }
+
+ if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
+ Addr.getOpcode() == ISD::TargetGlobalAddress))
+ return false;
+
+ // Addresses of the form FI+const
+ bool Valid = false;
+ if (CurDAG->isBaseWithConstantOffset(Addr)) {
+ ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
+ int64_t OffsetVal = CN->getSExtValue();
+
+ Valid = isValidAddrOffset(Scale, OffsetVal);
+
+ if (Valid) {
+ // If the first operand is a FI, get the TargetFI Node
+ if (FrameIndexSDNode *FIN =
+ dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
+ else
+ Base = Addr.getOperand(0);
+
+ Offset =
+ CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), ValTy);
+ return true;
+ }
+ }
+
+ // Last case
+ Base = Addr;
+ Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType());
+ return true;
}
bool selectMemRegAddrISH1(SDValue Addr, SDValue &Base, SDValue &Offset) {
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 276fab8..64b996b 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "XtensaISelLowering.h"
+#include "XtensaConstantPoolValue.h"
#include "XtensaSubtarget.h"
#include "XtensaTargetMachine.h"
#include "llvm/CodeGen/CallingConvLower.h"
@@ -22,15 +23,26 @@
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <deque>
using namespace llvm;
#define DEBUG_TYPE "xtensa-lower"
+// Return true if we must use long (in fact, indirect) function call.
+// It's simplified version, production implimentation must
+// resolve a functions in ROM (usually glibc functions)
+static bool isLongCall(const char *str) {
+ // Currently always use long calls
+ return true;
+}
+
XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
const XtensaSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
+ MVT PtrVT = MVT::i32;
// Set up the register classes.
addRegisterClass(MVT::i32, &Xtensa::ARRegClass);
@@ -41,18 +53,507 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setMinFunctionAlignment(Align(4));
+ setOperationAction(ISD::Constant, MVT::i32, Custom);
+ setOperationAction(ISD::Constant, MVT::i64, Expand);
+
+ setBooleanContents(ZeroOrOneBooleanContent);
+
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
+
+ setOperationAction(ISD::BITCAST, MVT::i32, Expand);
+ setOperationAction(ISD::BITCAST, MVT::f32, Expand);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand);
+
+ // No sign extend instructions for i1
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
+ setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote);
+ setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote);
+ }
+
+ setOperationAction(ISD::ConstantPool, PtrVT, Custom);
+
// Compute derived properties from the register classes
computeRegisterProperties(STI.getRegisterInfo());
}
+//===----------------------------------------------------------------------===//
+// Calling conventions
+//===----------------------------------------------------------------------===//
+
+#include "XtensaGenCallingConv.inc"
+
+static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT,
+ CCValAssign::LocInfo LocInfo,
+ ISD::ArgFlagsTy ArgFlags, CCState &State) {
+ static const MCPhysReg IntRegs[] = {Xtensa::A2, Xtensa::A3, Xtensa::A4,
+ Xtensa::A5, Xtensa::A6, Xtensa::A7};
+
+ if (ArgFlags.isByVal()) {
+ Align ByValAlign = ArgFlags.getNonZeroByValAlign();
+ unsigned ByValSize = ArgFlags.getByValSize();
+ if (ByValSize < 4) {
+ ByValSize = 4;
+ }
+ if (ByValAlign < Align(4)) {
+ ByValAlign = Align(4);
+ }
+ unsigned Offset = State.AllocateStack(ByValSize, ByValAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ // Mark all unused registers as allocated to avoid misuse
+ // of such registers.
+ while (State.AllocateReg(IntRegs))
+ ;
+ return false;
+ }
+
+ // Promote i8 and i16
+ if (LocVT == MVT::i8 || LocVT == MVT::i16) {
+ LocVT = MVT::i32;
+ if (ArgFlags.isSExt())
+ LocInfo = CCValAssign::SExt;
+ else if (ArgFlags.isZExt())
+ LocInfo = CCValAssign::ZExt;
+ else
+ LocInfo = CCValAssign::AExt;
+ }
+
+ unsigned Register;
+
+ Align OrigAlign = ArgFlags.getNonZeroOrigAlign();
+ bool needs64BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(8));
+ bool needs128BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(16));
+
+ if (ValVT == MVT::i32) {
+ Register = State.AllocateReg(IntRegs);
+ // If this is the first part of an i64 arg,
+ // the allocated register must be either A2, A4 or A6.
+ if (needs64BitAlign && (Register == Xtensa::A3 || Register == Xtensa::A5 ||
+ Register == Xtensa::A7))
+ Register = State.AllocateReg(IntRegs);
+ // arguments with 16byte alignment must be passed in the first register or
+ // passed via stack
+ if (needs128BitAlign && (Register != Xtensa::A2))
+ while ((Register = State.AllocateReg(IntRegs)))
+ ;
+ LocVT = MVT::i32;
+ } else if (ValVT == MVT::f64) {
+ // Allocate int register and shadow next int register.
+ Register = State.AllocateReg(IntRegs);
+ if (Register == Xtensa::A3 || Register == Xtensa::A5 ||
+ Register == Xtensa::A7)
+ Register = State.AllocateReg(IntRegs);
+ State.AllocateReg(IntRegs);
+ LocVT = MVT::i32;
+ } else {
+ report_fatal_error("Cannot handle this ValVT.");
+ }
+
+ if (!Register) {
+ unsigned Offset = State.AllocateStack(ValVT.getStoreSize(), OrigAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ } else {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Register, LocVT, LocInfo));
+ }
+
+ return false;
+}
+
+CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
+ bool IsVarArg) const {
+ return CC_Xtensa_Custom;
+}
+
+SDValue XtensaTargetLowering::LowerFormalArguments(
+ SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
+ SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+
+ // Used with vargs to acumulate store chains.
+ std::vector<SDValue> OutChains;
+
+ if (IsVarArg)
+ report_fatal_error("Var arg not supported by FormalArguments Lowering");
+
+ // Assign locations to all of the incoming arguments.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+
+ CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg));
+
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ CCValAssign &VA = ArgLocs[i];
+ // Arguments stored on registers
+ if (VA.isRegLoc()) {
+ EVT RegVT = VA.getLocVT();
+ const TargetRegisterClass *RC;
+
+ if (RegVT == MVT::i32)
+ RC = &Xtensa::ARRegClass;
+ else
+ report_fatal_error("RegVT not supported by FormalArguments Lowering");
+
+ // Transform the arguments stored on
+ // physical registers into virtual ones
+ unsigned Register = MF.addLiveIn(VA.getLocReg(), RC);
+ SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Register, RegVT);
+
+ // If this is an 8 or 16-bit value, it has been passed promoted
+ // to 32 bits. Insert an assert[sz]ext to capture this, then
+ // truncate to the right size.
+ if (VA.getLocInfo() != CCValAssign::Full) {
+ unsigned Opcode = 0;
+ if (VA.getLocInfo() == CCValAssign::SExt)
+ Opcode = ISD::AssertSext;
+ else if (VA.getLocInfo() == CCValAssign::ZExt)
+ Opcode = ISD::AssertZext;
+ if (Opcode)
+ ArgValue = DAG.getNode(Opcode, DL, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+ ArgValue = DAG.getNode((VA.getValVT() == MVT::f32) ? ISD::BITCAST
+ : ISD::TRUNCATE,
+ DL, VA.getValVT(), ArgValue);
+ }
+
+ InVals.push_back(ArgValue);
+
+ } else {
+ assert(VA.isMemLoc());
+
+ EVT ValVT = VA.getValVT();
+
+ // The stack pointer offset is relative to the caller stack frame.
+ int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
+ true);
+
+ if (Ins[VA.getValNo()].Flags.isByVal()) {
+ // Assume that in this case load operation is created
+ SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
+ InVals.push_back(FIN);
+ } else {
+ // Create load nodes to retrieve arguments from the stack
+ SDValue FIN =
+ DAG.getFrameIndex(FI, getFrameIndexTy(DAG.getDataLayout()));
+ InVals.push_back(DAG.getLoad(
+ ValVT, DL, Chain, FIN,
+ MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)));
+ }
+ }
+ }
+
+ // All stores are grouped in one node to allow the matching between
+ // the size of Ins and InVals. This only happens when on varg functions
+ if (!OutChains.empty()) {
+ OutChains.push_back(Chain);
+ Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
+ }
+
+ return Chain;
+}
+
+SDValue
+XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const {
+ SelectionDAG &DAG = CLI.DAG;
+ SDLoc &DL = CLI.DL;
+ SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs;
+ SmallVector<SDValue, 32> &OutVals = CLI.OutVals;
+ SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins;
+ SDValue Chain = CLI.Chain;
+ SDValue Callee = CLI.Callee;
+ bool &IsTailCall = CLI.IsTailCall;
+ CallingConv::ID CallConv = CLI.CallConv;
+ bool IsVarArg = CLI.IsVarArg;
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ EVT PtrVT = getPointerTy(DAG.getDataLayout());
+ const TargetFrameLowering *TFL = Subtarget.getFrameLowering();
+
+ // TODO: Support tail call optimization.
+ IsTailCall = false;
+
+ // Analyze the operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
+
+ CCAssignFn *CC = CCAssignFnForCall(CallConv, IsVarArg);
+
+ CCInfo.AnalyzeCallOperands(Outs, CC);
+
+ // Get a count of how many bytes are to be pushed on the stack.
+ unsigned NumBytes = CCInfo.getStackSize();
+
+ Align StackAlignment = TFL->getStackAlign();
+ unsigned NextStackOffset = alignTo(NumBytes, StackAlignment);
+
+ Chain = DAG.getCALLSEQ_START(Chain, NextStackOffset, 0, DL);
+
+ // Copy argument values to their designated locations.
+ std::deque<std::pair<unsigned, SDValue>> RegsToPass;
+ SmallVector<SDValue, 8> MemOpChains;
+ SDValue StackPtr;
+ for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) {
+ CCValAssign &VA = ArgLocs[I];
+ SDValue ArgValue = OutVals[I];
+ ISD::ArgFlagsTy Flags = Outs[I].Flags;
+
+ if (VA.isRegLoc())
+ // Queue up the argument copies and emit them at the end.
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
+ else if (Flags.isByVal()) {
+ assert(VA.isMemLoc());
+ assert(Flags.getByValSize() &&
+ "ByVal args of size 0 should have been ignored by front-end.");
+ assert(!IsTailCall &&
+ "Do not tail-call optimize if there is a byval argument.");
+
+ if (!StackPtr.getNode())
+ StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT);
+ unsigned Offset = VA.getLocMemOffset();
+ SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
+ DAG.getIntPtrConstant(Offset, DL));
+ SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), DL, MVT::i32);
+ SDValue Memcpy = DAG.getMemcpy(
+ Chain, DL, Address, ArgValue, SizeNode, Flags.getNonZeroByValAlign(),
+ /*isVolatile=*/false, /*AlwaysInline=*/false,
+ /*isTailCall=*/false, MachinePointerInfo(), MachinePointerInfo());
+ MemOpChains.push_back(Memcpy);
+ } else {
+ assert(VA.isMemLoc() && "Argument not register or memory");
+
+ // Work out the address of the stack slot. Unpromoted ints and
+ // floats are passed as right-justified 8-byte values.
+ if (!StackPtr.getNode())
+ StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT);
+ unsigned Offset = VA.getLocMemOffset();
+ SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
+ DAG.getIntPtrConstant(Offset, DL));
+
+ // Emit the store.
+ MemOpChains.push_back(
+ DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
+ }
+ }
+
+ // Join the stores, which are independent of one another.
+ if (!MemOpChains.empty())
+ Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
+
+ // Build a sequence of copy-to-reg nodes, chained and glued together.
+ SDValue Glue;
+ for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
+ unsigned Reg = RegsToPass[I].first;
+ Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue);
+ Glue = Chain.getValue(1);
+ }
+ std::string name;
+ unsigned char TF = 0;
+
+ // Accept direct calls by converting symbolic call addresses to the
+ // associated Target* opcodes.
+ if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ name = E->getSymbol();
+ TF = E->getTargetFlags();
+ if (isPositionIndependent()) {
+ report_fatal_error("PIC relocations is not supported");
+ } else
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, TF);
+ } else if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ const GlobalValue *GV = G->getGlobal();
+ name = GV->getName().str();
+ }
+
+ if ((!name.empty()) && isLongCall(name.c_str())) {
+ // Create a constant pool entry for the callee address
+ XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier;
+
+ XtensaConstantPoolValue *CPV = XtensaConstantPoolSymbol::Create(
+ *DAG.getContext(), name.c_str(), 0 /* XtensaCLabelIndex */, false,
+ Modifier);
+
+ // Get the address of the callee into a register
+ SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4), 0, TF);
+ SDValue CPWrap = getAddrPCRel(CPAddr, DAG);
+ Callee = CPWrap;
+ }
+
+ // The first call operand is the chain and the second is the target address.
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+
+ // Add a register mask operand representing the call-preserved registers.
+ const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
+ const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
+ assert(Mask && "Missing call preserved mask for calling convention");
+ Ops.push_back(DAG.getRegisterMask(Mask));
+
+ // Add argument registers to the end of the list so that they are
+ // known live into the call.
+ for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
+ unsigned Reg = RegsToPass[I].first;
+ Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType()));
+ }
+
+ // Glue the call to the argument copies, if any.
+ if (Glue.getNode())
+ Ops.push_back(Glue);
+
+ SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
+ Chain = DAG.getNode(XtensaISD::CALL, DL, NodeTys, Ops);
+ Glue = Chain.getValue(1);
+
+ // Mark the end of the call, which is glued to the call itself.
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true),
+ DAG.getConstant(0, DL, PtrVT, true), Glue, DL);
+ Glue = Chain.getValue(1);
+
+ // Assign locations to each value returned by this call.
+ SmallVector<CCValAssign, 16> RetLocs;
+ CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
+ RetCCInfo.AnalyzeCallResult(Ins, RetCC_Xtensa);
+
+ // Copy all of the result registers out of their specified physreg.
+ for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {
+ CCValAssign &VA = RetLocs[I];
+
+ // Copy the value out, gluing the copy to the end of the call sequence.
+ unsigned Reg = VA.getLocReg();
+ SDValue RetValue = DAG.getCopyFromReg(Chain, DL, Reg, VA.getLocVT(), Glue);
+ Chain = RetValue.getValue(1);
+ Glue = RetValue.getValue(2);
+
+ InVals.push_back(RetValue);
+ }
+ return Chain;
+}
+
+bool XtensaTargetLowering::CanLowerReturn(
+ CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
+ return CCInfo.CheckReturn(Outs, RetCC_Xtensa);
+}
+
+SDValue
+XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
+ bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ const SDLoc &DL, SelectionDAG &DAG) const {
+ if (IsVarArg)
+ report_fatal_error("VarArg not supported");
+
+ MachineFunction &MF = DAG.getMachineFunction();
+
+ // Assign locations to each returned value.
+ SmallVector<CCValAssign, 16> RetLocs;
+ CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
+ RetCCInfo.AnalyzeReturn(Outs, RetCC_Xtensa);
+
+ SDValue Glue;
+ // Quick exit for void returns
+ if (RetLocs.empty())
+ return DAG.getNode(XtensaISD::RET, DL, MVT::Other, Chain);
+
+ // Copy the result values into the output registers.
+ SmallVector<SDValue, 4> RetOps;
+ RetOps.push_back(Chain);
+ for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {
+ CCValAssign &VA = RetLocs[I];
+ SDValue RetValue = OutVals[I];
+
+ // Make the return register live on exit.
+ assert(VA.isRegLoc() && "Can only return in registers!");
+
+ // Chain and glue the copies together.
+ unsigned Register = VA.getLocReg();
+ Chain = DAG.getCopyToReg(Chain, DL, Register, RetValue, Glue);
+ Glue = Chain.getValue(1);
+ RetOps.push_back(DAG.getRegister(Register, VA.getLocVT()));
+ }
+
+ // Update chain and glue.
+ RetOps[0] = Chain;
+ if (Glue.getNode())
+ RetOps.push_back(Glue);
+
+ return DAG.getNode(XtensaISD::RET, DL, MVT::Other, RetOps);
+}
+
+SDValue XtensaTargetLowering::LowerImmediate(SDValue Op,
+ SelectionDAG &DAG) const {
+ const ConstantSDNode *CN = cast<ConstantSDNode>(Op);
+ SDLoc DL(CN);
+ APInt APVal = CN->getAPIntValue();
+ int64_t Value = APVal.getSExtValue();
+ if (Op.getValueType() == MVT::i32) {
+ // Check if use node maybe lowered to the MOVI instruction
+ if (Value > -2048 && Value <= 2047)
+ return Op;
+ // Check if use node maybe lowered to the ADDMI instruction
+ SDNode &OpNode = *Op.getNode();
+ if ((OpNode.hasOneUse() && OpNode.use_begin()->getOpcode() == ISD::ADD) &&
+ isShiftedInt<16, 8>(Value))
+ return Op;
+ Type *Ty = Type::getInt32Ty(*DAG.getContext());
+ Constant *CV = ConstantInt::get(Ty, Value);
+ SDValue CP = DAG.getConstantPool(CV, MVT::i32);
+ return CP;
+ }
+ return Op;
+}
+
+SDValue XtensaTargetLowering::getAddrPCRel(SDValue Op,
+ SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ EVT Ty = Op.getValueType();
+ return DAG.getNode(XtensaISD::PCREL_WRAPPER, DL, Ty, Op);
+}
+
+SDValue XtensaTargetLowering::LowerConstantPool(ConstantPoolSDNode *CP,
+ SelectionDAG &DAG) const {
+ EVT PtrVT = getPointerTy(DAG.getDataLayout());
+ SDValue Result;
+ if (!CP->isMachineConstantPoolEntry()) {
+ Result = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlign(),
+ CP->getOffset());
+ } else {
+ report_fatal_error("This constantpool type is not supported yet");
+ }
+
+ return getAddrPCRel(Result, DAG);
+}
+
SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
+ case ISD::Constant:
+ return LowerImmediate(Op, DAG);
+ case ISD::ConstantPool:
+ return LowerConstantPool(cast<ConstantPoolSDNode>(Op), DAG);
default:
report_fatal_error("Unexpected node to lower");
}
}
const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const {
+ switch (Opcode) {
+ case XtensaISD::CALL:
+ return "XtensaISD::CALL";
+ case XtensaISD::PCREL_WRAPPER:
+ return "XtensaISD::PCREL_WRAPPER";
+ case XtensaISD::RET:
+ return "XtensaISD::RET";
+ }
return nullptr;
}
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
index 8b03712..077559e 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
@@ -19,6 +19,23 @@
#include "llvm/CodeGen/TargetLowering.h"
namespace llvm {
+
+namespace XtensaISD {
+enum {
+ FIRST_NUMBER = ISD::BUILTIN_OP_END,
+
+ // Calls a function. Operand 0 is the chain operand and operand 1
+ // is the target address. The arguments start at operand 2.
+ // There is an optional glue operand at the end.
+ CALL,
+
+ // Wraps a TargetGlobalAddress that should be loaded using PC-relative
+ // accesses. Operand 0 is the address.
+ PCREL_WRAPPER,
+ RET
+};
+}
+
class XtensaSubtarget;
class XtensaTargetLowering : public TargetLowering {
@@ -30,10 +47,37 @@ public:
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
+ SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
+ bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins,
+ const SDLoc &DL, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const override;
+
+ SDValue LowerCall(CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const override;
+
+ bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF,
+ bool isVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ LLVMContext &Context) const override;
+
+ SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
+ SelectionDAG &DAG) const override;
+
const XtensaSubtarget &getSubtarget() const { return Subtarget; }
private:
const XtensaSubtarget &Subtarget;
+
+ SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const;
+
+ SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const;
+
+ SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const;
+
+ CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const;
};
} // end namespace llvm
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
index 41b794d..26d8727 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
@@ -15,6 +15,7 @@
#include "XtensaInstrInfo.h"
#include "XtensaTargetMachine.h"
#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
@@ -23,5 +24,139 @@
using namespace llvm;
+static const MachineInstrBuilder &
+addFrameReference(const MachineInstrBuilder &MIB, int FI) {
+ MachineInstr *MI = MIB;
+ MachineFunction &MF = *MI->getParent()->getParent();
+ MachineFrameInfo &MFFrame = MF.getFrameInfo();
+ const MCInstrDesc &MCID = MI->getDesc();
+ MachineMemOperand::Flags Flags = MachineMemOperand::MONone;
+ if (MCID.mayLoad())
+ Flags |= MachineMemOperand::MOLoad;
+ if (MCID.mayStore())
+ Flags |= MachineMemOperand::MOStore;
+ int64_t Offset = 0;
+ Align Alignment = MFFrame.getObjectAlign(FI);
+
+ MachineMemOperand *MMO =
+ MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI, Offset),
+ Flags, MFFrame.getObjectSize(FI), Alignment);
+ return MIB.addFrameIndex(FI).addImm(Offset).addMemOperand(MMO);
+}
+
XtensaInstrInfo::XtensaInstrInfo(const XtensaSubtarget &STI)
- : XtensaGenInstrInfo(), RI(STI), STI(STI) {}
+ : XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP),
+ RI(STI), STI(STI) {}
+
+/// Adjust SP by Amount bytes.
+void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const {
+ DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
+
+ if (Amount == 0)
+ return;
+
+ MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo();
+ const TargetRegisterClass *RC = &Xtensa::ARRegClass;
+
+ // create virtual reg to store immediate
+ unsigned Reg = RegInfo.createVirtualRegister(RC);
+
+ if (isInt<8>(Amount)) { // addi sp, sp, amount
+ BuildMI(MBB, I, DL, get(Xtensa::ADDI), Reg).addReg(SP).addImm(Amount);
+ } else { // Expand immediate that doesn't fit in 8-bit.
+ unsigned Reg1;
+ loadImmediate(MBB, I, &Reg1, Amount);
+ BuildMI(MBB, I, DL, get(Xtensa::ADD), Reg)
+ .addReg(SP)
+ .addReg(Reg1, RegState::Kill);
+ }
+
+ BuildMI(MBB, I, DL, get(Xtensa::OR), SP)
+ .addReg(Reg, RegState::Kill)
+ .addReg(Reg, RegState::Kill);
+}
+
+void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ const DebugLoc &DL, MCRegister DestReg,
+ MCRegister SrcReg, bool KillSrc) const {
+ // The MOV instruction is not present in core ISA,
+ // so use OR instruction.
+ if (Xtensa::ARRegClass.contains(DestReg, SrcReg))
+ BuildMI(MBB, MBBI, DL, get(Xtensa::OR), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc))
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ else
+ report_fatal_error("Impossible reg-to-reg copy");
+}
+
+void XtensaInstrInfo::storeRegToStackSlot(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg,
+ bool isKill, int FrameIdx, const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI, Register VReg) const {
+ DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
+ unsigned LoadOpcode, StoreOpcode;
+ getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx);
+ MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, get(StoreOpcode))
+ .addReg(SrcReg, getKillRegState(isKill));
+ addFrameReference(MIB, FrameIdx);
+}
+
+void XtensaInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ Register DestReg, int FrameIdx,
+ const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI,
+ Register VReg) const {
+ DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
+ unsigned LoadOpcode, StoreOpcode;
+ getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx);
+ addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg), FrameIdx);
+}
+
+void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC,
+ unsigned &LoadOpcode,
+ unsigned &StoreOpcode,
+ int64_t offset) const {
+ assert((RC == &Xtensa::ARRegClass) &&
+ "Unsupported regclass to load or store");
+
+ LoadOpcode = Xtensa::L32I;
+ StoreOpcode = Xtensa::S32I;
+}
+
+void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ unsigned *Reg, int64_t Value) const {
+ DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
+ MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo();
+ const TargetRegisterClass *RC = &Xtensa::ARRegClass;
+
+ // create virtual reg to store immediate
+ *Reg = RegInfo.createVirtualRegister(RC);
+ if (Value >= -2048 && Value <= 2047) {
+ BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Value);
+ } else if (Value >= -32768 && Value <= 32767) {
+ int Low = Value & 0xFF;
+ int High = Value & ~0xFF;
+
+ BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Low);
+ BuildMI(MBB, MBBI, DL, get(Xtensa::ADDMI), *Reg).addReg(*Reg).addImm(High);
+ } else if (Value >= -4294967296LL && Value <= 4294967295LL) {
+ // 32 bit arbirary constant
+ MachineConstantPool *MCP = MBB.getParent()->getConstantPool();
+ uint64_t UVal = ((uint64_t)Value) & 0xFFFFFFFFLL;
+ const Constant *CVal = ConstantInt::get(
+ Type::getInt32Ty(MBB.getParent()->getFunction().getContext()), UVal,
+ false);
+ unsigned Idx = MCP->getConstantPoolIndex(CVal, Align(2U));
+ // MCSymbol MSym
+ BuildMI(MBB, MBBI, DL, get(Xtensa::L32R), *Reg).addConstantPoolIndex(Idx);
+ } else {
+ // use L32R to let assembler load immediate best
+ // TODO replace to L32R
+ report_fatal_error("Unsupported load immediate value");
+ }
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
index 8c73c9b..1acd314 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
@@ -35,9 +35,38 @@ class XtensaInstrInfo : public XtensaGenInstrInfo {
public:
XtensaInstrInfo(const XtensaSubtarget &STI);
+ void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const;
+
// Return the XtensaRegisterInfo, which this class owns.
const XtensaRegisterInfo &getRegisterInfo() const { return RI; }
+ void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
+ bool KillSrc) const override;
+
+ void storeRegToStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI, Register SrcReg,
+ bool isKill, int FrameIndex,
+ const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI,
+ Register VReg) const override;
+
+ void loadRegFromStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI, Register DestReg,
+ int FrameIdx, const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI,
+ Register VReg) const override;
+
+ // Get the load and store opcodes for a given register class and offset.
+ void getLoadStoreOpcodes(const TargetRegisterClass *RC, unsigned &LoadOpcode,
+ unsigned &StoreOpcode, int64_t offset) const;
+
+ // Emit code before MBBI in MI to move immediate value Value into
+ // physical register Reg.
+ void loadImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ unsigned *Reg, int64_t Value) const;
+
const XtensaSubtarget &getSubtarget() const { return STI; }
};
} // end namespace llvm
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 268a994..6e9e752 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -14,6 +14,7 @@
include "XtensaInstrFormats.td"
include "XtensaOperands.td"
+include "XtensaOperators.td"
//===----------------------------------------------------------------------===//
// Arithmetic & Logical instructions
@@ -238,6 +239,34 @@ def L32R : RI16_Inst<0x01, (outs AR:$t), (ins L32Rtarget:$label),
let imm16 = label;
}
+// pcrel addr loading using L32R
+def : Pat<(Xtensa_pcrel_wrapper tconstpool : $in), (L32R tconstpool : $in)>;
+
+// FrameIndexes are legalized when they are operands from load/store
+// instructions. The same not happens for stack address copies, so an
+// add op with mem ComplexPattern is used and the stack address copy
+// can be matched.
+// Setting of attribute mayLoad is trick to process instruction operands
+// in function XtensaRegisterInfo::eliminateFI
+
+let isCodeGenOnly = 1, mayLoad = 1 in {
+
+ def LEA_ADD : RRI8_Inst<0x02, (outs AR:$t), (ins mem32:$addr),
+ "addi\t$t, $addr",
+ [(set AR:$t, addr_ish4:$addr)]> {
+ bits<12> addr;
+
+ let r = 0x0C;
+ let imm8{7-0} = addr{11-4};
+ let s{3-0} = addr{3-0};
+ }
+}
+
+//extending loads
+def : Pat<(i32 (extloadi1 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>;
+def : Pat<(i32 (extloadi8 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>;
+def : Pat<(i32 (extloadi16 addr_ish2:$addr)), (L16UI addr_ish2:$addr)>;
+
//===----------------------------------------------------------------------===//
// Conditional branch instructions
//===----------------------------------------------------------------------===//
@@ -426,7 +455,7 @@ let isReturn = 1, isTerminator = 1,
isBarrier = 1, Uses = [A0] in {
def RET : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins),
- "ret", []> {
+ "ret", [(Xtensa_ret)]> {
let m = 0x2;
let n = 0x0;
let s = 0;
@@ -434,6 +463,14 @@ let isReturn = 1, isTerminator = 1,
}
}
+// Call patterns
+def : Pat<(Xtensa_call (i32 tglobaladdr:$dst)),
+ (CALL0 tglobaladdr:$dst)>;
+def : Pat<(Xtensa_call (i32 texternalsym:$dst)),
+ (CALL0 texternalsym:$dst)>;
+def : Pat<(Xtensa_call AR:$dst),
+ (CALLX0 AR:$dst)>;
+
//===----------------------------------------------------------------------===//
// Mem barrier instructions
//===----------------------------------------------------------------------===//
@@ -506,3 +543,19 @@ def XSR : RSR_Inst<0x00, 0x01, 0x06, (outs AR:$ard, SR:$srd), (ins AR:$t, SR:$sr
"xsr\t$t, $sr", []> {
let Constraints = "$ard = $t, $srd = $sr";
}
+
+//===----------------------------------------------------------------------===//
+// Stack allocation
+//===----------------------------------------------------------------------===//
+
+// ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into
+// a stack adjustment and the codegen must know that they may modify the stack
+// pointer before prolog-epilog rewriting occurs.
+let Defs = [SP], Uses = [SP] in {
+ def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
+ "#ADJCALLSTACKDOWN",
+ [(Xtensa_callseq_start timm:$amt1, timm:$amt2)]>;
+ def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
+ "#ADJCALLSTACKUP",
+ [(Xtensa_callseq_end timm:$amt1, timm:$amt2)]>;
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td
index 7a1a2e8..f41081f 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperands.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperands.td
@@ -195,7 +195,7 @@ def jumptarget : Operand<OtherVT> {
let ParserMatchClass = XtensaPCRelTargetAsmOperand;
}
-def L32Rtarget : Operand<OtherVT> {
+def L32Rtarget : Operand<i32> {
let PrintMethod = "printL32RTarget";
let EncoderMethod = "getL32RTargetEncoding";
let DecoderMethod = "decodeL32ROperand";
diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td
new file mode 100644
index 0000000..cd4d831
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/XtensaOperators.td
@@ -0,0 +1,36 @@
+//===- XtensaOperators.td - Xtensa-specific operators ---------*- tblgen-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Type profiles
+//===----------------------------------------------------------------------===//
+def SDT_XtensaCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
+def SDT_XtensaCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
+def SDT_XtensaCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
+
+def SDT_XtensaWrapPtr : SDTypeProfile<1, 1,
+ [SDTCisSameAs<0, 1>,
+ SDTCisPtrTy<0>]>;
+
+//===----------------------------------------------------------------------===//
+// Node definitions
+//===----------------------------------------------------------------------===//
+def Xtensa_call: SDNode<"XtensaISD::CALL", SDT_XtensaCall,
+ [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
+
+def Xtensa_ret: SDNode<"XtensaISD::RET", SDTNone,
+ [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+
+def Xtensa_pcrel_wrapper: SDNode<"XtensaISD::PCREL_WRAPPER", SDT_XtensaWrapPtr, []>;
+
+def Xtensa_callseq_start: SDNode<"ISD::CALLSEQ_START", SDT_XtensaCallSeqStart,
+ [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>;
+
+def Xtensa_callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_XtensaCallSeqEnd,
+ [SDNPHasChain, SDNPSideEffect, SDNPOptInGlue,
+ SDNPOutGlue]>;
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
index f749cc5..bced2d4 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
@@ -13,6 +13,9 @@
#include "XtensaRegisterInfo.h"
#include "XtensaInstrInfo.h"
#include "XtensaSubtarget.h"
+#include "XtensaUtils.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
@@ -31,15 +34,13 @@ XtensaRegisterInfo::XtensaRegisterInfo(const XtensaSubtarget &STI)
const uint16_t *
XtensaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
- // Calling convention is not implemented yet
- return nullptr;
+ return CSR_Xtensa_SaveList;
}
const uint32_t *
XtensaRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const {
- // Calling convention is not implemented yet
- return nullptr;
+ return CSR_Xtensa_RegMask;
}
BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
@@ -60,7 +61,70 @@ BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS) const {
- report_fatal_error("Eliminate frame index not supported yet");
+ MachineInstr &MI = *II;
+ MachineFunction &MF = *MI.getParent()->getParent();
+ int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
+ uint64_t StackSize = MF.getFrameInfo().getStackSize();
+ int64_t SPOffset = MF.getFrameInfo().getObjectOffset(FrameIndex);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
+ int MinCSFI = 0;
+ int MaxCSFI = -1;
+
+ if (CSI.size()) {
+ MinCSFI = CSI[0].getFrameIdx();
+ MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
+ }
+ // The following stack frame objects are always referenced relative to $sp:
+ // 1. Outgoing arguments.
+ // 2. Pointer to dynamically allocated stack space.
+ // 3. Locations for callee-saved registers.
+ // 4. Locations for eh data registers.
+ // Everything else is referenced relative to whatever register
+ // getFrameRegister() returns.
+ unsigned FrameReg;
+ if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI))
+ FrameReg = Xtensa::SP;
+ else
+ FrameReg = getFrameRegister(MF);
+
+ // Calculate final offset.
+ // - There is no need to change the offset if the frame object is one of the
+ // following: an outgoing argument, pointer to a dynamically allocated
+ // stack space or a $gp restore location,
+ // - If the frame object is any of the following, its offset must be adjusted
+ // by adding the size of the stack:
+ // incoming argument, callee-saved register location or local variable.
+ bool IsKill = false;
+ int64_t Offset =
+ SPOffset + (int64_t)StackSize + MI.getOperand(FIOperandNum + 1).getImm();
+
+ bool Valid = isValidAddrOffset(MI, Offset);
+
+ // If MI is not a debug value, make sure Offset fits in the 16-bit immediate
+ // field.
+ if (!MI.isDebugValue() && !Valid) {
+ MachineBasicBlock &MBB = *MI.getParent();
+ DebugLoc DL = II->getDebugLoc();
+ unsigned ADD = Xtensa::ADD;
+ unsigned Reg;
+ const XtensaInstrInfo &TII = *static_cast<const XtensaInstrInfo *>(
+ MBB.getParent()->getSubtarget().getInstrInfo());
+
+ TII.loadImmediate(MBB, II, &Reg, Offset);
+ BuildMI(MBB, II, DL, TII.get(ADD), Reg)
+ .addReg(FrameReg)
+ .addReg(Reg, RegState::Kill);
+
+ FrameReg = Reg;
+ Offset = 0;
+ IsKill = true;
+ }
+
+ MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false, false, IsKill);
+ MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
+
+ return false;
}
Register XtensaRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
diff --git a/llvm/lib/Target/Xtensa/XtensaUtils.cpp b/llvm/lib/Target/Xtensa/XtensaUtils.cpp
new file mode 100644
index 0000000..98e424f
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/XtensaUtils.cpp
@@ -0,0 +1,59 @@
+//===--- XtensaUtils.cpp ---- Xtensa Utility Functions ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains miscellaneous utility functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "XtensaUtils.h"
+
+namespace llvm {
+
+bool isValidAddrOffset(int Scale, int64_t OffsetVal) {
+ bool Valid = false;
+
+ switch (Scale) {
+ case 1:
+ Valid = (OffsetVal >= 0 && OffsetVal <= 255);
+ break;
+ case 2:
+ Valid = (OffsetVal >= 0 && OffsetVal <= 510) && ((OffsetVal & 0x1) == 0);
+ break;
+ case 4:
+ Valid = (OffsetVal >= 0 && OffsetVal <= 1020) && ((OffsetVal & 0x3) == 0);
+ break;
+ default:
+ break;
+ }
+ return Valid;
+}
+
+bool isValidAddrOffset(MachineInstr &MI, int64_t Offset) {
+ int Scale = 0;
+
+ switch (MI.getOpcode()) {
+ case Xtensa::L8UI:
+ case Xtensa::S8I:
+ Scale = 1;
+ break;
+ case Xtensa::L16SI:
+ case Xtensa::L16UI:
+ case Xtensa::S16I:
+ Scale = 2;
+ break;
+ case Xtensa::LEA_ADD:
+ return (Offset >= -128 && Offset <= 127);
+ default:
+ // assume that MI is 32-bit load/store operation
+ Scale = 4;
+ break;
+ }
+ return isValidAddrOffset(Scale, Offset);
+}
+
+} // namespace llvm
diff --git a/llvm/lib/Target/Xtensa/XtensaUtils.h b/llvm/lib/Target/Xtensa/XtensaUtils.h
new file mode 100644
index 0000000..2b0ac37
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/XtensaUtils.h
@@ -0,0 +1,27 @@
+//===--- XtensaUtils.h ---- Xtensa Utility Functions ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains miscellaneous utility functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_XTENSA_XTENSAUTILS_H
+#define LLVM_LIB_TARGET_XTENSA_XTENSAUTILS_H
+
+#include "XtensaInstrInfo.h"
+#include "llvm/CodeGen/MachineInstr.h"
+
+namespace llvm {
+// Check address offset for load/store instructions.
+// The offset should be multiple of scale.
+bool isValidAddrOffset(int Scale, int64_t OffsetVal);
+
+// Check address offset for load/store instructions.
+bool isValidAddrOffset(MachineInstr &MI, int64_t Offset);
+} // namespace llvm
+#endif // LLVM_LIB_TARGET_XTENSA_XTENSAUTILS_H
diff --git a/llvm/test/CodeGen/Xtensa/call.ll b/llvm/test/CodeGen/Xtensa/call.ll
new file mode 100644
index 0000000..24c7c4f
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/call.ll
@@ -0,0 +1,49 @@
+; RUN: llc --mtriple=xtensa < %s | FileCheck %s
+
+declare i32 @external_function(i32)
+
+define i32 @test_call_external(i32 %a) nounwind {
+; CHECK-LABEL: test_call_external:
+; CHECK: # %bb.0:
+; CHECK-NEXT: s32i a0, a1, 0
+; CHECK-NEXT: l32r a8, .LCPI0_0
+; CHECK-NEXT: callx0 a8
+; CHECK-NEXT: l32i a0, a1, 0
+; CHECK-NEXT: ret
+ %1 = call i32 @external_function(i32 %a)
+ ret i32 %1
+}
+
+define i32 @defined_function(i32 %a) nounwind {
+; CHECK-LABEL: defined_function:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi a2, a2, 1
+; CHECK-NEXT: ret
+ %1 = add i32 %a, 1
+ ret i32 %1
+}
+
+define i32 @test_call_defined(i32 %a) nounwind {
+; CHECK-LABEL: test_call_defined:
+; CHECK: # %bb.0:
+; CHECK-NEXT: s32i a0, a1, 0
+; CHECK-NEXT: l32r a8, .LCPI2_0
+; CHECK-NEXT: callx0 a8
+; CHECK-NEXT: l32i a0, a1, 0
+; CHECK-NEXT: ret
+ %1 = call i32 @defined_function(i32 %a) nounwind
+ ret i32 %1
+}
+
+define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
+; CHECK-LABEL: test_call_indirect:
+; CHECK: # %bb.0:
+; CHECK-NEXT: s32i a0, a1, 0
+; CHECK-NEXT: or a8, a2, a2
+; CHECK-NEXT: or a2, a3, a3
+; CHECK-NEXT: callx0 a8
+; CHECK-NEXT: l32i a0, a1, 0
+; CHECK-NEXT: ret
+ %1 = call i32 %a(i32 %b)
+ ret i32 %1
+}
diff --git a/llvm/test/CodeGen/Xtensa/calling-conv.ll b/llvm/test/CodeGen/Xtensa/calling-conv.ll
new file mode 100644
index 0000000..41ae422
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/calling-conv.ll
@@ -0,0 +1,78 @@
+; RUN: llc -mtriple=xtensa -O1 -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=XTENSA
+
+; Check placement of first 6 arguments in registers and 7th argument on stack
+define dso_local i32 @test1(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, i32 noundef %4, i32 noundef %5, ptr nocapture noundef readonly byval(i32) align 4 %6) {
+; XTENSA-LABEL: @test1
+; XTENSA: add a8, a7, a2
+; XTENSA: l32i a9, a1, 0
+; XTENSA: add a2, a8, a9
+; XTENSA: ret
+ %8 = load i32, ptr %6, align 4
+ %9 = add nsw i32 %5, %0
+ %10 = add nsw i32 %9, %8
+ ret i32 %10
+}
+
+; Check placement of second i64 argument in registers
+define dso_local i32 @test2(i32 noundef %0, i64 noundef %1, i32 noundef %2) {
+; XTENSA-LABEL: @test2
+; XTENSA: add a8, a6, a2
+; XTENSA: add a2, a8, a4
+; XTENSA: ret
+ %4 = trunc i64 %1 to i32
+ %5 = add nsw i32 %2, %0
+ %6 = add nsw i32 %5, %4
+ ret i32 %6
+}
+
+; Check placement of first argument typeof i8 in register
+define dso_local i32 @test3(i8 noundef signext %0, i64 noundef %1, i32 noundef %2) {
+; XTENSA-LABEL: @test3
+; XTENSA: add a8, a2, a6
+; XTENSA: add a2, a8, a4
+; XTENSA: ret
+ %4 = trunc i64 %1 to i32
+ %5 = sext i8 %0 to i32
+ %6 = add nsw i32 %5, %2
+ %7 = add nsw i32 %6, %4
+ ret i32 %7
+}
+
+; Check placement of 4th argument typeof i64 on stack
+define dso_local i32 @test4(i8 noundef signext %0, i64 noundef %1, i32 noundef %2, ptr nocapture noundef readonly byval(i64) align 8 %3) {
+; XTENSA-LABEL: @test4
+; XTENSA: add a8, a2, a6
+; XTENSA: add a8, a8, a4
+; XTENSA: l32i a9, a1, 0
+; XTENSA: add a2, a8, a9
+; XTENSA: ret
+ %5 = load i64, ptr %3, align 8
+ %6 = trunc i64 %1 to i32
+ %7 = trunc i64 %5 to i32
+ %8 = sext i8 %0 to i32
+ %9 = add nsw i32 %8, %2
+ %10 = add nsw i32 %9, %6
+ %11 = add nsw i32 %10, %7
+ ret i32 %11
+}
+
+; Check placement of 128 bit structure on registers
+define dso_local i32 @test5([4 x i32] %0, i32 noundef %1) {
+; XTENSA-LABEL: @test5
+; XTENSA: add a2, a2, a6
+; XTENSA: ret
+ %3 = extractvalue [4 x i32] %0, 0
+ %4 = add nsw i32 %3, %1
+ ret i32 %4
+}
+
+; Check placement of 128 bit structure on stack
+define dso_local i32 @test6(i32 noundef %0, [4 x i32] %1) {
+; XTENSA-LABEL: @test6
+; XTENSA: add a2, a3, a2
+; XTENSA: ret
+ %3 = extractvalue [4 x i32] %1, 0
+ %4 = add nsw i32 %3, %0
+ ret i32 %4
+}
diff --git a/llvm/test/CodeGen/Xtensa/constantpool.ll b/llvm/test/CodeGen/Xtensa/constantpool.ll
new file mode 100644
index 0000000..9b380d2
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/constantpool.ll
@@ -0,0 +1,28 @@
+; RUN: llc -mtriple=xtensa -verify-machineinstrs < %s \
+; RUN: | FileCheck %s
+
+; Test placement of the i32,i64, float and double constants in constantpool
+
+define dso_local i32 @const_i32() #0 {
+; CHECK: .literal_position
+; CHECK-NEXT: .literal .LCPI0_0, 74565
+; CHECK-LABEL: const_i32:
+; CHECK: l32r a2, .LCPI0_0
+ %1 = alloca i32, align 4
+ store i32 74565, ptr %1, align 4
+ %2 = load i32, ptr %1, align 4
+ ret i32 %2
+}
+
+define dso_local i64 @const_int64() #0 {
+; CHECK: .literal_position
+; CHECK-NEXT: .literal .LCPI1_0, 305419896
+; CHECK-NEXT: .literal .LCPI1_1, -1859959449
+; CHECK-LABEL: const_int64:
+; CHECK: l32r a3, .LCPI1_0
+; CHECK: l32r a2, .LCPI1_1
+ %1 = alloca i64, align 8
+ store i64 1311768467302729063, ptr %1, align 8
+ %2 = load i64, ptr %1, align 8
+ ret i64 %2
+}
diff --git a/llvm/test/CodeGen/Xtensa/stack-access.ll b/llvm/test/CodeGen/Xtensa/stack-access.ll
new file mode 100644
index 0000000..1590d24
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/stack-access.ll
@@ -0,0 +1,35 @@
+; RUN: llc -mtriple=xtensa -O0 -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=XTENSA
+
+define i8 @loadi8(i8 %a) {
+; XTENSA-LABEL: loadi8:
+; XTENSA: s8i a2, a1, 3
+; XTENSA: l8ui a2, a1, 3
+; XTENSA: ret
+ %b = alloca i8, align 1
+ store i8 %a, ptr %b, align 1
+ %1 = load i8, ptr %b, align 1
+ ret i8 %1
+}
+
+define i16 @loadi16(i16 %a) {
+; XTENSA-LABEL: loadi16:
+; XTENSA: s16i a2, a1, 2
+; XTENSA: l16ui a2, a1, 2
+; XTENSA: ret
+ %b = alloca i16, align 2
+ store i16 %a, ptr %b, align 2
+ %1 = load i16, ptr %b, align 2
+ ret i16 %1
+}
+
+define i32 @loadi32(i32 %a) {
+; XTENSA-LABEL: loadi32:
+; XTENSA: s32i a2, a1, 0
+; XTENSA: l32i a2, a1, 0
+; XTENSA: ret
+ %b = alloca i32, align 4
+ store i32 %a, ptr %b, align 4
+ %1 = load i32, ptr %b, align 4
+ ret i32 %1
+}
diff --git a/llvm/test/MC/Xtensa/Core/invalid.s b/llvm/test/MC/Xtensa/Core/invalid.s
index d3d8fba..c7473e9 100644
--- a/llvm/test/MC/Xtensa/Core/invalid.s
+++ b/llvm/test/MC/Xtensa/Core/invalid.s
@@ -4,10 +4,6 @@ LBL0:
# Out of range immediates
-# imm12m
-movi a1, 3000
-# CHECK: :[[#@LINE-1]]:10: error: expected immediate in range [-2048, 2047]
-
# imm8
addi a1, a2, 300
# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [-128, 127]
diff --git a/llvm/test/MC/Xtensa/directive-literal.s b/llvm/test/MC/Xtensa/directive-literal.s
new file mode 100644
index 0000000..269cf20
--- /dev/null
+++ b/llvm/test/MC/Xtensa/directive-literal.s
@@ -0,0 +1,42 @@
+# RUN: llvm-mc -triple=xtensa -filetype obj -o - %s \
+# RUN: | llvm-readobj -S --sd - \
+# RUN: | FileCheck -check-prefix=CHECK-LITERAL %s
+
+# RUN: llvm-mc %s -triple=xtensa -show-encoding \
+# RUN: | FileCheck -check-prefix=CHECK-INST %s
+
+ .text
+ .literal_position
+ .literal .LCPI0_0, 305419896
+ .literal .LCPI1_0, ext_var
+ .global test_literal
+ .p2align 2
+ .type test_literal,@function
+test_literal:
+ l32r a2, .LCPI0_0
+ l32r a3, .LCPI1_0
+ movi a4, 30000
+ movi a5, 1000
+ ret
+
+# CHECK-LITERAL: Section {
+# CHECK-LITERAL: Name: .literal
+# CHECK-LITERAL: SectionData (
+# CHECK-LITERAL: 0000: 78563412 00000000 30750000
+# CHECK-LITERAL: )
+# CHECK-LITERAL: }
+
+# CHECK-INST: .literal_position
+# CHECK-INST: .literal .LCPI0_0, 305419896
+# CHECK-INST: .literal .LCPI1_0, ext_var
+# CHECK-INST: .global test_literal
+# CHECK-INST: .p2align 2
+# CHECK-INST: .type test_literal,@function
+# CHECK-INST: test_literal:
+# CHECK-INST: l32r a2, .LCPI0_0
+# CHECK-INST: l32r a3, .LCPI1_0
+# CHECK-INST: .literal .Ltmp0, 30000
+# CHECK-INST: l32r a4, .Ltmp0
+# CHECK-INST: movi a5, 1000
+# CHECK-INST: ret
+
diff --git a/llvm/test/MC/Xtensa/invalid-literal.s b/llvm/test/MC/Xtensa/invalid-literal.s
new file mode 100644
index 0000000..ebb3744
--- /dev/null
+++ b/llvm/test/MC/Xtensa/invalid-literal.s
@@ -0,0 +1,10 @@
+# RUN: not llvm-mc %s -triple=xtensa -filetype=asm 2>&1 | FileCheck %s
+
+.text
+.literal_position
+.literal .LCPI0_0 a
+# CHECK: [[@LINE-1]]:20: error: expected comma
+.literal 123, a
+# CHECK: [[@LINE-1]]:10: error: literal label must be a symbol
+.literal .LCPI1_0,
+# CHECK: [[@LINE-1]]:19: error: expected value