[llvm] [Xtensa] Implement Xtensa Floating Point Option. (PR #136086)
Andrei Safronov via llvm-commits
llvm-commits at lists.llvm.org
Tue May 27 02:53:01 PDT 2025
https://github.com/andreisfr updated https://github.com/llvm/llvm-project/pull/136086
>From 94b8fbe4219ebc3642ebe4d03dc02720be3bb568 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Thu, 24 Apr 2025 10:38:22 +0300
Subject: [PATCH 1/5] [Xtensa] Implement Xtensa Floating Point Option.
---
.../Disassembler/XtensaDisassembler.cpp | 38 ++
.../MCTargetDesc/XtensaMCCodeEmitter.cpp | 5 +
llvm/lib/Target/Xtensa/XtensaCallingConv.td | 1 +
llvm/lib/Target/Xtensa/XtensaFeatures.td | 5 +
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 168 +++++-
llvm/lib/Target/Xtensa/XtensaISelLowering.h | 23 +
llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 14 +-
llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 291 +++++++++
llvm/lib/Target/Xtensa/XtensaOperators.td | 17 +
llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 44 ++
llvm/lib/Target/Xtensa/XtensaSubtarget.h | 1 +
llvm/test/CodeGen/Xtensa/float-arith.ll | 569 ++++++++++++++++++
llvm/test/MC/Xtensa/float-err.s | 37 ++
llvm/test/MC/Xtensa/float.s | 177 ++++++
14 files changed, 1384 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/Xtensa/float-arith.ll
create mode 100644 llvm/test/MC/Xtensa/float-err.s
create mode 100644 llvm/test/MC/Xtensa/float.s
diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
index 6b355e6363b22..237aed3cc71ea 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -113,6 +113,44 @@ static DecodeStatus DecodeMR23RegisterClass(MCInst &Inst, uint64_t RegNo,
return MCDisassembler::Success;
}
+static const unsigned FPRDecoderTable[] = {
+ Xtensa::F0, Xtensa::F1, Xtensa::F2, Xtensa::F3, Xtensa::F4, Xtensa::F5,
+ Xtensa::F6, Xtensa::F7, Xtensa::F8, Xtensa::F9, Xtensa::F10, Xtensa::F11,
+ Xtensa::F12, Xtensa::F13, Xtensa::F14, Xtensa::F15};
+
+static DecodeStatus DecodeFPRRegisterClass(MCInst &Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo >= std::size(FPRDecoderTable))
+ return MCDisassembler::Fail;
+
+ unsigned Reg = FPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static const unsigned URDecoderTable[] = {Xtensa::FCR, 232, Xtensa::FSR, 233};
+
+static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ const llvm::MCSubtargetInfo STI =
+ ((const MCDisassembler *)Decoder)->getSubtargetInfo();
+
+ if (RegNo > 255)
+ return MCDisassembler::Fail;
+
+ for (unsigned i = 0; i < std::size(URDecoderTable); i += 2) {
+ if (URDecoderTable[i + 1] == RegNo) {
+ unsigned Reg = URDecoderTable[i];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+ }
+ }
+
+ return MCDisassembler::Fail;
+}
+
const MCPhysReg SRDecoderTable[] = {
Xtensa::SAR, 3, Xtensa::ACCLO, 16, Xtensa::ACCHI, 17,
Xtensa::M0, 32, Xtensa::M1, 33, Xtensa::M2, 34,
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
index 8231a8a9a44d4..03b3ed0c121be 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
@@ -307,6 +307,11 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo,
case Xtensa::L32I:
case Xtensa::S32I_N:
case Xtensa::L32I_N:
+ case Xtensa::SSI:
+ case Xtensa::SSIP:
+ case Xtensa::LSI:
+ case Xtensa::LSIP:
+
if (Res & 0x3) {
report_fatal_error("Unexpected operand value!");
}
diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
index 2c48f8f86cafb..96528ed283a30 100644
--- a/llvm/lib/Target/Xtensa/XtensaCallingConv.td
+++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
@@ -15,6 +15,7 @@
def RetCC_Xtensa : CallingConv<[
// First two return values go in a2, a3, a4, a5
CCIfType<[i32], CCAssignToReg<[A2, A3, A4, A5]>>,
+ CCIfType<[f32], CCAssignToReg<[A2, A3, A4, A5]>>,
CCIfType<[i64], CCAssignToRegWithShadow<[A2, A4], [A3, A5]>>
]>;
diff --git a/llvm/lib/Target/Xtensa/XtensaFeatures.td b/llvm/lib/Target/Xtensa/XtensaFeatures.td
index 2a47214946401..31084d63879d1 100644
--- a/llvm/lib/Target/Xtensa/XtensaFeatures.td
+++ b/llvm/lib/Target/Xtensa/XtensaFeatures.td
@@ -8,6 +8,11 @@ def FeatureDensity : SubtargetFeature<"density", "HasDensity", "true",
def HasDensity : Predicate<"Subtarget->hasDensity()">,
AssemblerPredicate<(all_of FeatureDensity)>;
+def FeatureSingleFloat : SubtargetFeature<"fp", "HasSingleFloat", "true",
+ "Enable Xtensa Single FP instructions">;
+def HasSingleFloat : Predicate<"Subtarget->hasSingleFloat()">,
+ AssemblerPredicate<(all_of FeatureSingleFloat)>;
+
def FeatureWindowed : SubtargetFeature<"windowed", "HasWindowed", "true",
"Enable Xtensa Windowed Register option">;
def HasWindowed : Predicate<"Subtarget->hasWindowed()">,
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index b17840aad9b4d..83f58607c9d37 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -58,6 +58,10 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
// Set up the register classes.
addRegisterClass(MVT::i32, &Xtensa::ARRegClass);
+ if (Subtarget.hasSingleFloat()) {
+ addRegisterClass(MVT::f32, &Xtensa::FPRRegClass);
+ }
+
if (Subtarget.hasBoolean()) {
addRegisterClass(MVT::v1i1, &Xtensa::BRRegClass);
}
@@ -71,6 +75,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::Constant, MVT::i32, Custom);
setOperationAction(ISD::Constant, MVT::i64, Expand);
+ setOperationAction(ISD::ConstantFP, MVT::f32, Custom);
+ setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
setBooleanContents(ZeroOrOneBooleanContent);
@@ -108,7 +114,10 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SELECT, MVT::i32, Expand);
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
+
setOperationAction(ISD::SETCC, MVT::i32, Expand);
+ setOperationAction(ISD::SETCC, MVT::f32, Expand);
setCondCodeAction(ISD::SETGT, MVT::i32, Expand);
setCondCodeAction(ISD::SETLE, MVT::i32, Expand);
@@ -175,6 +184,103 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::VACOPY, MVT::Other, Custom);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
+ // Handle floating-point types.
+ for (unsigned I = MVT::FIRST_FP_VALUETYPE; I <= MVT::LAST_FP_VALUETYPE; ++I) {
+ MVT VT = MVT::SimpleValueType(I);
+ if (isTypeLegal(VT)) {
+ // We can use FI for FRINT.
+ // setOperationAction(ISD::FRINT, VT, Legal);
+ if (VT.getSizeInBits() == 32 && Subtarget.hasSingleFloat()) {
+ setOperationAction(ISD::FABS, VT, Legal);
+ setOperationAction(ISD::FADD, VT, Legal);
+ setOperationAction(ISD::FSUB, VT, Legal);
+ setOperationAction(ISD::FMA, VT, Legal);
+ setOperationAction(ISD::FMUL, VT, Legal);
+ setOperationAction(ISD::FNEG, VT, Legal);
+ } else {
+ setOperationAction(ISD::FABS, VT, Expand);
+ setOperationAction(ISD::FADD, VT, Expand);
+ setOperationAction(ISD::FSUB, VT, Expand);
+ setOperationAction(ISD::FMA, VT, Expand);
+ setOperationAction(ISD::FMUL, VT, Expand);
+ setOperationAction(ISD::FNEG, VT, Expand);
+ }
+
+ // TODO: once implemented in InstrInfo uncomment
+ setOperationAction(ISD::FSQRT, VT, Expand);
+
+ // No special instructions for these.
+ setOperationAction(ISD::FCBRT, VT, Expand);
+ setOperationAction(ISD::FCEIL, VT, Expand);
+ setOperationAction(ISD::FSIN, VT, Expand);
+ setOperationAction(ISD::FCOS, VT, Expand);
+ setOperationAction(ISD::FREM, VT, Expand);
+ setOperationAction(ISD::FDIV, VT, Expand);
+ setOperationAction(ISD::FEXP, VT, Expand);
+ setOperationAction(ISD::FEXP2, VT, Expand);
+ setOperationAction(ISD::FFLOOR, VT, Expand);
+ setOperationAction(ISD::FLOG, VT, Expand);
+ setOperationAction(ISD::FLOG2, VT, Expand);
+ setOperationAction(ISD::FLOG10, VT, Expand);
+ setOperationAction(ISD::FMAXIMUM, VT, Expand);
+ setOperationAction(ISD::FMINIMUM, VT, Expand);
+ setOperationAction(ISD::FMAXNUM, VT, Expand);
+ setOperationAction(ISD::FMINNUM, VT, Expand);
+ setOperationAction(ISD::FNEARBYINT, VT, Expand);
+ setOperationAction(ISD::FPOW, VT, Expand);
+ setOperationAction(ISD::FPOWI, VT, Expand);
+ setOperationAction(ISD::FRINT, VT, Expand);
+ setOperationAction(ISD::FROUND, VT, Expand);
+ setOperationAction(ISD::FSINCOS, VT, Expand);
+ setOperationAction(ISD::FSQRT, VT, Expand);
+ setOperationAction(ISD::FTRUNC, VT, Expand);
+ setOperationAction(ISD::LLRINT, VT, Expand);
+ setOperationAction(ISD::LLROUND, VT, Expand);
+ setOperationAction(ISD::LRINT, VT, Expand);
+ setOperationAction(ISD::LROUND, VT, Expand);
+ }
+ }
+
+ // Handle floating-point types.
+ if (Subtarget.hasSingleFloat()) {
+ setOperationAction(ISD::BITCAST, MVT::i32, Legal);
+ setOperationAction(ISD::BITCAST, MVT::f32, Legal);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i32, Legal);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i32, Legal);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal);
+
+ setCondCodeAction(ISD::SETOGT, MVT::f32, Expand);
+ setCondCodeAction(ISD::SETOGE, MVT::f32, Expand);
+ setCondCodeAction(ISD::SETONE, MVT::f32, Expand);
+ setCondCodeAction(ISD::SETUGE, MVT::f32, Expand);
+ setCondCodeAction(ISD::SETUGT, MVT::f32, Expand);
+ } else {
+ 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);
+ }
+ setOperationAction(ISD::FMA, MVT::f64, Expand);
+ setOperationAction(ISD::SETCC, MVT::f64, Expand);
+ setOperationAction(ISD::BITCAST, MVT::i64, Expand);
+ setOperationAction(ISD::BITCAST, MVT::f64, Expand);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i64, Expand);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i64, Expand);
+
+ // Needed so that we don't try to implement f128 constant loads using
+ // a load-and-extend of a f80 constant (in cases where the constant
+ // would fit in an f80).
+ for (MVT VT : MVT::fp_valuetypes())
+ setLoadExtAction(ISD::EXTLOAD, VT, MVT::f80, Expand);
+
+ // Floating-point truncation and stores need to be done separately.
+ setTruncStoreAction(MVT::f64, MVT::f32, Expand);
+
// Compute derived properties from the register classes
computeRegisterProperties(STI.getRegisterInfo());
}
@@ -185,6 +291,11 @@ bool XtensaTargetLowering::isOffsetFoldingLegal(
return false;
}
+bool XtensaTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
+ bool ForCodeSize) const {
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Inline asm support
//===----------------------------------------------------------------------===//
@@ -335,6 +446,16 @@ static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT,
return false;
}
+/// Return the register type for a given MVT
+MVT XtensaTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
+ CallingConv::ID CC,
+ EVT VT) const {
+ if (VT.isFloatingPoint())
+ return MVT::i32;
+
+ return TargetLowering::getRegisterTypeForCallingConv(Context, CC, VT);
+}
+
CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
bool IsVarArg) const {
return CC_Xtensa_Custom;
@@ -815,6 +936,21 @@ SDValue XtensaTargetLowering::LowerImmediate(SDValue Op,
return Op;
}
+SDValue XtensaTargetLowering::LowerImmediateFP(SDValue Op,
+ SelectionDAG &DAG) const {
+ const ConstantFPSDNode *CN = cast<ConstantFPSDNode>(Op);
+ SDLoc DL(CN);
+ APFloat apval = CN->getValueAPF();
+ int64_t value = llvm::bit_cast<uint32_t>(CN->getValueAPF().convertToFloat());
+ if (Op.getValueType() == MVT::f32) {
+ Type *Ty = Type::getInt32Ty(*DAG.getContext());
+ Constant *CV = ConstantInt::get(Ty, value);
+ SDValue CP = DAG.getConstantPool(CV, MVT::i32);
+ return DAG.getNode(ISD::BITCAST, DL, MVT::f32, CP);
+ }
+ return Op;
+}
+
SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) const {
const GlobalAddressSDNode *G = cast<GlobalAddressSDNode>(Op);
@@ -1248,6 +1384,8 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
return LowerBR_JT(Op, DAG);
case ISD::Constant:
return LowerImmediate(Op, DAG);
+ case ISD::ConstantFP:
+ return LowerImmediateFP(Op, DAG);
case ISD::RETURNADDR:
return LowerRETURNADDR(Op, DAG);
case ISD::GlobalAddress:
@@ -1311,6 +1449,26 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const {
return "XtensaISD::SRCL";
case XtensaISD::SRCR:
return "XtensaISD::SRCR";
+ case XtensaISD::CMPUO:
+ return "XtensaISD::CMPUO";
+ case XtensaISD::CMPUEQ:
+ return "XtensaISD::CMPUEQ";
+ case XtensaISD::CMPULE:
+ return "XtensaISD::CMPULE";
+ case XtensaISD::CMPULT:
+ return "XtensaISD::CMPULT";
+ case XtensaISD::CMPOEQ:
+ return "XtensaISD::CMPOEQ";
+ case XtensaISD::CMPOLE:
+ return "XtensaISD::CMPOLE";
+ case XtensaISD::CMPOLT:
+ return "XtensaISD::CMPOLT";
+ case XtensaISD::MADD:
+ return "XtensaISD::MADD";
+ case XtensaISD::MSUB:
+ return "XtensaISD::MSUB";
+ case XtensaISD::MOVS:
+ return "XtensaISD::MOVS";
}
return nullptr;
}
@@ -1395,11 +1553,19 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter(
case Xtensa::S16I:
case Xtensa::S32I:
case Xtensa::S32I_N:
+ case Xtensa::SSI:
+ case Xtensa::SSIP:
+ case Xtensa::SSX:
+ case Xtensa::SSXP:
case Xtensa::L8UI:
case Xtensa::L16SI:
case Xtensa::L16UI:
case Xtensa::L32I:
- case Xtensa::L32I_N: {
+ case Xtensa::L32I_N:
+ case Xtensa::LSI:
+ case Xtensa::LSIP:
+ case Xtensa::LSX:
+ case Xtensa::LSXP: {
// Insert memory wait instruction "memw" before volatile load/store as it is
// implemented in gcc. If memoperands is empty then assume that it aslo
// maybe volatile load/store and insert "memw".
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
index c7d4f41b1f08e..850ec6f3b023a 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
@@ -56,6 +56,21 @@ enum {
SRCL,
// Shift Right Combined
SRCR,
+
+ // Floating point unordered compare conditions
+ CMPUEQ,
+ CMPULE,
+ CMPULT,
+ CMPUO,
+ // Floating point compare conditions
+ CMPOEQ,
+ CMPOLE,
+ CMPOLT,
+ // FP multipy-add/sub
+ MADD,
+ MSUB,
+ // FP move
+ MOVS,
};
}
@@ -70,6 +85,9 @@ class XtensaTargetLowering : public TargetLowering {
return LHSTy.getSizeInBits() <= 32 ? MVT::i32 : MVT::i64;
}
+ MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC,
+ EVT VT) const override;
+
EVT getSetCCResultType(const DataLayout &, LLVMContext &,
EVT VT) const override {
if (!VT.isVector())
@@ -81,6 +99,9 @@ class XtensaTargetLowering : public TargetLowering {
const char *getTargetNodeName(unsigned Opcode) const override;
+ bool isFPImmLegal(const APFloat &Imm, EVT VT,
+ bool ForCodeSize) const override;
+
std::pair<unsigned, const TargetRegisterClass *>
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint, MVT VT) const override;
@@ -133,6 +154,8 @@ class XtensaTargetLowering : public TargetLowering {
SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerImmediateFP(SDValue Op, SelectionDAG &DAG) const;
+
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
index 005532b864c41..5b1bc73267157 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
@@ -151,11 +151,15 @@ 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;
+ if (RC == &Xtensa::ARRegClass) {
+ LoadOpcode = Xtensa::L32I;
+ StoreOpcode = Xtensa::S32I;
+ } else if (RC == &Xtensa::FPRRegClass) {
+ LoadOpcode = Xtensa::LSI;
+ StoreOpcode = Xtensa::SSI;
+ } else {
+ llvm_unreachable("Unsupported regclass to load or store");
+ }
}
void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 0bd3ba81340ff..758277f7f601f 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -986,6 +986,297 @@ let Predicates = [HasDiv32] in {
def REMU : ArithLogic_RRR<0x0E, 0x02, "remu", urem>;
}
+//===----------------------------------------------------------------------===//
+// Floating-Point Instructions
+//===----------------------------------------------------------------------===//
+
+class FPArith_RRR<bits<4> oper2, bits<4> oper1, string instrAsm,
+ SDPatternOperator opNode, bit isComm = 0>
+ : RRR_Inst<0x00, oper1, oper2, (outs FPR:$r), (ins FPR:$s, FPR:$t),
+ instrAsm#"\t$r, $s, $t",
+ [(set FPR:$r, (opNode FPR:$s, FPR:$t))]> {
+ let isCommutable = isComm;
+ let isReMaterializable = 0;
+ let Predicates = [HasSingleFloat];
+}
+
+def ADD_S : FPArith_RRR<0x00, 0x0A, "add.s", fadd, 1>;
+def SUB_S : FPArith_RRR<0x01, 0x0A, "sub.s", fsub>;
+def MUL_S : FPArith_RRR<0x02, 0x0A, "mul.s", fmul, 1>;
+
+// FP load instructions
+let mayLoad = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in {
+ def LSI : RRI8_Inst<0x03, (outs FPR:$t), (ins mem32:$addr),
+ "lsi\t$t, $addr", []> {
+ bits<12> addr;
+
+ let r = 0x00;
+ let imm8{7-0} = addr{11-4};
+ let s{3-0} = addr{3-0};
+ }
+
+ def LSIP : RRI8_Inst<0x03, (outs FPR:$t), (ins mem32:$addr),
+ "lsip\t$t, $addr", []> {
+ bits<12> addr;
+
+ let r = 0x08;
+ let imm8{7-0} = addr{11-4};
+ let s{3-0} = addr{3-0};
+ }
+
+ def LSX : RRR_Inst<0x00, 0x08, 0x00, (outs), (ins FPR:$r, AR:$s, AR:$t),
+ "lsx\t$r, $s, $t", []>;
+
+ def LSXP : RRR_Inst<0x00, 0x08, 0x01, (outs), (ins FPR:$r, AR:$s, AR:$t),
+ "lsxp\t$r, $s, $t", []>;
+}
+
+def : Pat<(f32 (load addr_ish4:$addr)), (f32 (LSI mem32:$addr))>;
+
+// FP store instructions
+let mayStore = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in {
+ def SSI : RRI8_Inst<0x03, (outs), (ins FPR:$t, mem32:$addr),
+ "ssi\t$t, $addr", []> {
+ bits<12> addr;
+
+ let r = 0x04;
+ let imm8{7-0} = addr{11-4};
+ let s{3-0} = addr{3-0};
+ }
+
+ def SSIP : RRI8_Inst<0x03, (outs), (ins FPR:$t, mem32:$addr),
+ "ssip\t$t, $addr", []> {
+ bits<12> addr;
+
+ let r = 0x0C;
+ let imm8{7-0} = addr{11-4};
+ let s{3-0} = addr{3-0};
+ }
+
+ def SSX: RRR_Inst<0x00, 0x08, 0x04, (outs), (ins FPR:$r, AR:$s, AR:$t),
+ "ssx\t$r, $s, $t", []>;
+
+ def SSXP: RRR_Inst<0x00, 0x08, 0x05, (outs), (ins FPR:$r, AR:$s, AR:$t),
+ "ssxp\t$r, $s, $t", []>;
+}
+
+def : Pat<(store FPR:$t, addr_ish4:$addr), (SSI FPR:$t, mem32:$addr)>;
+
+// FP compare instructions
+let isCompare = 1, Predicates = [HasSingleFloat] in {
+ class FCompare <bits<4> oper2, bits<4> oper1, string instrAsm,
+ SDPatternOperator opNode, bit isComm = 0>
+ : RRR_Inst<0x00, oper1, oper2, (outs BR:$r), (ins FPR:$s, FPR:$t),
+ instrAsm#"\t$r, $s, $t",
+ [(set BR:$r, (opNode FPR:$s, FPR:$t))]> {
+ let isCommutable = isComm;
+ let isReMaterializable = 0;
+ let Predicates = [HasSingleFloat];
+ }
+}
+
+def OEQ_S : FCompare<0x02, 0x0b, "oeq.s", Xtensa_cmpoeq, 1>;
+def OLT_S : FCompare<0x04, 0x0b, "olt.s", Xtensa_cmpolt, 0>;
+def OLE_S : FCompare<0x06, 0x0b, "ole.s", Xtensa_cmpole, 0>;
+
+def UEQ_S : FCompare<0x03, 0x0b, "ueq.s", Xtensa_cmpueq, 1>;
+def ULT_S : FCompare<0x05, 0x0b, "ult.s", Xtensa_cmpult, 0>;
+def ULE_S : FCompare<0x07, 0x0b, "ule.s", Xtensa_cmpule, 0>;
+def UN_S : FCompare<0x01, 0x0b, "un.s", Xtensa_cmpuo, 1>;
+
+def ABS_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "abs.s\t$r, $s",
+ [(set FPR:$r, (fabs FPR:$s))]>, Requires<[HasSingleFloat]> {
+ let t = 0x01;
+}
+
+def : Pat<(fabs FPR:$s), (ABS_S $s)>;
+
+def ADDEXP_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "addexp.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x0E;
+}
+
+def ADDEXPM_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "addexpm.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x0F;
+}
+
+def CEIL_S : RRR_Inst<0x00, 0x0A, 0x0B, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
+ "ceil.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+def CONST_S : RRR_Inst<0x00, 0x0a, 0x0f, (outs FPR:$r), (ins uimm4:$imm),
+ "const.s\t$r, $imm", []>, Requires<[HasSingleFloat]> {
+ bits<4> imm;
+
+ let t = 0x03;
+ let s = imm{3-0};
+}
+
+def DIV0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "div0.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x7;
+}
+
+def DIVN_S : RRR_Inst<0x00, 0x0A, 0x07, (outs FPR:$r), (ins FPR:$s, FPR:$t),
+ "divn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>;
+
+def FLOAT_S : RRR_Inst<0x00, 0x0A, 0x0c, (outs FPR:$r), (ins AR:$s, uimm4:$imm),
+ "float.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+def : Pat<(f32 (sint_to_fp AR:$s)), (FLOAT_S AR:$s, 0)>;
+
+def FLOOR_S : RRR_Inst<0x00, 0x0A, 0x0A, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
+ "floor.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+def MADDN_S : RRR_Inst<0x00, 0x0A, 0x06, (outs FPR:$r), (ins FPR:$s, FPR:$t),
+ "maddn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]> {
+ let isCommutable = 0;
+}
+
+// FP multipy-add
+def MADD_S : RRR_Inst<0x00, 0x0A, 0x04, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t),
+ "madd.s\t$r, $s, $t",
+ [(set FPR:$r, (Xtensa_madd FPR:$a, FPR:$s, FPR:$t))]>,
+ Requires<[HasSingleFloat]> {
+ let isCommutable = 0;
+ let isReMaterializable = 0;
+ let Constraints = "$r = $a";
+}
+
+// fmadd: r1 * r2 + r3
+def : Pat<(fma FPR:$r1, FPR:$r2, FPR:$r3),
+ (MADD_S $r3, $r1, $r2)>;
+
+
+def MKDADJ_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "mkdadj.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x0D;
+}
+
+def MKSADJ_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "mksadj.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x0C;
+}
+
+// FP move instructions
+def MOV_S : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins FPR:$s),
+ "mov.s\t$r, $s",
+ [(set FPR:$r, (Xtensa_movs FPR:$s))]>, Requires<[HasSingleFloat]> {
+ let t = 0x00;
+}
+
+def MOVEQZ_S : RRR_Inst<0x00, 0x0B, 0x08, (outs FPR:$r), (ins FPR:$s, AR:$t),
+ "moveqz.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>;
+
+def MOVF_S : RRR_Inst<0x00, 0x0B, 0x0C, (outs FPR:$r), (ins FPR:$s, BR:$t),
+ "movf.s\t$r, $s, $t", []>, Requires<[HasBoolean, HasSingleFloat]>;
+
+def MOVGEZ_S : RRR_Inst<0x00, 0x0B, 0x0B, (outs FPR:$r), (ins FPR:$s, AR:$t),
+ "movgez.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>;
+
+def MOVLTZ_S : RRR_Inst<0x00, 0x0B, 0x0A, (outs FPR:$r), (ins FPR:$s, AR:$t),
+ "movltz.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>;
+
+def MOVNEZ_S : RRR_Inst<0x00, 0x0B, 0x09, (outs FPR:$r), (ins FPR:$s, AR:$t),
+ "movnez.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>;
+
+def MOVT_S : RRR_Inst<0x00, 0x0B, 0x0D, (outs FPR:$r), (ins FPR:$s, BR:$t),
+ "movt.s\t$r, $s, $t", []>, Requires<[HasBoolean, HasSingleFloat]>;
+
+// FP multipy-sub
+def MSUB_S : RRR_Inst<0x00, 0x0A, 0x05, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t),
+ "msub.s\t$r, $s, $t",
+ [(set FPR:$r, (Xtensa_msub FPR:$a, FPR:$s, FPR:$t))]>, Requires<[HasSingleFloat]> {
+ let isCommutable = 0;
+ let isReMaterializable = 0;
+ let Constraints = "$r = $a";
+}
+
+def NEXP01_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "nexp01.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x0B;
+}
+
+def NEG_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "neg.s\t$r, $s",
+ [(set FPR:$r, (fneg FPR:$s))]> {
+ let t = 0x06;
+}
+
+def RECIP0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "recip0.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x08;
+}
+
+def RFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs AR:$r), (ins FPR:$s),
+ "rfr\t$r, $s",
+ [(set AR:$r, (bitconvert FPR:$s))]> {
+ let t = 0x04;
+}
+
+def ROUND_S : RRR_Inst<0x00, 0x0A, 0x08, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
+ "round.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+def RSQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "rsqrt0.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x0A;
+}
+
+def SQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
+ "sqrt0.s\t$r, $s", []>, Requires<[HasSingleFloat]> {
+ let t = 0x09;
+}
+
+def TRUNC_S : RRR_Inst<0x00, 0x0A, 0x09, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
+ "trunc.s\t$r, $s, $imm", []> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+def : Pat<(i32 (fp_to_sint FPR:$s)), (TRUNC_S FPR:$s, 0)>;
+
+def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s, uimm4:$imm),
+ "ufloat.s\t$r, $s, $imm", []> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+def : Pat<(f32 (uint_to_fp AR:$s)), (UFLOAT_S AR:$s, 0)>;
+
+def UTRUNC_S : RRR_Inst<0x00, 0x0A, 0x0e, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
+ "utrunc.s\t$r, $s, $imm", []> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+def : Pat<(i32 (fp_to_uint FPR:$s)), (UTRUNC_S FPR:$s, 0)>;
+
+def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s),
+ "wfr\t$r, $s",
+ [(set FPR:$r, (bitconvert AR:$s))]> {
+ let t = 0x05;
+}
+
//===----------------------------------------------------------------------===//
// DSP Instructions
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td
index 12b81fccec479..fea13c2298d97 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperators.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperators.td
@@ -25,6 +25,11 @@ def SDT_XtensaSelectCC : SDTypeProfile<1, 5,
SDTCisSameAs<2, 3>,
SDTCisVT<5, i32>]>;
+def SDT_XtensaCmp : SDTypeProfile<1, 2, [SDTCisVT<0, v1i1>, SDTCisVT<1, f32>, SDTCisVT<2, f32>]>;
+def SDT_XtensaMADD : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisVT<0, f32>]>;
+def SDT_XtensaMOVS : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, f32>]>;
+def SDT_XtensaSelectCCFP : SDTypeProfile<1, 5, [SDTCisSameAs<0, 3>, SDTCisSameAs<1, 2>, SDTCisSameAs<3, 4>, SDTCisVT<5, i32>]>;
+
def SDT_XtensaSRC : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>,
SDTCisVT<2, i32>, SDTCisVT<3, i32>]>;
@@ -70,3 +75,15 @@ def Xtensa_extui: SDNode<"XtensaISD::EXTUI", SDT_XtensaEXTUI>;
def Xtensa_movsp: SDNode<"XtensaISD::MOVSP", SDT_XtensaMOVSP,
[SDNPHasChain, SDNPSideEffect, SDNPInGlue]>;
+
+def Xtensa_cmpoeq : SDNode<"XtensaISD::CMPOEQ", SDT_XtensaCmp, [SDNPOutGlue]>;
+def Xtensa_cmpolt : SDNode<"XtensaISD::CMPOLT", SDT_XtensaCmp, [SDNPOutGlue]>;
+def Xtensa_cmpole : SDNode<"XtensaISD::CMPOLE", SDT_XtensaCmp, [SDNPOutGlue]>;
+def Xtensa_cmpueq : SDNode<"XtensaISD::CMPUEQ", SDT_XtensaCmp, [SDNPOutGlue]>;
+def Xtensa_cmpult : SDNode<"XtensaISD::CMPULT", SDT_XtensaCmp, [SDNPOutGlue]>;
+def Xtensa_cmpule : SDNode<"XtensaISD::CMPULE", SDT_XtensaCmp, [SDNPOutGlue]>;
+def Xtensa_cmpuo : SDNode<"XtensaISD::CMPUO", SDT_XtensaCmp, [SDNPOutGlue]>;
+
+def Xtensa_madd: SDNode<"XtensaISD::MADD", SDT_XtensaMADD, [SDNPInGlue]>;
+def Xtensa_msub: SDNode<"XtensaISD::MSUB", SDT_XtensaMADD, [SDNPInGlue]>;
+def Xtensa_movs: SDNode<"XtensaISD::MOVS", SDT_XtensaMOVS, [SDNPInGlue]>;
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
index 2a40431adc7f0..36b2b50ccbe9d 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
@@ -103,6 +103,50 @@ def MR : RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>;
def SR : RegisterClass<"Xtensa", [i32], 32, (add
LBEG, LEND, LCOUNT, SAR, BREG, MR, WINDOWBASE, WINDOWSTART)>;
+//===----------------------------------------------------------------------===//
+// USER registers
+//===----------------------------------------------------------------------===//
+class URReg<bits<8> num, string n, list<string> alt = []> : XtensaReg<n> {
+ let HWEncoding{7-0} = num;
+ let AltNames = alt;
+}
+
+def FCR : URReg<232, "fcr", ["FCR"]>;
+def FSR : URReg<233, "fsr", ["FSR"]>;
+
+def UR : RegisterClass<"Xtensa", [i32], 32, (add FCR, FSR)>;
+
+//===----------------------------------------------------------------------===//
+// Floating-Point registers
+//===----------------------------------------------------------------------===//
+
+// Xtensa Floating-Point regs
+class FPReg<bits<4> num, string n> : XtensaReg<n> {
+ let HWEncoding{3-0} = num;
+}
+
+def F0 : FPReg<0, "f0">, DwarfRegNum<[19]>;
+def F1 : FPReg<1, "f1">, DwarfRegNum<[20]>;
+def F2 : FPReg<2, "f2">, DwarfRegNum<[21]>;
+def F3 : FPReg<3, "f3">, DwarfRegNum<[22]>;
+def F4 : FPReg<4, "f4">, DwarfRegNum<[23]>;
+def F5 : FPReg<5, "f5">, DwarfRegNum<[24]>;
+def F6 : FPReg<6, "f6">, DwarfRegNum<[25]>;
+def F7 : FPReg<7, "f7">, DwarfRegNum<[26]>;
+def F8 : FPReg<8, "f8">, DwarfRegNum<[27]>;
+def F9 : FPReg<9, "f9">, DwarfRegNum<[28]>;
+def F10 : FPReg<10, "f10">, DwarfRegNum<[29]>;
+def F11 : FPReg<11, "f11">, DwarfRegNum<[30]>;
+def F12 : FPReg<12, "f12">, DwarfRegNum<[31]>;
+def F13 : FPReg<13, "f13">, DwarfRegNum<[32]>;
+def F14 : FPReg<14, "f14">, DwarfRegNum<[33]>;
+def F15 : FPReg<15, "f15">, DwarfRegNum<[34]>;
+
+// Floating-Point register class with allocation order
+def FPR : RegisterClass<"Xtensa", [f32], 32, (add
+ F8, F9, F10, F11, F12, F13, F14, F15,
+ F7, F6, F5, F4, F3, F2, F1, F0)>;
+
//===----------------------------------------------------------------------===//
// Boolean registers
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
index 227ce2134b33b..96ca62c2c33ee 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
@@ -77,6 +77,7 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
bool hasMul32() const { return HasMul32; }
bool hasMul32High() const { return HasMul32High; }
bool hasDiv32() const { return HasDiv32; }
+ bool hasSingleFloat() const { return HasSingleFloat; }
bool isWindowedABI() const { return hasWindowed(); }
// Automatically generated by tblgen.
diff --git a/llvm/test/CodeGen/Xtensa/float-arith.ll b/llvm/test/CodeGen/Xtensa/float-arith.ll
new file mode 100644
index 0000000000000..be12a1fb70d22
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/float-arith.ll
@@ -0,0 +1,569 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=xtensa -mattr=+fp -verify-machineinstrs < %s | FileCheck -check-prefix=XTENSA %s
+
+define float @fadd_s(float %a, float %b) nounwind {
+; XTENSA-LABEL: fadd_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: add.s f8, f9, f8
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %1 = fadd float %a, %b
+ ret float %1
+}
+
+define float @fsub_s(float %a, float %b) nounwind {
+; XTENSA-LABEL: fsub_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: sub.s f8, f9, f8
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %1 = fsub float %a, %b
+ ret float %1
+}
+
+define float @fmul_s(float %a, float %b) nounwind {
+; XTENSA-LABEL: fmul_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: mul.s f8, f9, f8
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %1 = fmul float %a, %b
+ ret float %1
+}
+
+define float @fdiv_s(float %a, float %b) nounwind {
+; XTENSA-LABEL: fdiv_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI3_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = fdiv float %a, %b
+ ret float %1
+}
+
+declare float @llvm.sqrt.f32(float)
+
+define float @fsqrt_s(float %a) nounwind {
+; XTENSA-LABEL: fsqrt_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI4_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.sqrt.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.fabs.f32(float)
+
+define float @fabs_s(float %a, float %b) nounwind {
+; XTENSA-LABEL: fabs_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: add.s f8, f9, f8
+; XTENSA-NEXT: abs.s f9, f8
+; XTENSA-NEXT: add.s f8, f9, f8
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %1 = fadd float %a, %b
+ %2 = call float @llvm.fabs.f32(float %1)
+ %3 = fadd float %2, %1
+ ret float %3
+}
+
+declare float @llvm.minnum.f32(float, float)
+
+define float @fmin_s(float %a, float %b) nounwind {
+; XTENSA-LABEL: fmin_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI6_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.minnum.f32(float %a, float %b)
+ ret float %1
+}
+
+declare float @llvm.maxnum.f32(float, float)
+
+define float @fmax_s(float %a, float %b) nounwind {
+; XTENSA-LABEL: fmax_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI7_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.maxnum.f32(float %a, float %b)
+ ret float %1
+}
+
+declare float @llvm.fma.f32(float, float, float)
+
+define float @fmadd_s(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fmadd_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: madd.s f10, f9, f8
+; XTENSA-NEXT: rfr a2, f10
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.fma.f32(float %a, float %b, float %c)
+ ret float %1
+}
+
+define float @fmsub_s(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fmsub_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI9_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a4
+; XTENSA-NEXT: add.s f8, f9, f8
+; XTENSA-NEXT: neg.s f8, f8
+; XTENSA-NEXT: wfr f9, a3
+; XTENSA-NEXT: wfr f10, a2
+; XTENSA-NEXT: madd.s f8, f10, f9
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %c_ = fadd float 0.0, %c ; avoid negation using xor
+ %negc = fsub float -0.0, %c_
+ %1 = call float @llvm.fma.f32(float %a, float %b, float %negc)
+ ret float %1
+}
+
+define float @fnmadd_s(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmadd_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI10_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: add.s f9, f9, f8
+; XTENSA-NEXT: neg.s f9, f9
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: add.s f8, f10, f8
+; XTENSA-NEXT: neg.s f8, f8
+; XTENSA-NEXT: wfr f10, a3
+; XTENSA-NEXT: madd.s f8, f9, f10
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %a_ = fadd float 0.0, %a
+ %c_ = fadd float 0.0, %c
+ %nega = fsub float -0.0, %a_
+ %negc = fsub float -0.0, %c_
+ %1 = call float @llvm.fma.f32(float %nega, float %b, float %negc)
+ ret float %1
+}
+
+define float @fnmadd_s_2(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmadd_s_2:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI11_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a3
+; XTENSA-NEXT: add.s f9, f9, f8
+; XTENSA-NEXT: neg.s f9, f9
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: add.s f8, f10, f8
+; XTENSA-NEXT: neg.s f8, f8
+; XTENSA-NEXT: wfr f10, a2
+; XTENSA-NEXT: madd.s f8, f10, f9
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %b_ = fadd float 0.0, %b
+ %c_ = fadd float 0.0, %c
+ %negb = fsub float -0.0, %b_
+ %negc = fsub float -0.0, %c_
+ %1 = call float @llvm.fma.f32(float %a, float %negb, float %negc)
+ ret float %1
+}
+
+define float @fnmadd_s_3(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmadd_s_3:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: madd.s f10, f9, f8
+; XTENSA-NEXT: rfr a8, f10
+; XTENSA-NEXT: l32r a9, .LCPI12_0
+; XTENSA-NEXT: xor a2, a8, a9
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.fma.f32(float %a, float %b, float %c)
+ %neg = fneg float %1
+ ret float %neg
+}
+
+define float @fnmadd_nsz(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmadd_nsz:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: madd.s f10, f9, f8
+; XTENSA-NEXT: rfr a8, f10
+; XTENSA-NEXT: l32r a9, .LCPI13_0
+; XTENSA-NEXT: xor a2, a8, a9
+; XTENSA-NEXT: ret
+ %1 = call nsz float @llvm.fma.f32(float %a, float %b, float %c)
+ %neg = fneg nsz float %1
+ ret float %neg
+}
+
+define float @fnmsub_s(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmsub_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI14_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: add.s f8, f9, f8
+; XTENSA-NEXT: neg.s f8, f8
+; XTENSA-NEXT: wfr f9, a3
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: madd.s f10, f8, f9
+; XTENSA-NEXT: rfr a2, f10
+; XTENSA-NEXT: ret
+ %a_ = fadd float 0.0, %a
+ %nega = fsub float -0.0, %a_
+ %1 = call float @llvm.fma.f32(float %nega, float %b, float %c)
+ ret float %1
+}
+
+define float @fnmsub_s_2(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmsub_s_2:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI15_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a3
+; XTENSA-NEXT: add.s f8, f9, f8
+; XTENSA-NEXT: neg.s f8, f8
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: madd.s f10, f9, f8
+; XTENSA-NEXT: rfr a2, f10
+; XTENSA-NEXT: ret
+ %b_ = fadd float 0.0, %b
+ %negb = fsub float -0.0, %b_
+ %1 = call float @llvm.fma.f32(float %a, float %negb, float %c)
+ ret float %1
+}
+
+define float @fmadd_s_contract(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fmadd_s_contract:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: wfr f8, a3
+; XTENSA-NEXT: wfr f9, a2
+; XTENSA-NEXT: mul.s f8, f9, f8
+; XTENSA-NEXT: wfr f9, a4
+; XTENSA-NEXT: add.s f8, f8, f9
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %1 = fmul contract float %a, %b
+ %2 = fadd contract float %1, %c
+ ret float %2
+}
+
+define float @fmsub_s_contract(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fmsub_s_contract:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI17_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a4
+; XTENSA-NEXT: add.s f8, f9, f8
+; XTENSA-NEXT: wfr f9, a3
+; XTENSA-NEXT: wfr f10, a2
+; XTENSA-NEXT: mul.s f9, f10, f9
+; XTENSA-NEXT: sub.s f8, f9, f8
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %c_ = fadd float 0.0, %c ; avoid negation using xor
+ %1 = fmul contract float %a, %b
+ %2 = fsub contract float %1, %c_
+ ret float %2
+}
+
+define float @fnmadd_s_contract(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmadd_s_contract:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI18_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a3
+; XTENSA-NEXT: add.s f9, f9, f8
+; XTENSA-NEXT: wfr f10, a2
+; XTENSA-NEXT: add.s f10, f10, f8
+; XTENSA-NEXT: mul.s f9, f10, f9
+; XTENSA-NEXT: neg.s f9, f9
+; XTENSA-NEXT: wfr f10, a4
+; XTENSA-NEXT: add.s f8, f10, f8
+; XTENSA-NEXT: sub.s f8, f9, f8
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %a_ = fadd float 0.0, %a ; avoid negation using xor
+ %b_ = fadd float 0.0, %b ; avoid negation using xor
+ %c_ = fadd float 0.0, %c ; avoid negation using xor
+ %1 = fmul contract float %a_, %b_
+ %2 = fneg float %1
+ %3 = fsub contract float %2, %c_
+ ret float %3
+}
+
+define float @fnmsub_s_contract(float %a, float %b, float %c) nounwind {
+; XTENSA-LABEL: fnmsub_s_contract:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI19_0
+; XTENSA-NEXT: wfr f8, a8
+; XTENSA-NEXT: wfr f9, a3
+; XTENSA-NEXT: add.s f9, f9, f8
+; XTENSA-NEXT: wfr f10, a2
+; XTENSA-NEXT: add.s f8, f10, f8
+; XTENSA-NEXT: mul.s f8, f8, f9
+; XTENSA-NEXT: wfr f9, a4
+; XTENSA-NEXT: sub.s f8, f9, f8
+; XTENSA-NEXT: rfr a2, f8
+; XTENSA-NEXT: ret
+ %a_ = fadd float 0.0, %a ; avoid negation using xor
+ %b_ = fadd float 0.0, %b ; avoid negation using xor
+ %1 = fmul contract float %a_, %b_
+ %2 = fsub contract float %c, %1
+ ret float %2
+}
+
+declare float @llvm.powi.f32(float, i32)
+
+define float @powi_f32(float %a, i32 %b) nounwind {
+; XTENSA-LABEL: powi_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI20_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+
+ %1 = call float @llvm.powi.f32(float %a, i32 %b)
+ ret float %1
+}
+
+declare float @llvm.sin.f32(float)
+
+define float @sin_f32(float %a) nounwind {
+; XTENSA-LABEL: sin_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI21_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.sin.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.cos.f32(float)
+
+define float @cos_f32(float %a) nounwind {
+; XTENSA-LABEL: cos_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI22_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.cos.f32(float %a)
+ ret float %1
+}
+declare float @llvm.exp.f32(float)
+
+define float @exp_f32(float %a) nounwind {
+; XTENSA-LABEL: exp_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI23_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.exp.f32(float %a)
+ ret float %1
+}
+
+define float @log_f32(float %a) nounwind {
+; XTENSA-LABEL: log_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI24_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.log.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.log10.f32(float)
+
+define float @log10_f32(float %a) nounwind {
+; XTENSA-LABEL: log10_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI25_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.log10.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.log2.f32(float)
+
+define float @log2_f32(float %a) nounwind {
+; XTENSA-LABEL: log2_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI26_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.log2.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.floor.f32(float)
+
+define float @floor_f32(float %a) nounwind {
+; XTENSA-LABEL: floor_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI27_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.floor.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.ceil.f32(float)
+
+define float @ceil_f32(float %a) nounwind {
+; XTENSA-LABEL: ceil_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI28_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.ceil.f32(float %a)
+ ret float %1
+}
+declare float @llvm.rint.f32(float)
+
+define float @rint_f32(float %a) nounwind {
+; XTENSA-LABEL: rint_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI29_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.rint.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.nearbyint.f32(float)
+
+define float @nearbyint_f32(float %a) nounwind {
+; XTENSA-LABEL: nearbyint_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI30_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.nearbyint.f32(float %a)
+ ret float %1
+}
+
+declare float @llvm.round.f32(float)
+
+define float @round_f32(float %a) nounwind {
+; XTENSA-LABEL: round_f32:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: s32i a0, a1, 0 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI31_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l32i a0, a1, 0 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 16
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %1 = call float @llvm.round.f32(float %a)
+ ret float %1
+}
diff --git a/llvm/test/MC/Xtensa/float-err.s b/llvm/test/MC/Xtensa/float-err.s
new file mode 100644
index 0000000000000..a7145f0673395
--- /dev/null
+++ b/llvm/test/MC/Xtensa/float-err.s
@@ -0,0 +1,37 @@
+# RUN: not llvm-mc %s -triple=xtensa -filetype=asm 2>&1 | FileCheck --implicit-check-not=error: %s
+
+ceil.s a2, f3, 17
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+const.s f3, 18
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+float.s f2, a3, 16
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+ufloat.s f2, a3, 25
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
+
+floor.s a2, f3, 17
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+lsi f2, a3, 4099
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+lsip f2, a3, 4099
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+round.s a2, f3, 20
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+ssi f2, a3, 5000
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+ssip f2, a3, 5001
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+
+trunc.s a2, f3, 21
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
+
+utrunc.s a2, f3, 19
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
diff --git a/llvm/test/MC/Xtensa/float.s b/llvm/test/MC/Xtensa/float.s
new file mode 100644
index 0000000000000..0c51addeb3774
--- /dev/null
+++ b/llvm/test/MC/Xtensa/float.s
@@ -0,0 +1,177 @@
+# RUN: llvm-mc %s -triple=xtensa -mattr=+fp -mattr=+bool -show-encoding \
+# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+
+.align 4
+LBL0:
+
+# CHECK-INST: abs.s f2, f3
+# CHECK: encoding: [0x10,0x23,0xfa]
+ abs.s f2, f3
+# CHECK-INST: add.s f2, f3, f4
+# CHECK: encoding: [0x40,0x23,0x0a]
+ add.s f2, f3, f4
+# CHECK-INST: addexp.s f2, f3
+# CHECK: encoding: [0xe0,0x23,0xfa]
+ addexp.s f2, f3
+# CHECK-INST: addexpm.s f2, f3
+# CHECK: encoding: [0xf0,0x23,0xfa]
+ addexpm.s f2, f3
+
+# CHECK-INST: ceil.s a2, f3, 5
+# CHECK: encoding: [0x50,0x23,0xba]
+ ceil.s a2, f3, 5
+# CHECK-INST: const.s f3, 5
+# CHECK: encoding: [0x30,0x35,0xfa]
+ const.s f3, 5
+
+# CHECK-INST: div0.s f2, f3
+# CHECK: encoding: [0x70,0x23,0xfa]
+ div0.s f2, f3
+# CHECK-INST: divn.s f2, f3, f4
+# CHECK: encoding: [0x40,0x23,0x7a]
+ divn.s f2, f3, f4
+
+# CHECK-INST: float.s f2, a3, 5
+# CHECK: encoding: [0x50,0x23,0xca]
+ float.s f2, a3, 5
+# CHECK-INST: floor.s a2, f3, 5
+# CHECK: encoding: [0x50,0x23,0xaa]
+ floor.s a2, f3, 5
+
+# CHECK-INST: lsi f2, a3, 8
+# CHECK: encoding: [0x23,0x03,0x02]
+ lsi f2, a3, 8
+# CHECK-INST: lsip f2, a3, 8
+# CHECK: encoding: [0x23,0x83,0x02]
+ lsip f2, a3, 8
+# CHECK-INST: lsx f2, a3, a4
+# CHECK: encoding: [0x40,0x23,0x08]
+ lsx f2, a3, a4
+# CHECK-INST: lsxp f2, a3, a4
+# CHECK: encoding: [0x40,0x23,0x18]
+ lsxp f2, a3, a4
+
+# CHECK-INST: madd.s f2, f3, f4
+# CHECK: encoding: [0x40,0x23,0x4a]
+ madd.s f2, f3, f4
+# CHECK-INST: maddn.s f2, f3, f4
+# CHECK: encoding: [0x40,0x23,0x6a]
+ maddn.s f2, f3, f4
+# CHECK-INST: mkdadj.s f2, f3
+# CHECK: encoding: [0xd0,0x23,0xfa]
+ mkdadj.s f2, f3
+# CHECK-INST: mksadj.s f2, f3
+# CHECK: encoding: [0xc0,0x23,0xfa]
+ mksadj.s f2, f3
+
+# CHECK-INST: mov.s f2, f3
+# CHECK: encoding: [0x00,0x23,0xfa]
+ mov.s f2, f3
+
+# CHECK-INST: moveqz.s f2, f3, a4
+# CHECK: encoding: [0x40,0x23,0x8b]
+ moveqz.s f2, f3, a4
+# CHECK-INST: movf.s f2, f3, b0
+# CHECK: encoding: [0x00,0x23,0xcb]
+ movf.s f2, f3, b0
+# CHECK-INST: movgez.s f2, f3, a4
+# CHECK: encoding: [0x40,0x23,0xbb]
+ movgez.s f2, f3, a4
+# CHECK-INST: movltz.s f2, f3, a4
+# CHECK: encoding: [0x40,0x23,0xab]
+ movltz.s f2, f3, a4
+# CHECK-INST: movnez.s f2, f3, a4
+# CHECK: encoding: [0x40,0x23,0x9b]
+ movnez.s f2, f3, a4
+# CHECK-INST: movt.s f2, f3, b0
+# CHECK: encoding: [0x00,0x23,0xdb]
+ movt.s f2, f3, b0
+
+# CHECK-INST: msub.s f2, f3, f4
+# CHECK: encoding: [0x40,0x23,0x5a]
+ msub.s f2, f3, f4
+# CHECK-INST: mul.s f2, f3, f4
+# CHECK: encoding: [0x40,0x23,0x2a]
+ mul.s f2, f3, f4
+# CHECK-INST: neg.s f2, f3
+# CHECK: encoding: [0x60,0x23,0xfa]
+ neg.s f2, f3
+
+# CHECK-INST: nexp01.s f2, f3
+# CHECK: encoding: [0xb0,0x23,0xfa]
+ nexp01.s f2, f3
+
+# CHECK-INST: oeq.s b0, f2, f3
+# CHECK: encoding: [0x30,0x02,0x2b]
+ oeq.s b0, f2, f3
+# CHECK-INST: ole.s b0, f2, f3
+# CHECK: encoding: [0x30,0x02,0x6b]
+ ole.s b0, f2, f3
+# CHECK-INST: olt.s b0, f2, f3
+# CHECK: encoding: [0x30,0x02,0x4b]
+ olt.s b0, f2, f3
+
+# CHECK-INST: recip0.s f2, f3
+# CHECK: encoding: [0x80,0x23,0xfa]
+ recip0.s f2, f3
+
+# CHECK-INST: rfr a2, f3
+# CHECK: encoding: [0x40,0x23,0xfa]
+ rfr a2, f3
+
+# CHECK-INST: round.s a2, f3, 5
+# CHECK: encoding: [0x50,0x23,0x8a]
+ round.s a2, f3, 5
+# CHECK-INST: rsqrt0.s f2, f3
+# CHECK: encoding: [0xa0,0x23,0xfa]
+ rsqrt0.s f2, f3
+# CHECK-INST: sqrt0.s f2, f3
+# CHECK: encoding: [0x90,0x23,0xfa]
+ sqrt0.s f2, f3
+
+# CHECK-INST: ssi f2, a3, 8
+# CHECK: encoding: [0x23,0x43,0x02]
+ ssi f2, a3, 8
+# CHECK-INST: ssip f2, a3, 8
+# CHECK: encoding: [0x23,0xc3,0x02]
+ ssip f2, a3, 8
+# CHECK-INST: ssx f2, a3, a4
+# CHECK: encoding: [0x40,0x23,0x48]
+ ssx f2, a3, a4
+# CHECK-INST: ssxp f2, a3, a4
+# CHECK: encoding: [0x40,0x23,0x58]
+ ssxp f2, a3, a4
+
+# CHECK-INST: sub.s f2, f3, f4
+# CHECK: encoding: [0x40,0x23,0x1a]
+ sub.s f2, f3, f4
+
+# CHECK-INST: trunc.s a2, f3, 5
+# CHECK: encoding: [0x50,0x23,0x9a]
+ trunc.s a2, f3, 5
+
+# CHECK-INST: ueq.s b0, f2, f3
+# CHECK: encoding: [0x30,0x02,0x3b]
+ ueq.s b0, f2, f3
+
+# CHECK-INST: ufloat.s f2, a3, 5
+# CHECK: encoding: [0x50,0x23,0xda]
+ ufloat.s f2, a3, 5
+
+# CHECK-INST: ule.s b0, f2, f3
+# CHECK: encoding: [0x30,0x02,0x7b]
+ ule.s b0, f2, f3
+# CHECK-INST: ult.s b0, f2, f3
+# CHECK: encoding: [0x30,0x02,0x5b]
+ ult.s b0, f2, f3
+# CHECK-INST: un.s b0, f2, f3
+# CHECK: encoding: [0x30,0x02,0x1b]
+ un.s b0, f2, f3
+
+# CHECK-INST: utrunc.s a2, f3, 5
+# CHECK: encoding: [0x50,0x23,0xea]
+ utrunc.s a2, f3, 5
+
+# CHECK-INST: wfr f2, a3
+# CHECK: encoding: [0x50,0x23,0xfa]
+ wfr f2, a3
>From 8ec0901d291d7338c0f1a84dfc8d33186722c00f Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Mon, 19 May 2025 20:34:25 +0300
Subject: [PATCH 2/5] [Xtensa] Fix Floating Point implementation.
Add more more FP tests. Remove redundant code.
Improve User Registers parsing.
---
.../Xtensa/AsmParser/XtensaAsmParser.cpp | 46 ++--
.../Disassembler/XtensaDisassembler.cpp | 21 +-
.../MCTargetDesc/XtensaMCTargetDesc.cpp | 14 ++
.../Xtensa/MCTargetDesc/XtensaMCTargetDesc.h | 3 +
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 42 +---
llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 45 +++-
llvm/test/CodeGen/Xtensa/brcc_fp.ll | 223 ++++++++++++++++++
llvm/test/CodeGen/Xtensa/float-arith.ll | 181 ++++++++------
llvm/test/MC/Disassembler/Xtensa/fp.txt | 215 +++++++++++++++++
llvm/test/MC/Xtensa/float-err.s | 20 +-
llvm/test/MC/Xtensa/float.s | 32 +++
11 files changed, 683 insertions(+), 159 deletions(-)
create mode 100644 llvm/test/CodeGen/Xtensa/brcc_fp.ll
create mode 100644 llvm/test/MC/Disassembler/Xtensa/fp.txt
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 30c9ee34ade1c..c3422ac2e7b43 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -35,7 +35,7 @@ using namespace llvm;
struct XtensaOperand;
class XtensaAsmParser : public MCTargetAsmParser {
-
+ enum XtensaRegisterType { Xtensa_Generic, Xtensa_SR, Xtensa_UR };
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
XtensaTargetStreamer &getTargetStreamer() {
@@ -63,10 +63,10 @@ class XtensaAsmParser : public MCTargetAsmParser {
ParseStatus parseImmediate(OperandVector &Operands);
ParseStatus parseRegister(OperandVector &Operands, bool AllowParens = false,
- bool SR = false);
+ XtensaRegisterType SR = Xtensa_Generic);
ParseStatus parseOperandWithModifier(OperandVector &Operands);
bool parseOperand(OperandVector &Operands, StringRef Mnemonic,
- bool SR = false);
+ XtensaRegisterType SR = Xtensa_Generic);
bool ParseInstructionWithSR(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands);
ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
@@ -586,7 +586,8 @@ bool XtensaAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
}
ParseStatus XtensaAsmParser::parseRegister(OperandVector &Operands,
- bool AllowParens, bool SR) {
+ bool AllowParens,
+ XtensaRegisterType RegType) {
SMLoc FirstS = getLoc();
bool HadParens = false;
AsmToken Buf[2];
@@ -596,25 +597,33 @@ ParseStatus XtensaAsmParser::parseRegister(OperandVector &Operands,
if (AllowParens && getLexer().is(AsmToken::LParen)) {
size_t ReadCount = getLexer().peekTokens(Buf);
if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) {
- if ((Buf[0].getKind() == AsmToken::Integer) && (!SR))
+ if ((Buf[0].getKind() == AsmToken::Integer) &&
+ (RegType == Xtensa_Generic))
return ParseStatus::NoMatch;
HadParens = true;
getParser().Lex(); // Eat '('
}
}
- unsigned RegNo = 0;
+ MCRegister RegNo = 0;
switch (getLexer().getKind()) {
default:
return ParseStatus::NoMatch;
case AsmToken::Integer:
- if (!SR)
+ if (RegType == Xtensa_Generic)
return ParseStatus::NoMatch;
- RegName = getLexer().getTok().getString();
- RegNo = MatchRegisterName(RegName);
- if (RegNo == 0)
+
+ // Parse case when we expect UR register code as special case,
+ // because SR and UR registers may have the same number
+ // and such situation may lead to confilct
+ if (RegType == Xtensa_UR) {
+ int64_t RegCode = getLexer().getTok().getIntVal();
+ RegNo = Xtensa::getUserRegister(RegCode);
+ } else {
+ RegName = getLexer().getTok().getString();
RegNo = MatchRegisterAltName(RegName);
+ }
break;
case AsmToken::Identifier:
RegName = getLexer().getTok().getIdentifier();
@@ -691,7 +700,7 @@ ParseStatus XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) {
/// from this information, adding to Operands.
/// If operand was parsed, returns false, else true.
bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
- bool SR) {
+ XtensaRegisterType RegType) {
// Check if the current operand has a custom associated parser, if so, try to
// custom parse the operand, or fallback to the general approach.
ParseStatus Res = MatchOperandParserImpl(Operands, Mnemonic);
@@ -705,7 +714,7 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
return true;
// Attempt to parse token as register
- if (parseRegister(Operands, true, SR).isSuccess())
+ if (parseRegister(Operands, true, RegType).isSuccess())
return false;
// Attempt to parse token as an immediate
@@ -719,11 +728,9 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
- if ((Name.starts_with("wsr.") || Name.starts_with("rsr.") ||
- Name.starts_with("xsr.")) &&
- (Name.size() > 4)) {
- // Parse case when instruction name is concatenated with SR register
- // name, like "wsr.sar a1"
+ if ((Name.size() > 4) && Name[3] == '.') {
+ // Parse case when instruction name is concatenated with SR/UR register
+ // name, like "wsr.sar a1" or "wur.fcr a1"
// First operand is token for instruction
Operands.push_back(XtensaOperand::createToken(Name.take_front(3), NameLoc));
@@ -759,7 +766,7 @@ bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
}
// Parse second operand
- if (parseOperand(Operands, Name, true))
+ if (parseOperand(Operands, Name, Name[1] == 's' ? Xtensa_SR : Xtensa_UR))
return true;
}
@@ -777,7 +784,8 @@ bool XtensaAsmParser::parseInstruction(ParseInstructionInfo &Info,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
if (Name.starts_with("wsr") || Name.starts_with("rsr") ||
- Name.starts_with("xsr")) {
+ Name.starts_with("xsr") || Name.starts_with("rur") ||
+ Name.starts_with("wur")) {
return ParseInstructionWithSR(Info, Name, NameLoc, Operands);
}
diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
index 237aed3cc71ea..eb92ae6b9ef84 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -113,7 +113,7 @@ static DecodeStatus DecodeMR23RegisterClass(MCInst &Inst, uint64_t RegNo,
return MCDisassembler::Success;
}
-static const unsigned FPRDecoderTable[] = {
+static const MCPhysReg FPRDecoderTable[] = {
Xtensa::F0, Xtensa::F1, Xtensa::F2, Xtensa::F3, Xtensa::F4, Xtensa::F5,
Xtensa::F6, Xtensa::F7, Xtensa::F8, Xtensa::F9, Xtensa::F10, Xtensa::F11,
Xtensa::F12, Xtensa::F13, Xtensa::F14, Xtensa::F15};
@@ -124,31 +124,26 @@ static DecodeStatus DecodeFPRRegisterClass(MCInst &Inst, uint64_t RegNo,
if (RegNo >= std::size(FPRDecoderTable))
return MCDisassembler::Fail;
- unsigned Reg = FPRDecoderTable[RegNo];
+ MCPhysReg Reg = FPRDecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}
-static const unsigned URDecoderTable[] = {Xtensa::FCR, 232, Xtensa::FSR, 233};
-
static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
- const void *Decoder) {
+ const MCDisassembler *Decoder) {
const llvm::MCSubtargetInfo STI =
((const MCDisassembler *)Decoder)->getSubtargetInfo();
if (RegNo > 255)
return MCDisassembler::Fail;
- for (unsigned i = 0; i < std::size(URDecoderTable); i += 2) {
- if (URDecoderTable[i + 1] == RegNo) {
- unsigned Reg = URDecoderTable[i];
- Inst.addOperand(MCOperand::createReg(Reg));
- return MCDisassembler::Success;
- }
- }
+ MCPhysReg Reg = Xtensa::getUserRegister(RegNo);
+ if (!Xtensa::checkRegister(Reg, Decoder->getSubtargetInfo().getFeatureBits()))
+ return MCDisassembler::Fail;
- return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
}
const MCPhysReg SRDecoderTable[] = {
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
index 792faf811aca9..19479b69bb218 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
@@ -83,6 +83,9 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) {
case Xtensa::LEND:
case Xtensa::LCOUNT:
return FeatureBits[Xtensa::FeatureLoop];
+ case Xtensa::FCR:
+ case Xtensa::FSR:
+ return FeatureBits[FeatureSingleFloat];
case Xtensa::WINDOWBASE:
case Xtensa::WINDOWSTART:
return FeatureBits[Xtensa::FeatureWindowed];
@@ -93,6 +96,17 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) {
return true;
}
+// Get Xtensa User Register by encoding value.
+MCRegister Xtensa::getUserRegister(unsigned Code) {
+ switch (Code) {
+ case 232:
+ return Xtensa::FCR;
+ case 233:
+ return Xtensa::FSR;
+ }
+ return Xtensa::NoRegister;
+}
+
static MCAsmInfo *createXtensaMCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TT,
const MCTargetOptions &Options) {
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
index 649073b01f5c1..a8beb318a0665 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
@@ -57,6 +57,9 @@ bool isValidAddrOffsetForOpcode(unsigned Opcode, int64_t Offset);
// Verify if it's correct to use a special register.
bool checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits);
+
+// Get Xtensa User Register by register encoding value.
+MCRegister getUserRegister(unsigned Code);
} // namespace Xtensa
} // end namespace llvm
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 83f58607c9d37..d3300a0c01f49 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -113,6 +113,7 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::BR_CC, MVT::f32, Expand);
setOperationAction(ISD::SELECT, MVT::i32, Expand);
+ setOperationAction(ISD::SELECT, MVT::f32, Expand);
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
@@ -188,8 +189,6 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
for (unsigned I = MVT::FIRST_FP_VALUETYPE; I <= MVT::LAST_FP_VALUETYPE; ++I) {
MVT VT = MVT::SimpleValueType(I);
if (isTypeLegal(VT)) {
- // We can use FI for FRINT.
- // setOperationAction(ISD::FRINT, VT, Legal);
if (VT.getSizeInBits() == 32 && Subtarget.hasSingleFloat()) {
setOperationAction(ISD::FABS, VT, Legal);
setOperationAction(ISD::FADD, VT, Legal);
@@ -208,36 +207,13 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
// TODO: once implemented in InstrInfo uncomment
setOperationAction(ISD::FSQRT, VT, Expand);
-
- // No special instructions for these.
- setOperationAction(ISD::FCBRT, VT, Expand);
- setOperationAction(ISD::FCEIL, VT, Expand);
setOperationAction(ISD::FSIN, VT, Expand);
setOperationAction(ISD::FCOS, VT, Expand);
setOperationAction(ISD::FREM, VT, Expand);
setOperationAction(ISD::FDIV, VT, Expand);
- setOperationAction(ISD::FEXP, VT, Expand);
- setOperationAction(ISD::FEXP2, VT, Expand);
- setOperationAction(ISD::FFLOOR, VT, Expand);
- setOperationAction(ISD::FLOG, VT, Expand);
- setOperationAction(ISD::FLOG2, VT, Expand);
- setOperationAction(ISD::FLOG10, VT, Expand);
- setOperationAction(ISD::FMAXIMUM, VT, Expand);
- setOperationAction(ISD::FMINIMUM, VT, Expand);
- setOperationAction(ISD::FMAXNUM, VT, Expand);
- setOperationAction(ISD::FMINNUM, VT, Expand);
- setOperationAction(ISD::FNEARBYINT, VT, Expand);
setOperationAction(ISD::FPOW, VT, Expand);
- setOperationAction(ISD::FPOWI, VT, Expand);
- setOperationAction(ISD::FRINT, VT, Expand);
- setOperationAction(ISD::FROUND, VT, Expand);
- setOperationAction(ISD::FSINCOS, VT, Expand);
setOperationAction(ISD::FSQRT, VT, Expand);
- setOperationAction(ISD::FTRUNC, VT, Expand);
- setOperationAction(ISD::LLRINT, VT, Expand);
- setOperationAction(ISD::LLROUND, VT, Expand);
- setOperationAction(ISD::LRINT, VT, Expand);
- setOperationAction(ISD::LROUND, VT, Expand);
+ setOperationAction(ISD::FCOPYSIGN, VT, Expand);
}
}
@@ -263,20 +239,6 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand);
}
- setOperationAction(ISD::FMA, MVT::f64, Expand);
- setOperationAction(ISD::SETCC, MVT::f64, Expand);
- setOperationAction(ISD::BITCAST, MVT::i64, Expand);
- setOperationAction(ISD::BITCAST, MVT::f64, Expand);
- setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand);
- setOperationAction(ISD::SINT_TO_FP, MVT::i64, Expand);
- setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand);
- setOperationAction(ISD::FP_TO_SINT, MVT::i64, Expand);
-
- // Needed so that we don't try to implement f128 constant loads using
- // a load-and-extend of a f80 constant (in cases where the constant
- // would fit in an f80).
- for (MVT VT : MVT::fp_valuetypes())
- setLoadExtAction(ISD::EXTLOAD, VT, MVT::f80, Expand);
// Floating-point truncation and stores need to be done separately.
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 758277f7f601f..6ec220e92a939 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -553,6 +553,26 @@ def XSR : RSR_Inst<0x00, 0x01, 0x06, (outs AR:$ard, SR:$srd), (ins AR:$t, SR:$sr
let Constraints = "$ard = $t, $srd = $sr";
}
+//===----------------------------------------------------------------------===//
+// User Registers read/write instructions
+//===----------------------------------------------------------------------===//
+
+def WUR : RRR_Inst<0x00, 0x03, 0x0F, (outs UR:$ur), (ins AR:$t),
+ "wur\t$t, $ur", []> {
+ bits<8> ur;
+
+ let r = ur{7-4};
+ let s = ur{3-0};
+}
+
+def RUR : RRR_Inst<0x00, 0x03, 0x0E, (outs AR:$r), (ins UR:$ur),
+ "rur\t$r, $ur", []> {
+ bits<8> ur;
+
+ let s = ur{7-4};
+ let t = ur{3-0};
+}
+
//===----------------------------------------------------------------------===//
// Stack allocation
//===----------------------------------------------------------------------===//
@@ -868,6 +888,19 @@ let Constraints = "$dr = $r, at earlyclobber $dr" in {
"movt\t$r, $s, $t", []>, Requires<[HasBoolean]>;
}
+let Predicates = [HasBoolean] in {
+ def SPILL_BOOL: Pseudo<(outs), (ins BR:$b, mem8:$mem),
+ "!spill_bool $b, $mem",[]> {
+ let mayStore = 1;
+ }
+
+ def RESTORE_BOOL: Pseudo<(outs BR:$out), (ins mem8:$mem),
+ "!restore_bool $out, $mem",[]> {
+ let mayLoad = 1;
+ let Defs = [BREG];
+ }
+}
+
//===----------------------------------------------------------------------===//
// SEXT Instruction
//===----------------------------------------------------------------------===//
@@ -1212,7 +1245,7 @@ def NEXP01_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
def NEG_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
"neg.s\t$r, $s",
- [(set FPR:$r, (fneg FPR:$s))]> {
+ [(set FPR:$r, (fneg FPR:$s))]>, Requires<[HasSingleFloat]> {
let t = 0x06;
}
@@ -1223,7 +1256,7 @@ def RECIP0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
def RFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs AR:$r), (ins FPR:$s),
"rfr\t$r, $s",
- [(set AR:$r, (bitconvert FPR:$s))]> {
+ [(set AR:$r, (bitconvert FPR:$s))]>, Requires<[HasSingleFloat]> {
let t = 0x04;
}
@@ -1245,7 +1278,7 @@ def SQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s),
}
def TRUNC_S : RRR_Inst<0x00, 0x0A, 0x09, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
- "trunc.s\t$r, $s, $imm", []> {
+ "trunc.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> {
bits<4> imm;
let t = imm;
@@ -1254,7 +1287,7 @@ def TRUNC_S : RRR_Inst<0x00, 0x0A, 0x09, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
def : Pat<(i32 (fp_to_sint FPR:$s)), (TRUNC_S FPR:$s, 0)>;
def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s, uimm4:$imm),
- "ufloat.s\t$r, $s, $imm", []> {
+ "ufloat.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> {
bits<4> imm;
let t = imm;
@@ -1263,7 +1296,7 @@ def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s, uimm4:$imm)
def : Pat<(f32 (uint_to_fp AR:$s)), (UFLOAT_S AR:$s, 0)>;
def UTRUNC_S : RRR_Inst<0x00, 0x0A, 0x0e, (outs AR:$r), (ins FPR:$s, uimm4:$imm),
- "utrunc.s\t$r, $s, $imm", []> {
+ "utrunc.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> {
bits<4> imm;
let t = imm;
@@ -1273,7 +1306,7 @@ def : Pat<(i32 (fp_to_uint FPR:$s)), (UTRUNC_S FPR:$s, 0)>;
def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s),
"wfr\t$r, $s",
- [(set FPR:$r, (bitconvert AR:$s))]> {
+ [(set FPR:$r, (bitconvert AR:$s))]>, Requires<[HasSingleFloat]> {
let t = 0x05;
}
diff --git a/llvm/test/CodeGen/Xtensa/brcc_fp.ll b/llvm/test/CodeGen/Xtensa/brcc_fp.ll
new file mode 100644
index 0000000000000..3dd17b9ccb940
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/brcc_fp.ll
@@ -0,0 +1,223 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=xtensa -mattr=+fp -disable-block-placement -verify-machineinstrs < %s \
+; RUN: | FileCheck %s
+
+define i32 @brcc_sgt(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_sgt:
+; CHECK: bge a3, a2, .LBB0_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB0_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp sgt i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_ugt(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_ugt:
+; CHECK: bgeu a3, a2, .LBB1_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB1_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp ugt i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_sle(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_sle:
+; CHECK: blt a3, a2, .LBB2_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB2_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp sle i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_ule(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_ule:
+; CHECK: bltu a3, a2, .LBB3_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB3_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp ule i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_eq(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_eq:
+; CHECK: bne a2, a3, .LBB4_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB4_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp eq i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_ne(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_ne:
+; CHECK: beq a2, a3, .LBB5_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB5_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp ne i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_ge(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_ge:
+; CHECK: blt a2, a3, .LBB6_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB6_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp sge i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_lt(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_lt:
+; CHECK: bge a2, a3, .LBB7_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB7_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp slt i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_uge(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_uge:
+; CHECK: bltu a2, a3, .LBB8_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB8_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp uge i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
+
+define i32 @brcc_ult(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: brcc_ult:
+; CHECK: bgeu a2, a3, .LBB9_2
+; CHECK-NEXT: # %bb.1: # %t1
+; CHECK-NEXT: addi a2, a2, 4
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB9_2: # %t2
+; CHECK-NEXT: addi a2, a3, 8
+; CHECK-NEXT: ret
+ %wb = icmp ult i32 %a, %b
+ br i1 %wb, label %t1, label %t2
+t1:
+ %t1v = add i32 %a, 4
+ br label %exit
+t2:
+ %t2v = add i32 %b, 8
+ br label %exit
+exit:
+ %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
+ ret i32 %v
+}
diff --git a/llvm/test/CodeGen/Xtensa/float-arith.ll b/llvm/test/CodeGen/Xtensa/float-arith.ll
index be12a1fb70d22..720a9e58ef956 100644
--- a/llvm/test/CodeGen/Xtensa/float-arith.ll
+++ b/llvm/test/CodeGen/Xtensa/float-arith.ll
@@ -9,8 +9,8 @@ define float @fadd_s(float %a, float %b) nounwind {
; XTENSA-NEXT: add.s f8, f9, f8
; XTENSA-NEXT: rfr a2, f8
; XTENSA-NEXT: ret
- %1 = fadd float %a, %b
- ret float %1
+ %res = fadd float %a, %b
+ ret float %res
}
define float @fsub_s(float %a, float %b) nounwind {
@@ -21,8 +21,8 @@ define float @fsub_s(float %a, float %b) nounwind {
; XTENSA-NEXT: sub.s f8, f9, f8
; XTENSA-NEXT: rfr a2, f8
; XTENSA-NEXT: ret
- %1 = fsub float %a, %b
- ret float %1
+ %res = fsub float %a, %b
+ ret float %res
}
define float @fmul_s(float %a, float %b) nounwind {
@@ -33,8 +33,8 @@ define float @fmul_s(float %a, float %b) nounwind {
; XTENSA-NEXT: mul.s f8, f9, f8
; XTENSA-NEXT: rfr a2, f8
; XTENSA-NEXT: ret
- %1 = fmul float %a, %b
- ret float %1
+ %res = fmul float %a, %b
+ ret float %res
}
define float @fdiv_s(float %a, float %b) nounwind {
@@ -49,8 +49,8 @@ define float @fdiv_s(float %a, float %b) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = fdiv float %a, %b
- ret float %1
+ %res = fdiv float %a, %b
+ ret float %res
}
declare float @llvm.sqrt.f32(float)
@@ -67,8 +67,8 @@ define float @fsqrt_s(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.sqrt.f32(float %a)
- ret float %1
+ %res = call float @llvm.sqrt.f32(float %a)
+ ret float %res
}
declare float @llvm.fabs.f32(float)
@@ -83,10 +83,10 @@ define float @fabs_s(float %a, float %b) nounwind {
; XTENSA-NEXT: add.s f8, f9, f8
; XTENSA-NEXT: rfr a2, f8
; XTENSA-NEXT: ret
- %1 = fadd float %a, %b
- %2 = call float @llvm.fabs.f32(float %1)
- %3 = fadd float %2, %1
- ret float %3
+ %fa = fadd float %a, %b
+ %call_res = call float @llvm.fabs.f32(float %fa)
+ %res = fadd float %call_res, %fa
+ ret float %res
}
declare float @llvm.minnum.f32(float, float)
@@ -103,8 +103,8 @@ define float @fmin_s(float %a, float %b) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.minnum.f32(float %a, float %b)
- ret float %1
+ %res = call float @llvm.minnum.f32(float %a, float %b)
+ ret float %res
}
declare float @llvm.maxnum.f32(float, float)
@@ -121,8 +121,8 @@ define float @fmax_s(float %a, float %b) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.maxnum.f32(float %a, float %b)
- ret float %1
+ %res = call float @llvm.maxnum.f32(float %a, float %b)
+ ret float %res
}
declare float @llvm.fma.f32(float, float, float)
@@ -136,8 +136,8 @@ define float @fmadd_s(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: madd.s f10, f9, f8
; XTENSA-NEXT: rfr a2, f10
; XTENSA-NEXT: ret
- %1 = call float @llvm.fma.f32(float %a, float %b, float %c)
- ret float %1
+ %res = call float @llvm.fma.f32(float %a, float %b, float %c)
+ ret float %res
}
define float @fmsub_s(float %a, float %b, float %c) nounwind {
@@ -155,8 +155,8 @@ define float @fmsub_s(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: ret
%c_ = fadd float 0.0, %c ; avoid negation using xor
%negc = fsub float -0.0, %c_
- %1 = call float @llvm.fma.f32(float %a, float %b, float %negc)
- ret float %1
+ %res = call float @llvm.fma.f32(float %a, float %b, float %negc)
+ ret float %res
}
define float @fnmadd_s(float %a, float %b, float %c) nounwind {
@@ -178,8 +178,8 @@ define float @fnmadd_s(float %a, float %b, float %c) nounwind {
%c_ = fadd float 0.0, %c
%nega = fsub float -0.0, %a_
%negc = fsub float -0.0, %c_
- %1 = call float @llvm.fma.f32(float %nega, float %b, float %negc)
- ret float %1
+ %res = call float @llvm.fma.f32(float %nega, float %b, float %negc)
+ ret float %res
}
define float @fnmadd_s_2(float %a, float %b, float %c) nounwind {
@@ -201,8 +201,8 @@ define float @fnmadd_s_2(float %a, float %b, float %c) nounwind {
%c_ = fadd float 0.0, %c
%negb = fsub float -0.0, %b_
%negc = fsub float -0.0, %c_
- %1 = call float @llvm.fma.f32(float %a, float %negb, float %negc)
- ret float %1
+ %res = call float @llvm.fma.f32(float %a, float %negb, float %negc)
+ ret float %res
}
define float @fnmadd_s_3(float %a, float %b, float %c) nounwind {
@@ -216,8 +216,8 @@ define float @fnmadd_s_3(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: l32r a9, .LCPI12_0
; XTENSA-NEXT: xor a2, a8, a9
; XTENSA-NEXT: ret
- %1 = call float @llvm.fma.f32(float %a, float %b, float %c)
- %neg = fneg float %1
+ %res = call float @llvm.fma.f32(float %a, float %b, float %c)
+ %neg = fneg float %res
ret float %neg
}
@@ -232,8 +232,8 @@ define float @fnmadd_nsz(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: l32r a9, .LCPI13_0
; XTENSA-NEXT: xor a2, a8, a9
; XTENSA-NEXT: ret
- %1 = call nsz float @llvm.fma.f32(float %a, float %b, float %c)
- %neg = fneg nsz float %1
+ %res = call nsz float @llvm.fma.f32(float %a, float %b, float %c)
+ %neg = fneg nsz float %res
ret float %neg
}
@@ -252,8 +252,8 @@ define float @fnmsub_s(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: ret
%a_ = fadd float 0.0, %a
%nega = fsub float -0.0, %a_
- %1 = call float @llvm.fma.f32(float %nega, float %b, float %c)
- ret float %1
+ %res = call float @llvm.fma.f32(float %nega, float %b, float %c)
+ ret float %res
}
define float @fnmsub_s_2(float %a, float %b, float %c) nounwind {
@@ -271,8 +271,8 @@ define float @fnmsub_s_2(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: ret
%b_ = fadd float 0.0, %b
%negb = fsub float -0.0, %b_
- %1 = call float @llvm.fma.f32(float %a, float %negb, float %c)
- ret float %1
+ %res = call float @llvm.fma.f32(float %a, float %negb, float %c)
+ ret float %res
}
define float @fmadd_s_contract(float %a, float %b, float %c) nounwind {
@@ -285,9 +285,9 @@ define float @fmadd_s_contract(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: add.s f8, f8, f9
; XTENSA-NEXT: rfr a2, f8
; XTENSA-NEXT: ret
- %1 = fmul contract float %a, %b
- %2 = fadd contract float %1, %c
- ret float %2
+ %fm = fmul contract float %a, %b
+ %res = fadd contract float %fm, %c
+ ret float %res
}
define float @fmsub_s_contract(float %a, float %b, float %c) nounwind {
@@ -304,9 +304,9 @@ define float @fmsub_s_contract(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: rfr a2, f8
; XTENSA-NEXT: ret
%c_ = fadd float 0.0, %c ; avoid negation using xor
- %1 = fmul contract float %a, %b
- %2 = fsub contract float %1, %c_
- ret float %2
+ %fm = fmul contract float %a, %b
+ %res = fsub contract float %fm, %c_
+ ret float %res
}
define float @fnmadd_s_contract(float %a, float %b, float %c) nounwind {
@@ -328,10 +328,10 @@ define float @fnmadd_s_contract(float %a, float %b, float %c) nounwind {
%a_ = fadd float 0.0, %a ; avoid negation using xor
%b_ = fadd float 0.0, %b ; avoid negation using xor
%c_ = fadd float 0.0, %c ; avoid negation using xor
- %1 = fmul contract float %a_, %b_
- %2 = fneg float %1
- %3 = fsub contract float %2, %c_
- ret float %3
+ %fm = fmul contract float %a_, %b_
+ %fn = fneg float %fm
+ %res = fsub contract float %fn, %c_
+ ret float %res
}
define float @fnmsub_s_contract(float %a, float %b, float %c) nounwind {
@@ -350,9 +350,9 @@ define float @fnmsub_s_contract(float %a, float %b, float %c) nounwind {
; XTENSA-NEXT: ret
%a_ = fadd float 0.0, %a ; avoid negation using xor
%b_ = fadd float 0.0, %b ; avoid negation using xor
- %1 = fmul contract float %a_, %b_
- %2 = fsub contract float %c, %1
- ret float %2
+ %fm = fmul contract float %a_, %b_
+ %res = fsub contract float %c, %fm
+ ret float %res
}
declare float @llvm.powi.f32(float, i32)
@@ -370,8 +370,8 @@ define float @powi_f32(float %a, i32 %b) nounwind {
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.powi.f32(float %a, i32 %b)
- ret float %1
+ %res = call float @llvm.powi.f32(float %a, i32 %b)
+ ret float %res
}
declare float @llvm.sin.f32(float)
@@ -388,8 +388,8 @@ define float @sin_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.sin.f32(float %a)
- ret float %1
+ %res = call float @llvm.sin.f32(float %a)
+ ret float %res
}
declare float @llvm.cos.f32(float)
@@ -406,8 +406,8 @@ define float @cos_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.cos.f32(float %a)
- ret float %1
+ %res = call float @llvm.cos.f32(float %a)
+ ret float %res
}
declare float @llvm.exp.f32(float)
@@ -423,8 +423,8 @@ define float @exp_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.exp.f32(float %a)
- ret float %1
+ %res = call float @llvm.exp.f32(float %a)
+ ret float %res
}
define float @log_f32(float %a) nounwind {
@@ -439,8 +439,8 @@ define float @log_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.log.f32(float %a)
- ret float %1
+ %res = call float @llvm.log.f32(float %a)
+ ret float %res
}
declare float @llvm.log10.f32(float)
@@ -457,8 +457,8 @@ define float @log10_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.log10.f32(float %a)
- ret float %1
+ %res = call float @llvm.log10.f32(float %a)
+ ret float %res
}
declare float @llvm.log2.f32(float)
@@ -475,8 +475,8 @@ define float @log2_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.log2.f32(float %a)
- ret float %1
+ %res = call float @llvm.log2.f32(float %a)
+ ret float %res
}
declare float @llvm.floor.f32(float)
@@ -493,8 +493,8 @@ define float @floor_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.floor.f32(float %a)
- ret float %1
+ %res = call float @llvm.floor.f32(float %a)
+ ret float %res
}
declare float @llvm.ceil.f32(float)
@@ -511,8 +511,8 @@ define float @ceil_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.ceil.f32(float %a)
- ret float %1
+ %res = call float @llvm.ceil.f32(float %a)
+ ret float %res
}
declare float @llvm.rint.f32(float)
@@ -528,8 +528,8 @@ define float @rint_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.rint.f32(float %a)
- ret float %1
+ %res = call float @llvm.rint.f32(float %a)
+ ret float %res
}
declare float @llvm.nearbyint.f32(float)
@@ -546,8 +546,8 @@ define float @nearbyint_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.nearbyint.f32(float %a)
- ret float %1
+ %res = call float @llvm.nearbyint.f32(float %a)
+ ret float %res
}
declare float @llvm.round.f32(float)
@@ -564,6 +564,45 @@ define float @round_f32(float %a) nounwind {
; XTENSA-NEXT: addi a8, a1, 16
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
- %1 = call float @llvm.round.f32(float %a)
- ret float %1
+ %res = call float @llvm.round.f32(float %a)
+ ret float %res
}
+
+
+define float @fneg_s(float %a) nounwind {
+; XTENSA-LABEL: fneg_s:
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI32_0
+; XTENSA-NEXT: and a2, a2, a8
+; XTENSA-NEXT: ret
+ %res = call float @llvm.fabs.f32(float %a)
+ ret float %res
+}
+
+define i32 @fptosi(float %f) {
+; XTENSA-LABEL: fptosi:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: wfr f8, a2
+; XTENSA-NEXT: trunc.s a2, f8, 0
+; XTENSA-NEXT: ret
+ %conv = fptosi float %f to i32
+ ret i32 %conv
+}
+
+define i32 @fptoui(float %f) {
+; XTENSA-LABEL: fptoui:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: wfr f8, a2
+; XTENSA-NEXT: utrunc.s a2, f8, 0
+; XTENSA-NEXT: ret
+ %conv = fptoui float %f to i32
+ ret i32 %conv
+}
+
+;define float @copysign_f32(float %a, float %b) {
+;entry:
+; %c = call float @llvm.copysign.f32(float %a, float %b)
+; ret float %c
+;}
diff --git a/llvm/test/MC/Disassembler/Xtensa/fp.txt b/llvm/test/MC/Disassembler/Xtensa/fp.txt
new file mode 100644
index 0000000000000..993b9987c1bca
--- /dev/null
+++ b/llvm/test/MC/Disassembler/Xtensa/fp.txt
@@ -0,0 +1,215 @@
+# NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 5
+# RUN: llvm-mc -triple=xtensa -mattr=+fp,+bool -disassemble %s | FileCheck -check-prefixes=CHECK-FLOAT %s
+# RUN: not llvm-mc -triple=xtensa -disassemble %s 2>&1 | FileCheck --implicit-check-not=warning: -check-prefixes=CHECK-CORE %s
+
+## Verify that binary code is correctly disassembled with
+## fp option enabled. Also verify that dissasembling without
+## fp option generates warnings.
+
+[0x10,0x23,0xfa]
+# CHECK-FLOAT: abs.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x0a]
+# CHECK-FLOAT: add.s f2, f3, f4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0xe0,0x23,0xfa]
+# CHECK-FLOAT: addexp.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0xf0,0x23,0xfa]
+# CHECK-FLOAT: addexpm.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0xba]
+# CHECK-FLOAT: ceil.s a2, f3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x35,0xfa]
+# CHECK-FLOAT: const.s f3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x70,0x23,0xfa]
+# CHECK-FLOAT: div0.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x7a]
+# CHECK-FLOAT: divn.s f2, f3, f4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0xca]
+# CHECK-FLOAT: float.s f2, a3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0xaa]
+# CHECK-FLOAT: floor.s a2, f3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x23,0x03,0x02]
+# CHECK-FLOAT: lsi f2, a3, 8
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x23,0x83,0x02]
+# CHECK-FLOAT: lsip f2, a3, 8
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x08]
+# CHECK-FLOAT: lsx f2, a3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x18]
+# CHECK-FLOAT: lsxp f2, a3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x4a]
+# CHECK-FLOAT: madd.s f2, f3, f4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x6a]
+# CHECK-FLOAT: maddn.s f2, f3, f4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0xd0,0x23,0xfa]
+# CHECK-FLOAT: mkdadj.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0xc0,0x23,0xfa]
+# CHECK-FLOAT: mksadj.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x00,0x23,0xfa]
+# CHECK-FLOAT: mov.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x8b]
+# CHECK-FLOAT: moveqz.s f2, f3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x00,0x23,0xcb]
+# CHECK-FLOAT: movf.s f2, f3, b0
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0xbb]
+# CHECK-FLOAT: movgez.s f2, f3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0xab]
+# CHECK-FLOAT: movltz.s f2, f3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x9b]
+# CHECK-FLOAT: movnez.s f2, f3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x00,0x23,0xdb]
+# CHECK-FLOAT: movt.s f2, f3, b0
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x5a]
+# CHECK-FLOAT: msub.s f2, f3, f4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x2a]
+# CHECK-FLOAT: mul.s f2, f3, f4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x60,0x23,0xfa]
+# CHECK-FLOAT: neg.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0xb0,0x23,0xfa]
+# CHECK-FLOAT: nexp01.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x02,0x2b]
+# CHECK-FLOAT: oeq.s b0, f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x02,0x6b]
+# CHECK-FLOAT: ole.s b0, f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x02,0x4b]
+# CHECK-FLOAT: olt.s b0, f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x80,0x23,0xfa]
+# CHECK-FLOAT: recip0.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0xfa]
+# CHECK-FLOAT: rfr a2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0x8a]
+# CHECK-FLOAT: round.s a2, f3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0xa0,0x23,0xfa]
+# CHECK-FLOAT: rsqrt0.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x90,0x23,0xfa]
+# CHECK-FLOAT: sqrt0.s f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x23,0x43,0x02]
+# CHECK-FLOAT: ssi f2, a3, 8
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x23,0xc3,0x02]
+# CHECK-FLOAT: ssip f2, a3, 8
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x48]
+# CHECK-FLOAT: ssx f2, a3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x58]
+# CHECK-FLOAT: ssxp f2, a3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x40,0x23,0x1a]
+# CHECK-FLOAT: sub.s f2, f3, f4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0x9a]
+# CHECK-FLOAT: trunc.s a2, f3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x02,0x3b]
+# CHECK-FLOAT: ueq.s b0, f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0xda]
+# CHECK-FLOAT: ufloat.s f2, a3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x02,0x7b]
+# CHECK-FLOAT: ule.s b0, f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x02,0x5b]
+# CHECK-FLOAT: ult.s b0, f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x02,0x1b]
+# CHECK-FLOAT: un.s b0, f2, f3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0xea]
+# CHECK-FLOAT: utrunc.s a2, f3, 5
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x50,0x23,0xfa]
+# CHECK-FLOAT: wfr f2, a3
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x80,0x3e,0xe3]
+# CHECK-FLOAT: rur a3, fcr
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x90,0x3e,0xe3]
+# CHECK-FLOAT: rur a3, fsr
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
diff --git a/llvm/test/MC/Xtensa/float-err.s b/llvm/test/MC/Xtensa/float-err.s
index a7145f0673395..34c41fab18081 100644
--- a/llvm/test/MC/Xtensa/float-err.s
+++ b/llvm/test/MC/Xtensa/float-err.s
@@ -1,34 +1,34 @@
-# RUN: not llvm-mc %s -triple=xtensa -filetype=asm 2>&1 | FileCheck --implicit-check-not=error: %s
+# RUN: not llvm-mc %s -triple=xtensa -mattr=+fp -filetype=asm 2>&1 | FileCheck --implicit-check-not=error: %s
ceil.s a2, f3, 17
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
const.s f3, 18
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
float.s f2, a3, 16
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
ufloat.s f2, a3, 25
// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
floor.s a2, f3, 17
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
lsi f2, a3, 4099
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 1020]
lsip f2, a3, 4099
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 1020]
round.s a2, f3, 20
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
ssi f2, a3, 5000
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 1020]
ssip f2, a3, 5001
-// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 1020]
trunc.s a2, f3, 21
// CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected immediate in range [0, 15]
diff --git a/llvm/test/MC/Xtensa/float.s b/llvm/test/MC/Xtensa/float.s
index 0c51addeb3774..08aa2a12878ec 100644
--- a/llvm/test/MC/Xtensa/float.s
+++ b/llvm/test/MC/Xtensa/float.s
@@ -175,3 +175,35 @@ LBL0:
# CHECK-INST: wfr f2, a3
# CHECK: encoding: [0x50,0x23,0xfa]
wfr f2, a3
+
+# CHECK-INST: rur a3, fcr
+# CHECK: encoding: [0x80,0x3e,0xe3]
+ rur a3, fcr
+
+# CHECK-INST: rur a3, fcr
+# CHECK: encoding: [0x80,0x3e,0xe3]
+ rur a3, 232
+
+# CHECK-INST: rur a3, fcr
+# CHECK: encoding: [0x80,0x3e,0xe3]
+ rur.fcr a3
+
+# CHECK-INST: wur a3, fcr
+# CHECK: encoding: [0x30,0xe8,0xf3]
+ wur a3, fcr
+
+# CHECK-INST: rur a3, fsr
+# CHECK: encoding: [0x90,0x3e,0xe3]
+ rur a3, fsr
+
+# CHECK-INST: rur a3, fsr
+# CHECK: encoding: [0x90,0x3e,0xe3]
+ rur a3, 233
+
+# CHECK-INST: rur a3, fsr
+# CHECK: encoding: [0x90,0x3e,0xe3]
+ rur.fsr a3
+
+# CHECK-INST: wur a3, fsr
+# CHECK: encoding: [0x30,0xe9,0xf3]
+ wur a3, fsr
>From b0c04d03cf84402216bdcaea09f6886dd499eab2 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Thu, 22 May 2025 14:17:14 +0300
Subject: [PATCH 3/5] [Xtensa] Minor fixes.
---
llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp | 3 ---
1 file changed, 3 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
index eb92ae6b9ef84..f1f32a9a169c4 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -132,9 +132,6 @@ static DecodeStatus DecodeFPRRegisterClass(MCInst &Inst, uint64_t RegNo,
static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
- const llvm::MCSubtargetInfo STI =
- ((const MCDisassembler *)Decoder)->getSubtargetInfo();
-
if (RegNo > 255)
return MCDisassembler::Fail;
>From 1cfc902c5103439e24ac78ff8ca1ffd2f05da41b Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Mon, 26 May 2025 22:49:48 +0300
Subject: [PATCH 4/5] [Xtensa] Fix ConstantPool lowering.
Fix lowering FP immediate constant. Fix loading from constant pool callee, basic block,
globaladdress and jumptable addresses. Also fixed potential memory leakage when
several similar XtensaConstantPoolValue objects are created, implement unique ID for such objects.
---
llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 33 +-
llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 6 +
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 61 ++--
llvm/lib/Target/Xtensa/XtensaISelLowering.h | 2 -
llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 4 +-
llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 8 +-
.../Target/Xtensa/XtensaMachineFunctionInfo.h | 3 +
llvm/test/CodeGen/Xtensa/aligned_alloc.ll | 2 +-
llvm/test/CodeGen/Xtensa/bswap.ll | 39 ++-
llvm/test/CodeGen/Xtensa/ctlz-cttz-ctpop.ll | 15 +-
llvm/test/CodeGen/Xtensa/mul.ll | 296 +++++++++---------
11 files changed, 254 insertions(+), 215 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
index a622ea2611cdb..8e7ebb3dc02a2 100644
--- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
@@ -62,22 +62,25 @@ void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) {
void XtensaAsmPrinter::emitMachineConstantPoolValue(
MachineConstantPoolValue *MCPV) {
- XtensaConstantPoolValue *ACPV = static_cast<XtensaConstantPoolValue *>(MCPV);
+ XtensaConstantPoolValue *XtensaCPV =
+ static_cast<XtensaConstantPoolValue *>(MCPV);
MCSymbol *MCSym;
- if (ACPV->isBlockAddress()) {
+ if (XtensaCPV->isBlockAddress()) {
const BlockAddress *BA =
- cast<XtensaConstantPoolConstant>(ACPV)->getBlockAddress();
+ cast<XtensaConstantPoolConstant>(XtensaCPV)->getBlockAddress();
MCSym = GetBlockAddressSymbol(BA);
- } else if (ACPV->isMachineBasicBlock()) {
- const MachineBasicBlock *MBB = cast<XtensaConstantPoolMBB>(ACPV)->getMBB();
+ } else if (XtensaCPV->isMachineBasicBlock()) {
+ const MachineBasicBlock *MBB =
+ cast<XtensaConstantPoolMBB>(XtensaCPV)->getMBB();
MCSym = MBB->getSymbol();
- } else if (ACPV->isJumpTable()) {
- unsigned Idx = cast<XtensaConstantPoolJumpTable>(ACPV)->getIndex();
+ } else if (XtensaCPV->isJumpTable()) {
+ unsigned Idx = cast<XtensaConstantPoolJumpTable>(XtensaCPV)->getIndex();
MCSym = this->GetJTISymbol(Idx, false);
} else {
- assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
- XtensaConstantPoolSymbol *XtensaSym = cast<XtensaConstantPoolSymbol>(ACPV);
+ assert(XtensaCPV->isExtSymbol() && "unrecognized constant pool value");
+ XtensaConstantPoolSymbol *XtensaSym =
+ cast<XtensaConstantPoolSymbol>(XtensaCPV);
const char *SymName = XtensaSym->getSymbol();
if (XtensaSym->isPrivateLinkage()) {
@@ -89,14 +92,14 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue(
}
}
- MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId());
+ MCSymbol *LblSym = GetCPISymbol(XtensaCPV->getLabelId());
auto *TS =
static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
- XtensaMCExpr::Specifier VK = getModifierSpecifier(ACPV->getModifier());
+ XtensaMCExpr::Specifier VK = getModifierSpecifier(XtensaCPV->getModifier());
- if (ACPV->getModifier() != XtensaCP::no_modifier) {
+ if (XtensaCPV->getModifier() != XtensaCP::no_modifier) {
std::string SymName(MCSym->getName());
- StringRef Modifier = ACPV->getModifierText();
+ StringRef Modifier = XtensaCPV->getModifierText();
SymName += Modifier;
MCSym = OutContext.getOrCreateSymbol(SymName);
}
@@ -108,9 +111,9 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue(
void XtensaAsmPrinter::emitMachineConstantPoolEntry(
const MachineConstantPoolEntry &CPE, int i) {
if (CPE.isMachineConstantPoolEntry()) {
- XtensaConstantPoolValue *ACPV =
+ XtensaConstantPoolValue *XtensaCPV =
static_cast<XtensaConstantPoolValue *>(CPE.Val.MachineCPVal);
- ACPV->setLabelId(i);
+ XtensaCPV->setLabelId(i);
emitMachineConstantPoolValue(CPE.Val.MachineCPVal);
} else {
MCSymbol *LblSym = GetCPISymbol(i);
diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
index 06cccd4831bfc..b4c8d22278911 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
@@ -50,6 +50,12 @@ class XtensaDAGToDAGISel : public SelectionDAGISel {
int Scale) {
EVT ValTy = Addr.getValueType();
+ if (Addr.getOpcode() == XtensaISD::PCREL_WRAPPER) {
+ Base = Addr.getOperand(0);
+ if (Base.getOpcode() == ISD::TargetConstantPool)
+ return false; // We want to select L32R instead.
+ }
+
// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index d3300a0c01f49..ccf57683c11e0 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -75,7 +75,7 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::Constant, MVT::i32, Custom);
setOperationAction(ISD::Constant, MVT::i64, Expand);
- setOperationAction(ISD::ConstantFP, MVT::f32, Custom);
+ setOperationAction(ISD::ConstantFP, MVT::f32, Expand);
setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
setBooleanContents(ZeroOrOneBooleanContent);
@@ -687,15 +687,19 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
if ((!name.empty()) && isLongCall(name.c_str())) {
// Create a constant pool entry for the callee address
XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier;
+ XtensaMachineFunctionInfo *XtensaFI =
+ MF.getInfo<XtensaMachineFunctionInfo>();
+ unsigned LabelId = XtensaFI->createCPLabelId();
XtensaConstantPoolValue *CPV = XtensaConstantPoolSymbol::Create(
- *DAG.getContext(), name.c_str(), 0 /* XtensaCLabelIndex */, false,
- Modifier);
+ *DAG.getContext(), name.c_str(), LabelId, 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;
+ Callee = DAG.getLoad(
+ PtrVT, DL, DAG.getEntryNode(), CPWrap,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
}
// The first call operand is the chain and the second is the target address.
@@ -893,22 +897,9 @@ SDValue XtensaTargetLowering::LowerImmediate(SDValue 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::LowerImmediateFP(SDValue Op,
- SelectionDAG &DAG) const {
- const ConstantFPSDNode *CN = cast<ConstantFPSDNode>(Op);
- SDLoc DL(CN);
- APFloat apval = CN->getValueAPF();
- int64_t value = llvm::bit_cast<uint32_t>(CN->getValueAPF().convertToFloat());
- if (Op.getValueType() == MVT::f32) {
- Type *Ty = Type::getInt32Ty(*DAG.getContext());
- Constant *CV = ConstantInt::get(Ty, value);
- SDValue CP = DAG.getConstantPool(CV, MVT::i32);
- return DAG.getNode(ISD::BITCAST, DL, MVT::f32, CP);
+ SDValue Res =
+ DAG.getLoad(MVT::i32, DL, DAG.getEntryNode(), CP, MachinePointerInfo());
+ return Res;
}
return Op;
}
@@ -922,22 +913,30 @@ SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op,
SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, Align(4));
SDValue CPWrap = getAddrPCRel(CPAddr, DAG);
-
- return CPWrap;
+ SDValue Res = DAG.getLoad(
+ PtrVT, DL, DAG.getEntryNode(), CPWrap,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ return Res;
}
SDValue XtensaTargetLowering::LowerBlockAddress(SDValue Op,
SelectionDAG &DAG) const {
BlockAddressSDNode *Node = cast<BlockAddressSDNode>(Op);
+ SDLoc DL(Op);
const BlockAddress *BA = Node->getBlockAddress();
EVT PtrVT = Op.getValueType();
+ MachineFunction &MF = DAG.getMachineFunction();
+ XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
+ unsigned LabelId = XtensaFI->createCPLabelId();
XtensaConstantPoolValue *CPV =
- XtensaConstantPoolConstant::Create(BA, 0, XtensaCP::CPBlockAddress);
+ XtensaConstantPoolConstant::Create(BA, LabelId, XtensaCP::CPBlockAddress);
SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4));
SDValue CPWrap = getAddrPCRel(CPAddr, DAG);
-
- return CPWrap;
+ SDValue Res = DAG.getLoad(
+ PtrVT, DL, DAG.getEntryNode(), CPWrap,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ return Res;
}
SDValue XtensaTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const {
@@ -972,15 +971,19 @@ SDValue XtensaTargetLowering::LowerJumpTable(SDValue Op,
SelectionDAG &DAG) const {
JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
EVT PtrVT = Op.getValueType();
+ SDLoc DL(Op);
- // Create a constant pool entry for the callee address
+ // Create a constant pool entry for the jumptable address
XtensaConstantPoolValue *CPV =
XtensaConstantPoolJumpTable::Create(*DAG.getContext(), JT->getIndex());
- // Get the address of the callee into a register
+ // Get the address of the jumptable into a register
SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4));
- return getAddrPCRel(CPAddr, DAG);
+ SDValue Res = DAG.getLoad(
+ PtrVT, DL, DAG.getEntryNode(), getAddrPCRel(CPAddr, DAG),
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ return Res;
}
SDValue XtensaTargetLowering::getAddrPCRel(SDValue Op,
@@ -1346,8 +1349,6 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
return LowerBR_JT(Op, DAG);
case ISD::Constant:
return LowerImmediate(Op, DAG);
- case ISD::ConstantFP:
- return LowerImmediateFP(Op, DAG);
case ISD::RETURNADDR:
return LowerRETURNADDR(Op, DAG);
case ISD::GlobalAddress:
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
index 850ec6f3b023a..b6f2ebe21c940 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
@@ -154,8 +154,6 @@ class XtensaTargetLowering : public TargetLowering {
SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerImmediateFP(SDValue Op, SelectionDAG &DAG) const;
-
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
index 5b1bc73267157..896e2f8f1c01c 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
@@ -524,8 +524,10 @@ void XtensaInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
JumpToMBB = &RestoreBB;
}
+ unsigned LabelId = XtensaFI->createCPLabelId();
+
XtensaConstantPoolValue *C = XtensaConstantPoolMBB::Create(
- MF->getFunction().getContext(), JumpToMBB, 0);
+ MF->getFunction().getContext(), JumpToMBB, LabelId);
unsigned Idx = ConstantPool->getConstantPoolIndex(C, Align(4));
L32R.addOperand(MachineOperand::CreateCPI(Idx, 0));
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 6ec220e92a939..2648af0571535 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -235,14 +235,11 @@ def S16I : Store_II8<0x05, "s16i", truncstorei16, addr_ish2, mem16>;
def S32I : Store_II8<0x06, "s32i", store, addr_ish4, mem32>;
def L32R : RI16_Inst<0x01, (outs AR:$t), (ins L32Rtarget:$label),
- "l32r\t$t, $label", []> {
+ "l32r\t$t, $label", [(set AR:$t, (load (Xtensa_pcrel_wrapper tconstpool:$label)))]> {
bits<16> 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
@@ -1310,6 +1307,9 @@ def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s),
let t = 0x05;
}
+def : Pat<(f32 (load (Xtensa_pcrel_wrapper tconstpool:$in))),
+ (WFR (L32R tconstpool:$in))>;
+
//===----------------------------------------------------------------------===//
// DSP Instructions
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h
index bc051d9ca14fa..ff3bba0985c27 100644
--- a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h
+++ b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h
@@ -28,6 +28,7 @@ class XtensaMachineFunctionInfo : public MachineFunctionInfo {
int VarArgsOnStackFrameIndex;
int VarArgsInRegsFrameIndex;
bool SaveFrameRegister = false;
+ unsigned CPLabelId = 0;
public:
explicit XtensaMachineFunctionInfo(const Function &F,
@@ -54,6 +55,8 @@ class XtensaMachineFunctionInfo : public MachineFunctionInfo {
bool isSaveFrameRegister() const { return SaveFrameRegister; }
void setSaveFrameRegister() { SaveFrameRegister = true; }
+
+ unsigned createCPLabelId() { return CPLabelId++; }
};
} // namespace llvm
diff --git a/llvm/test/CodeGen/Xtensa/aligned_alloc.ll b/llvm/test/CodeGen/Xtensa/aligned_alloc.ll
index ebb24d9272ddc..471158fb30b70 100644
--- a/llvm/test/CodeGen/Xtensa/aligned_alloc.ll
+++ b/llvm/test/CodeGen/Xtensa/aligned_alloc.ll
@@ -11,10 +11,10 @@ define i8 @loadi8_128(i8 %a) {
; XTENSA-NEXT: .cfi_def_cfa_offset 128
; XTENSA-NEXT: s32i a0, a1, 124 # 4-byte Folded Spill
; XTENSA-NEXT: .cfi_offset a0, -4
+; XTENSA-NEXT: l32r a8, .LCPI0_0
; XTENSA-NEXT: addi a2, a1, 0
; XTENSA-NEXT: movi a3, 0
; XTENSA-NEXT: movi a4, 64
-; XTENSA-NEXT: l32r a8, .LCPI0_0
; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: l8ui a2, a1, 0
; XTENSA-NEXT: l32i a0, a1, 124 # 4-byte Folded Reload
diff --git a/llvm/test/CodeGen/Xtensa/bswap.ll b/llvm/test/CodeGen/Xtensa/bswap.ll
index 6a87aa84351cf..a836f4c30e3eb 100644
--- a/llvm/test/CodeGen/Xtensa/bswap.ll
+++ b/llvm/test/CodeGen/Xtensa/bswap.ll
@@ -12,7 +12,8 @@ declare i64 @llvm.bitreverse.i64(i64)
define i16 @test_bswap_i16(i16 %a) nounwind {
; XTENSA-LABEL: test_bswap_i16:
-; XTENSA: l32r a8, .LCPI0_0
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI0_0
; XTENSA-NEXT: and a8, a2, a8
; XTENSA-NEXT: srli a8, a8, 8
; XTENSA-NEXT: slli a9, a2, 8
@@ -24,7 +25,8 @@ define i16 @test_bswap_i16(i16 %a) nounwind {
define i32 @test_bswap_i32(i32 %a) nounwind {
; XTENSA-LABEL: test_bswap_i32:
-; XTENSA: srli a8, a2, 8
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 8
; XTENSA-NEXT: l32r a9, .LCPI1_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: extui a10, a2, 24, 8
@@ -41,7 +43,8 @@ define i32 @test_bswap_i32(i32 %a) nounwind {
define i64 @test_bswap_i64(i64 %a) nounwind {
; XTENSA-LABEL: test_bswap_i64:
-; XTENSA: srli a8, a3, 8
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a3, 8
; XTENSA-NEXT: l32r a9, .LCPI2_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: extui a10, a3, 24, 8
@@ -68,7 +71,8 @@ define i64 @test_bswap_i64(i64 %a) nounwind {
define i8 @test_bitreverse_i8(i8 %a) nounwind {
; XTENSA-LABEL: test_bitreverse_i8:
-; XTENSA: movi a8, 15
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: movi a8, 15
; XTENSA-NEXT: and a8, a2, a8
; XTENSA-NEXT: slli a8, a8, 4
; XTENSA-NEXT: movi a9, 240
@@ -94,7 +98,8 @@ define i8 @test_bitreverse_i8(i8 %a) nounwind {
define i16 @test_bitreverse_i16(i16 %a) nounwind {
; XTENSA-LABEL: test_bitreverse_i16:
-; XTENSA: l32r a8, .LCPI4_0
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: l32r a8, .LCPI4_0
; XTENSA-NEXT: and a8, a2, a8
; XTENSA-NEXT: srli a8, a8, 8
; XTENSA-NEXT: slli a9, a2, 8
@@ -124,7 +129,8 @@ define i16 @test_bitreverse_i16(i16 %a) nounwind {
define i32 @test_bitreverse_i32(i32 %a) nounwind {
; XTENSA-LABEL: test_bitreverse_i32:
-; XTENSA: srli a8, a2, 8
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 8
; XTENSA-NEXT: l32r a9, .LCPI5_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: extui a10, a2, 24, 8
@@ -159,7 +165,8 @@ define i32 @test_bitreverse_i32(i32 %a) nounwind {
define i64 @test_bitreverse_i64(i64 %a) nounwind {
; XTENSA-LABEL: test_bitreverse_i64:
-; XTENSA: srli a8, a3, 8
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a3, 8
; XTENSA-NEXT: l32r a9, .LCPI6_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: extui a10, a3, 24, 8
@@ -219,7 +226,8 @@ define i64 @test_bitreverse_i64(i64 %a) nounwind {
define i16 @test_bswap_bitreverse_i16(i16 %a) nounwind {
; XTENSA-LABEL: test_bswap_bitreverse_i16:
-; XTENSA: srli a8, a2, 4
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 4
; XTENSA-NEXT: l32r a9, .LCPI7_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: and a9, a2, a9
@@ -245,7 +253,8 @@ define i16 @test_bswap_bitreverse_i16(i16 %a) nounwind {
define i32 @test_bswap_bitreverse_i32(i32 %a) nounwind {
; XTENSA-LABEL: test_bswap_bitreverse_i32:
-; XTENSA: srli a8, a2, 4
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 4
; XTENSA-NEXT: l32r a9, .LCPI8_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: and a9, a2, a9
@@ -271,7 +280,8 @@ define i32 @test_bswap_bitreverse_i32(i32 %a) nounwind {
define i64 @test_bswap_bitreverse_i64(i64 %a) nounwind {
; XTENSA-LABEL: test_bswap_bitreverse_i64:
-; XTENSA: srli a8, a2, 4
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 4
; XTENSA-NEXT: l32r a9, .LCPI9_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: and a10, a2, a9
@@ -312,7 +322,8 @@ define i64 @test_bswap_bitreverse_i64(i64 %a) nounwind {
define i16 @test_bitreverse_bswap_i16(i16 %a) nounwind {
; XTENSA-LABEL: test_bitreverse_bswap_i16:
-; XTENSA: srli a8, a2, 4
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 4
; XTENSA-NEXT: l32r a9, .LCPI10_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: and a9, a2, a9
@@ -338,7 +349,8 @@ define i16 @test_bitreverse_bswap_i16(i16 %a) nounwind {
define i32 @test_bitreverse_bswap_i32(i32 %a) nounwind {
; XTENSA-LABEL: test_bitreverse_bswap_i32:
-; XTENSA: srli a8, a2, 4
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 4
; XTENSA-NEXT: l32r a9, .LCPI11_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: and a9, a2, a9
@@ -364,7 +376,8 @@ define i32 @test_bitreverse_bswap_i32(i32 %a) nounwind {
define i64 @test_bitreverse_bswap_i64(i64 %a) nounwind {
; XTENSA-LABEL: test_bitreverse_bswap_i64:
-; XTENSA: srli a8, a2, 4
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 4
; XTENSA-NEXT: l32r a9, .LCPI12_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: and a10, a2, a9
diff --git a/llvm/test/CodeGen/Xtensa/ctlz-cttz-ctpop.ll b/llvm/test/CodeGen/Xtensa/ctlz-cttz-ctpop.ll
index 6030323538625..2524a333556e2 100644
--- a/llvm/test/CodeGen/Xtensa/ctlz-cttz-ctpop.ll
+++ b/llvm/test/CodeGen/Xtensa/ctlz-cttz-ctpop.ll
@@ -8,7 +8,8 @@ declare i32 @llvm.ctpop.i32(i32)
define i32 @test_cttz_i32(i32 %a) nounwind {
; XTENSA-LABEL: test_cttz_i32:
-; XTENSA: beqz a2, .LBB0_2
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: beqz a2, .LBB0_2
; XTENSA-NEXT: # %bb.1: # %cond.false
; XTENSA-NEXT: movi a8, -1
; XTENSA-NEXT: xor a8, a2, a8
@@ -42,7 +43,8 @@ define i32 @test_cttz_i32(i32 %a) nounwind {
define i32 @test_cttz_i32_zero_undef(i32 %a) nounwind {
; XTENSA-LABEL: test_cttz_i32_zero_undef:
-; XTENSA: movi a8, -1
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: movi a8, -1
; XTENSA-NEXT: xor a8, a2, a8
; XTENSA-NEXT: addi a9, a2, -1
; XTENSA-NEXT: and a8, a8, a9
@@ -71,7 +73,8 @@ define i32 @test_cttz_i32_zero_undef(i32 %a) nounwind {
define i32 @test_ctlz_i32(i32 %a) nounwind {
; XTENSA-LABEL: test_ctlz_i32:
-; XTENSA: beqz a2, .LBB2_2
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: beqz a2, .LBB2_2
; XTENSA-NEXT: # %bb.1: # %cond.false
; XTENSA-NEXT: srli a8, a2, 1
; XTENSA-NEXT: or a8, a2, a8
@@ -113,7 +116,8 @@ define i32 @test_ctlz_i32(i32 %a) nounwind {
define i32 @test_ctlz_i32_zero_undef(i32 %a) nounwind {
; XTENSA-LABEL: test_ctlz_i32_zero_undef:
-; XTENSA: srli a8, a2, 1
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 1
; XTENSA-NEXT: or a8, a2, a8
; XTENSA-NEXT: srli a9, a8, 2
; XTENSA-NEXT: or a8, a8, a9
@@ -150,7 +154,8 @@ define i32 @test_ctlz_i32_zero_undef(i32 %a) nounwind {
define i32 @test_ctpop_i32(i32 %a) nounwind {
; XTENSA-LABEL: test_ctpop_i32:
-; XTENSA: srli a8, a2, 1
+; XTENSA: # %bb.0:
+; XTENSA-NEXT: srli a8, a2, 1
; XTENSA-NEXT: l32r a9, .LCPI4_0
; XTENSA-NEXT: and a8, a8, a9
; XTENSA-NEXT: sub a8, a2, a8
diff --git a/llvm/test/CodeGen/Xtensa/mul.ll b/llvm/test/CodeGen/Xtensa/mul.ll
index 6901323822280..4dd03e408fcf4 100644
--- a/llvm/test/CodeGen/Xtensa/mul.ll
+++ b/llvm/test/CodeGen/Xtensa/mul.ll
@@ -767,51 +767,52 @@ define i64 @muli64_m3840(i64 %a) nounwind {
define i128 @muli128_m3840(i128 %a) nounwind {
; XTENSA-LABEL: muli128_m3840:
; XTENSA: # %bb.0:
-; XTENSA-NEXT: addi a8, a1, -80
+; XTENSA-NEXT: addi a8, a1, -64
; XTENSA-NEXT: or a1, a8, a8
-; XTENSA-NEXT: s32i a0, a1, 64 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a12, a1, 60 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a13, a1, 56 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a14, a1, 52 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 48 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a0, a1, 60 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a12, a1, 56 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a13, a1, 52 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a14, a1, 48 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a15, a1, 44 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a5, a1, 20 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a4, a1, 16 # 4-byte Folded Spill
-; XTENSA-NEXT: or a15, a3, a3
-; XTENSA-NEXT: l32r a14, .LCPI30_0
+; XTENSA-NEXT: or a13, a3, a3
+; XTENSA-NEXT: l32r a15, .LCPI30_0
; XTENSA-NEXT: movi a12, 0
-; XTENSA-NEXT: l32r a13, .LCPI30_1
+; XTENSA-NEXT: l32r a8, .LCPI30_1
; XTENSA-NEXT: s32i a2, a1, 36 # 4-byte Folded Spill
; XTENSA-NEXT: or a3, a12, a12
-; XTENSA-NEXT: or a4, a14, a14
+; XTENSA-NEXT: or a4, a15, a15
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a2, a1, 28 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a3, a1, 44 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 40 # 4-byte Folded Spill
-; XTENSA-NEXT: or a2, a15, a15
+; XTENSA-NEXT: or a14, a3, a3
+; XTENSA-NEXT: l32r a8, .LCPI30_2
+; XTENSA-NEXT: s32i a13, a1, 40 # 4-byte Folded Spill
+; XTENSA-NEXT: or a2, a13, a13
; XTENSA-NEXT: or a3, a12, a12
-; XTENSA-NEXT: s32i a14, a1, 12 # 4-byte Folded Spill
-; XTENSA-NEXT: or a4, a14, a14
+; XTENSA-NEXT: s32i a15, a1, 12 # 4-byte Folded Spill
+; XTENSA-NEXT: or a4, a15, a15
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
-; XTENSA-NEXT: l32i a8, a1, 44 # 4-byte Folded Reload
-; XTENSA-NEXT: add a15, a2, a8
-; XTENSA-NEXT: movi a8, 1
-; XTENSA-NEXT: s32i a8, a1, 44 # 4-byte Folded Spill
-; XTENSA-NEXT: bltu a15, a2, .LBB30_2
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: add a13, a2, a14
+; XTENSA-NEXT: movi a15, 1
+; XTENSA-NEXT: or a8, a15, a15
+; XTENSA-NEXT: bltu a13, a2, .LBB30_2
; XTENSA-NEXT: # %bb.1:
; XTENSA-NEXT: or a8, a12, a12
; XTENSA-NEXT: .LBB30_2:
; XTENSA-NEXT: add a8, a3, a8
; XTENSA-NEXT: s32i a8, a1, 32 # 4-byte Folded Spill
; XTENSA-NEXT: movi a14, -1
+; XTENSA-NEXT: l32r a8, .LCPI30_3
; XTENSA-NEXT: l32i a2, a1, 36 # 4-byte Folded Reload
; XTENSA-NEXT: or a3, a12, a12
; XTENSA-NEXT: or a4, a14, a14
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
-; XTENSA-NEXT: add a9, a2, a15
-; XTENSA-NEXT: l32i a8, a1, 44 # 4-byte Folded Reload
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: add a9, a2, a13
+; XTENSA-NEXT: or a8, a15, a15
; XTENSA-NEXT: s32i a9, a1, 24 # 4-byte Folded Spill
; XTENSA-NEXT: bltu a9, a2, .LBB30_4
; XTENSA-NEXT: # %bb.3:
@@ -819,70 +820,72 @@ define i128 @muli128_m3840(i128 %a) nounwind {
; XTENSA-NEXT: .LBB30_4:
; XTENSA-NEXT: add a8, a3, a8
; XTENSA-NEXT: l32i a9, a1, 32 # 4-byte Folded Reload
-; XTENSA-NEXT: add a15, a9, a8
+; XTENSA-NEXT: add a13, a9, a8
+; XTENSA-NEXT: l32r a8, .LCPI30_4
; XTENSA-NEXT: l32i a2, a1, 40 # 4-byte Folded Reload
; XTENSA-NEXT: or a3, a12, a12
; XTENSA-NEXT: or a4, a14, a14
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a3, a1, 4 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 8 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a13, a1, 8 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a2, a1, 0 # 4-byte Folded Spill
-; XTENSA-NEXT: add a15, a2, a15
+; XTENSA-NEXT: add a13, a2, a13
+; XTENSA-NEXT: l32r a8, .LCPI30_5
; XTENSA-NEXT: l32i a2, a1, 16 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a3, a1, 20 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a4, a1, 12 # 4-byte Folded Reload
; XTENSA-NEXT: or a5, a14, a14
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a2, a1, 16 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a3, a1, 20 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI30_6
; XTENSA-NEXT: l32i a2, a1, 36 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a3, a1, 40 # 4-byte Folded Reload
; XTENSA-NEXT: or a4, a14, a14
; XTENSA-NEXT: or a5, a14, a14
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: l32i a8, a1, 16 # 4-byte Folded Reload
; XTENSA-NEXT: add a9, a2, a8
-; XTENSA-NEXT: add a4, a15, a9
-; XTENSA-NEXT: l32i a7, a1, 44 # 4-byte Folded Reload
-; XTENSA-NEXT: or a8, a7, a7
-; XTENSA-NEXT: bltu a4, a15, .LBB30_6
+; XTENSA-NEXT: add a4, a13, a9
+; XTENSA-NEXT: or a8, a15, a15
+; XTENSA-NEXT: bltu a4, a13, .LBB30_6
; XTENSA-NEXT: # %bb.5:
; XTENSA-NEXT: or a8, a12, a12
; XTENSA-NEXT: .LBB30_6:
-; XTENSA-NEXT: or a10, a7, a7
+; XTENSA-NEXT: or a10, a15, a15
; XTENSA-NEXT: l32i a11, a1, 0 # 4-byte Folded Reload
-; XTENSA-NEXT: bltu a15, a11, .LBB30_8
+; XTENSA-NEXT: bltu a13, a11, .LBB30_8
; XTENSA-NEXT: # %bb.7:
; XTENSA-NEXT: or a10, a12, a12
; XTENSA-NEXT: .LBB30_8:
-; XTENSA-NEXT: or a11, a7, a7
-; XTENSA-NEXT: l32i a6, a1, 32 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a5, a1, 8 # 4-byte Folded Reload
-; XTENSA-NEXT: bltu a5, a6, .LBB30_10
+; XTENSA-NEXT: or a11, a15, a15
+; XTENSA-NEXT: l32i a7, a1, 32 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a6, a1, 8 # 4-byte Folded Reload
+; XTENSA-NEXT: bltu a6, a7, .LBB30_10
; XTENSA-NEXT: # %bb.9:
; XTENSA-NEXT: or a11, a12, a12
; XTENSA-NEXT: .LBB30_10:
-; XTENSA-NEXT: l32i a6, a1, 4 # 4-byte Folded Reload
-; XTENSA-NEXT: add a11, a6, a11
+; XTENSA-NEXT: l32i a7, a1, 4 # 4-byte Folded Reload
+; XTENSA-NEXT: add a11, a7, a11
; XTENSA-NEXT: add a10, a11, a10
; XTENSA-NEXT: bltu a9, a2, .LBB30_12
; XTENSA-NEXT: # %bb.11:
-; XTENSA-NEXT: or a7, a12, a12
+; XTENSA-NEXT: or a15, a12, a12
; XTENSA-NEXT: .LBB30_12:
; XTENSA-NEXT: l32i a9, a1, 20 # 4-byte Folded Reload
; XTENSA-NEXT: add a9, a3, a9
-; XTENSA-NEXT: add a9, a9, a7
+; XTENSA-NEXT: add a9, a9, a15
; XTENSA-NEXT: add a9, a10, a9
; XTENSA-NEXT: add a5, a9, a8
; XTENSA-NEXT: l32i a2, a1, 28 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a3, a1, 24 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a15, a1, 48 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a14, a1, 52 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a13, a1, 56 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a12, a1, 60 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a0, a1, 64 # 4-byte Folded Reload
-; XTENSA-NEXT: addi a8, a1, 80
+; XTENSA-NEXT: l32i a15, a1, 44 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a14, a1, 48 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a13, a1, 52 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a12, a1, 56 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a0, a1, 60 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 64
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
;
@@ -980,51 +983,52 @@ define i128 @muli128_m3840(i128 %a) nounwind {
define i128 @muli128_m63(i128 %a) nounwind {
; XTENSA-LABEL: muli128_m63:
; XTENSA: # %bb.0:
-; XTENSA-NEXT: addi a8, a1, -80
+; XTENSA-NEXT: addi a8, a1, -64
; XTENSA-NEXT: or a1, a8, a8
-; XTENSA-NEXT: s32i a0, a1, 64 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a12, a1, 60 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a13, a1, 56 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a14, a1, 52 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 48 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a0, a1, 60 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a12, a1, 56 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a13, a1, 52 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a14, a1, 48 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a15, a1, 44 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a5, a1, 20 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a4, a1, 16 # 4-byte Folded Spill
-; XTENSA-NEXT: or a15, a3, a3
-; XTENSA-NEXT: movi a14, -63
+; XTENSA-NEXT: or a13, a3, a3
+; XTENSA-NEXT: movi a15, -63
; XTENSA-NEXT: movi a12, 0
-; XTENSA-NEXT: l32r a13, .LCPI31_0
+; XTENSA-NEXT: l32r a8, .LCPI31_0
; XTENSA-NEXT: s32i a2, a1, 36 # 4-byte Folded Spill
; XTENSA-NEXT: or a3, a12, a12
-; XTENSA-NEXT: or a4, a14, a14
+; XTENSA-NEXT: or a4, a15, a15
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a2, a1, 28 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a3, a1, 44 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 40 # 4-byte Folded Spill
-; XTENSA-NEXT: or a2, a15, a15
+; XTENSA-NEXT: or a14, a3, a3
+; XTENSA-NEXT: l32r a8, .LCPI31_1
+; XTENSA-NEXT: s32i a13, a1, 40 # 4-byte Folded Spill
+; XTENSA-NEXT: or a2, a13, a13
; XTENSA-NEXT: or a3, a12, a12
-; XTENSA-NEXT: s32i a14, a1, 12 # 4-byte Folded Spill
-; XTENSA-NEXT: or a4, a14, a14
+; XTENSA-NEXT: s32i a15, a1, 12 # 4-byte Folded Spill
+; XTENSA-NEXT: or a4, a15, a15
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
-; XTENSA-NEXT: l32i a8, a1, 44 # 4-byte Folded Reload
-; XTENSA-NEXT: add a15, a2, a8
-; XTENSA-NEXT: movi a8, 1
-; XTENSA-NEXT: s32i a8, a1, 44 # 4-byte Folded Spill
-; XTENSA-NEXT: bltu a15, a2, .LBB31_2
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: add a13, a2, a14
+; XTENSA-NEXT: movi a15, 1
+; XTENSA-NEXT: or a8, a15, a15
+; XTENSA-NEXT: bltu a13, a2, .LBB31_2
; XTENSA-NEXT: # %bb.1:
; XTENSA-NEXT: or a8, a12, a12
; XTENSA-NEXT: .LBB31_2:
; XTENSA-NEXT: add a8, a3, a8
; XTENSA-NEXT: s32i a8, a1, 32 # 4-byte Folded Spill
; XTENSA-NEXT: movi a14, -1
+; XTENSA-NEXT: l32r a8, .LCPI31_2
; XTENSA-NEXT: l32i a2, a1, 36 # 4-byte Folded Reload
; XTENSA-NEXT: or a3, a12, a12
; XTENSA-NEXT: or a4, a14, a14
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
-; XTENSA-NEXT: add a9, a2, a15
-; XTENSA-NEXT: l32i a8, a1, 44 # 4-byte Folded Reload
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: add a9, a2, a13
+; XTENSA-NEXT: or a8, a15, a15
; XTENSA-NEXT: s32i a9, a1, 24 # 4-byte Folded Spill
; XTENSA-NEXT: bltu a9, a2, .LBB31_4
; XTENSA-NEXT: # %bb.3:
@@ -1032,70 +1036,72 @@ define i128 @muli128_m63(i128 %a) nounwind {
; XTENSA-NEXT: .LBB31_4:
; XTENSA-NEXT: add a8, a3, a8
; XTENSA-NEXT: l32i a9, a1, 32 # 4-byte Folded Reload
-; XTENSA-NEXT: add a15, a9, a8
+; XTENSA-NEXT: add a13, a9, a8
+; XTENSA-NEXT: l32r a8, .LCPI31_3
; XTENSA-NEXT: l32i a2, a1, 40 # 4-byte Folded Reload
; XTENSA-NEXT: or a3, a12, a12
; XTENSA-NEXT: or a4, a14, a14
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a3, a1, 4 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 8 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a13, a1, 8 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a2, a1, 0 # 4-byte Folded Spill
-; XTENSA-NEXT: add a15, a2, a15
+; XTENSA-NEXT: add a13, a2, a13
+; XTENSA-NEXT: l32r a8, .LCPI31_4
; XTENSA-NEXT: l32i a2, a1, 16 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a3, a1, 20 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a4, a1, 12 # 4-byte Folded Reload
; XTENSA-NEXT: or a5, a14, a14
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a2, a1, 16 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a3, a1, 20 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI31_5
; XTENSA-NEXT: l32i a2, a1, 36 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a3, a1, 40 # 4-byte Folded Reload
; XTENSA-NEXT: or a4, a14, a14
; XTENSA-NEXT: or a5, a14, a14
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: l32i a8, a1, 16 # 4-byte Folded Reload
; XTENSA-NEXT: add a9, a2, a8
-; XTENSA-NEXT: add a4, a15, a9
-; XTENSA-NEXT: l32i a7, a1, 44 # 4-byte Folded Reload
-; XTENSA-NEXT: or a8, a7, a7
-; XTENSA-NEXT: bltu a4, a15, .LBB31_6
+; XTENSA-NEXT: add a4, a13, a9
+; XTENSA-NEXT: or a8, a15, a15
+; XTENSA-NEXT: bltu a4, a13, .LBB31_6
; XTENSA-NEXT: # %bb.5:
; XTENSA-NEXT: or a8, a12, a12
; XTENSA-NEXT: .LBB31_6:
-; XTENSA-NEXT: or a10, a7, a7
+; XTENSA-NEXT: or a10, a15, a15
; XTENSA-NEXT: l32i a11, a1, 0 # 4-byte Folded Reload
-; XTENSA-NEXT: bltu a15, a11, .LBB31_8
+; XTENSA-NEXT: bltu a13, a11, .LBB31_8
; XTENSA-NEXT: # %bb.7:
; XTENSA-NEXT: or a10, a12, a12
; XTENSA-NEXT: .LBB31_8:
-; XTENSA-NEXT: or a11, a7, a7
-; XTENSA-NEXT: l32i a6, a1, 32 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a5, a1, 8 # 4-byte Folded Reload
-; XTENSA-NEXT: bltu a5, a6, .LBB31_10
+; XTENSA-NEXT: or a11, a15, a15
+; XTENSA-NEXT: l32i a7, a1, 32 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a6, a1, 8 # 4-byte Folded Reload
+; XTENSA-NEXT: bltu a6, a7, .LBB31_10
; XTENSA-NEXT: # %bb.9:
; XTENSA-NEXT: or a11, a12, a12
; XTENSA-NEXT: .LBB31_10:
-; XTENSA-NEXT: l32i a6, a1, 4 # 4-byte Folded Reload
-; XTENSA-NEXT: add a11, a6, a11
+; XTENSA-NEXT: l32i a7, a1, 4 # 4-byte Folded Reload
+; XTENSA-NEXT: add a11, a7, a11
; XTENSA-NEXT: add a10, a11, a10
; XTENSA-NEXT: bltu a9, a2, .LBB31_12
; XTENSA-NEXT: # %bb.11:
-; XTENSA-NEXT: or a7, a12, a12
+; XTENSA-NEXT: or a15, a12, a12
; XTENSA-NEXT: .LBB31_12:
; XTENSA-NEXT: l32i a9, a1, 20 # 4-byte Folded Reload
; XTENSA-NEXT: add a9, a3, a9
-; XTENSA-NEXT: add a9, a9, a7
+; XTENSA-NEXT: add a9, a9, a15
; XTENSA-NEXT: add a9, a10, a9
; XTENSA-NEXT: add a5, a9, a8
; XTENSA-NEXT: l32i a2, a1, 28 # 4-byte Folded Reload
; XTENSA-NEXT: l32i a3, a1, 24 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a15, a1, 48 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a14, a1, 52 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a13, a1, 56 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a12, a1, 60 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a0, a1, 64 # 4-byte Folded Reload
-; XTENSA-NEXT: addi a8, a1, 80
+; XTENSA-NEXT: l32i a15, a1, 44 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a14, a1, 48 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a13, a1, 52 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a12, a1, 56 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a0, a1, 60 # 4-byte Folded Reload
+; XTENSA-NEXT: addi a8, a1, 64
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
;
@@ -1195,30 +1201,30 @@ define i64 @mulhsu_i64(i64 %a, i64 %b) nounwind {
; XTENSA: # %bb.0:
; XTENSA-NEXT: addi a8, a1, -64
; XTENSA-NEXT: or a1, a8, a8
-; XTENSA-NEXT: s32i a0, a1, 56 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a12, a1, 52 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a13, a1, 48 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a14, a1, 44 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 40 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a0, a1, 52 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a12, a1, 48 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a13, a1, 44 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a14, a1, 40 # 4-byte Folded Spill
+; XTENSA-NEXT: s32i a15, a1, 36 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a5, a1, 28 # 4-byte Folded Spill
-; XTENSA-NEXT: or a14, a4, a4
+; XTENSA-NEXT: or a13, a4, a4
; XTENSA-NEXT: or a15, a3, a3
; XTENSA-NEXT: movi a12, 0
-; XTENSA-NEXT: l32r a13, .LCPI32_0
+; XTENSA-NEXT: l32r a8, .LCPI32_0
; XTENSA-NEXT: s32i a2, a1, 32 # 4-byte Folded Spill
; XTENSA-NEXT: or a3, a12, a12
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
-; XTENSA-NEXT: s32i a3, a1, 24 # 4-byte Folded Spill
-; XTENSA-NEXT: s32i a15, a1, 36 # 4-byte Folded Spill
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: or a14, a3, a3
+; XTENSA-NEXT: l32r a8, .LCPI32_1
+; XTENSA-NEXT: s32i a15, a1, 20 # 4-byte Folded Spill
; XTENSA-NEXT: or a2, a15, a15
; XTENSA-NEXT: or a3, a12, a12
-; XTENSA-NEXT: s32i a14, a1, 16 # 4-byte Folded Spill
-; XTENSA-NEXT: or a4, a14, a14
+; XTENSA-NEXT: s32i a13, a1, 16 # 4-byte Folded Spill
+; XTENSA-NEXT: or a4, a13, a13
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
-; XTENSA-NEXT: l32i a8, a1, 24 # 4-byte Folded Reload
-; XTENSA-NEXT: add a14, a2, a8
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: add a14, a2, a14
; XTENSA-NEXT: movi a15, 1
; XTENSA-NEXT: or a8, a15, a15
; XTENSA-NEXT: bltu a14, a2, .LBB32_2
@@ -1227,13 +1233,13 @@ define i64 @mulhsu_i64(i64 %a, i64 %b) nounwind {
; XTENSA-NEXT: .LBB32_2:
; XTENSA-NEXT: add a8, a3, a8
; XTENSA-NEXT: s32i a8, a1, 24 # 4-byte Folded Spill
+; XTENSA-NEXT: l32r a8, .LCPI32_2
; XTENSA-NEXT: l32i a2, a1, 32 # 4-byte Folded Reload
; XTENSA-NEXT: or a3, a12, a12
; XTENSA-NEXT: l32i a4, a1, 28 # 4-byte Folded Reload
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: add a9, a2, a14
-; XTENSA-NEXT: s32i a15, a1, 20 # 4-byte Folded Spill
; XTENSA-NEXT: or a8, a15, a15
; XTENSA-NEXT: bltu a9, a2, .LBB32_4
; XTENSA-NEXT: # %bb.3:
@@ -1242,68 +1248,70 @@ define i64 @mulhsu_i64(i64 %a, i64 %b) nounwind {
; XTENSA-NEXT: add a8, a3, a8
; XTENSA-NEXT: l32i a9, a1, 24 # 4-byte Folded Reload
; XTENSA-NEXT: add a14, a9, a8
-; XTENSA-NEXT: l32i a2, a1, 36 # 4-byte Folded Reload
+; XTENSA-NEXT: l32r a8, .LCPI32_3
+; XTENSA-NEXT: l32i a2, a1, 20 # 4-byte Folded Reload
; XTENSA-NEXT: or a3, a12, a12
-; XTENSA-NEXT: l32i a15, a1, 28 # 4-byte Folded Reload
-; XTENSA-NEXT: or a4, a15, a15
+; XTENSA-NEXT: l32i a13, a1, 28 # 4-byte Folded Reload
+; XTENSA-NEXT: or a4, a13, a13
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a3, a1, 8 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a14, a1, 12 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a2, a1, 4 # 4-byte Folded Spill
; XTENSA-NEXT: add a14, a2, a14
+; XTENSA-NEXT: l32r a8, .LCPI32_4
; XTENSA-NEXT: l32i a2, a1, 16 # 4-byte Folded Reload
-; XTENSA-NEXT: or a3, a15, a15
+; XTENSA-NEXT: or a3, a13, a13
; XTENSA-NEXT: or a4, a12, a12
; XTENSA-NEXT: or a5, a12, a12
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: s32i a2, a1, 0 # 4-byte Folded Spill
; XTENSA-NEXT: s32i a3, a1, 16 # 4-byte Folded Spill
-; XTENSA-NEXT: srai a2, a15, 31
+; XTENSA-NEXT: srai a2, a13, 31
+; XTENSA-NEXT: l32r a8, .LCPI32_5
; XTENSA-NEXT: or a3, a2, a2
; XTENSA-NEXT: l32i a4, a1, 32 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a5, a1, 36 # 4-byte Folded Reload
-; XTENSA-NEXT: callx0 a13
+; XTENSA-NEXT: l32i a5, a1, 20 # 4-byte Folded Reload
+; XTENSA-NEXT: callx0 a8
; XTENSA-NEXT: or a8, a2, a2
; XTENSA-NEXT: l32i a9, a1, 0 # 4-byte Folded Reload
; XTENSA-NEXT: add a10, a8, a9
; XTENSA-NEXT: add a2, a14, a10
-; XTENSA-NEXT: l32i a6, a1, 20 # 4-byte Folded Reload
-; XTENSA-NEXT: or a9, a6, a6
+; XTENSA-NEXT: or a9, a15, a15
; XTENSA-NEXT: bltu a2, a14, .LBB32_6
; XTENSA-NEXT: # %bb.5:
; XTENSA-NEXT: or a9, a12, a12
; XTENSA-NEXT: .LBB32_6:
-; XTENSA-NEXT: or a11, a6, a6
+; XTENSA-NEXT: or a11, a15, a15
; XTENSA-NEXT: l32i a7, a1, 4 # 4-byte Folded Reload
; XTENSA-NEXT: bltu a14, a7, .LBB32_8
; XTENSA-NEXT: # %bb.7:
; XTENSA-NEXT: or a11, a12, a12
; XTENSA-NEXT: .LBB32_8:
-; XTENSA-NEXT: or a7, a6, a6
-; XTENSA-NEXT: l32i a5, a1, 24 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a4, a1, 12 # 4-byte Folded Reload
-; XTENSA-NEXT: bltu a4, a5, .LBB32_10
+; XTENSA-NEXT: or a7, a15, a15
+; XTENSA-NEXT: l32i a6, a1, 24 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a5, a1, 12 # 4-byte Folded Reload
+; XTENSA-NEXT: bltu a5, a6, .LBB32_10
; XTENSA-NEXT: # %bb.9:
; XTENSA-NEXT: or a7, a12, a12
; XTENSA-NEXT: .LBB32_10:
-; XTENSA-NEXT: l32i a5, a1, 8 # 4-byte Folded Reload
-; XTENSA-NEXT: add a7, a5, a7
+; XTENSA-NEXT: l32i a6, a1, 8 # 4-byte Folded Reload
+; XTENSA-NEXT: add a7, a6, a7
; XTENSA-NEXT: add a11, a7, a11
; XTENSA-NEXT: bltu a10, a8, .LBB32_12
; XTENSA-NEXT: # %bb.11:
-; XTENSA-NEXT: or a6, a12, a12
+; XTENSA-NEXT: or a15, a12, a12
; XTENSA-NEXT: .LBB32_12:
; XTENSA-NEXT: l32i a8, a1, 16 # 4-byte Folded Reload
; XTENSA-NEXT: add a8, a3, a8
-; XTENSA-NEXT: add a8, a8, a6
+; XTENSA-NEXT: add a8, a8, a15
; XTENSA-NEXT: add a8, a11, a8
; XTENSA-NEXT: add a3, a8, a9
-; XTENSA-NEXT: l32i a15, a1, 40 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a14, a1, 44 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a13, a1, 48 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a12, a1, 52 # 4-byte Folded Reload
-; XTENSA-NEXT: l32i a0, a1, 56 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a15, a1, 36 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a14, a1, 40 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a13, a1, 44 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a12, a1, 48 # 4-byte Folded Reload
+; XTENSA-NEXT: l32i a0, a1, 52 # 4-byte Folded Reload
; XTENSA-NEXT: addi a8, a1, 64
; XTENSA-NEXT: or a1, a8, a8
; XTENSA-NEXT: ret
>From fe21537dcbc92014134d128d03a794ea5db79554 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Tue, 27 May 2025 12:51:41 +0300
Subject: [PATCH 5/5] [Xtensa] Implement pattern ordering for load from
ConstnatPool.
---
llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 6 ------
llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 2 ++
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
index b4c8d22278911..06cccd4831bfc 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
@@ -50,12 +50,6 @@ class XtensaDAGToDAGISel : public SelectionDAGISel {
int Scale) {
EVT ValTy = Addr.getValueType();
- if (Addr.getOpcode() == XtensaISD::PCREL_WRAPPER) {
- Base = Addr.getOperand(0);
- if (Base.getOpcode() == ISD::TargetConstantPool)
- return false; // We want to select L32R instead.
- }
-
// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 2648af0571535..8f67dad817d46 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -234,6 +234,7 @@ def S8I : Store_II8<0x04, "s8i", truncstorei8, addr_ish1, mem8>;
def S16I : Store_II8<0x05, "s16i", truncstorei16, addr_ish2, mem16>;
def S32I : Store_II8<0x06, "s32i", store, addr_ish4, mem32>;
+let AddedComplexity = 10 in
def L32R : RI16_Inst<0x01, (outs AR:$t), (ins L32Rtarget:$label),
"l32r\t$t, $label", [(set AR:$t, (load (Xtensa_pcrel_wrapper tconstpool:$label)))]> {
bits<16> label;
@@ -1307,6 +1308,7 @@ def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s),
let t = 0x05;
}
+let AddedComplexity = 10 in
def : Pat<(f32 (load (Xtensa_pcrel_wrapper tconstpool:$in))),
(WFR (L32R tconstpool:$in))>;
More information about the llvm-commits
mailing list