Skip to content

[Xtensa] Implement Xtensa Floating Point Option. #136086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,44 @@ static DecodeStatus DecodeMR23RegisterClass(MCInst &Inst, uint64_t RegNo,
return MCDisassembler::Success;
}

static const unsigned FPRDecoderTable[] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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};

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];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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 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,
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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!");
}
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/Xtensa/XtensaCallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>>
]>;

Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/Xtensa/XtensaFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -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()">,
Expand Down
168 changes: 167 additions & 1 deletion llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
Comment on lines +78 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom looks the same as default expand


setBooleanContents(ZeroOrOneBooleanContent);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mostly reinventing the default logic based on legal 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());
}
Expand All @@ -185,6 +291,11 @@ bool XtensaTargetLowering::isOffsetFoldingLegal(
return false;
}

bool XtensaTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const {
return false;
}
Comment on lines +294 to +297
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is redundant if you make ConstantFP Expand


//===----------------------------------------------------------------------===//
// Inline asm support
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -815,6 +936,21 @@ SDValue XtensaTargetLowering::LowerImmediate(SDValue Op,
return Op;
}

SDValue XtensaTargetLowering::LowerImmediateFP(SDValue Op,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same as the default expansion?

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);
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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".
Expand Down
23 changes: 23 additions & 0 deletions llvm/lib/Target/Xtensa/XtensaISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
}

Expand All @@ -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())
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 9 additions & 5 deletions llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading