[Xtensa] Implement SEXT, NSA, MINMAX and Loop Xtensa Options. (#133818)
Implement basic support of the several simple Xtensa Options with 1-4 instructions for each option. The Sign Extend Option (SEXT). The NSA Option. The Minimum/Maximum Integer 32-bit Option and Loop Option. Fixed address operands, added OPERAND_PCREL to operands descriptions.
This commit is contained in:
@@ -273,6 +273,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isimm7_22() const { return isImm(7, 22); }
|
||||
|
||||
/// getStartLoc - Gets location of the first token of this operand
|
||||
SMLoc getStartLoc() const override { return StartLoc; }
|
||||
/// getEndLoc - Gets location of the last token of this operand
|
||||
@@ -538,6 +540,9 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
|
||||
"expected immediate in range [0, 32760], first 3 bits "
|
||||
"should be zero");
|
||||
case Match_Invalidimm7_22:
|
||||
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
|
||||
"expected immediate in range [7, 22]");
|
||||
}
|
||||
|
||||
report_fatal_error("Unknown match type detected!");
|
||||
|
||||
@@ -168,7 +168,8 @@ static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
|
||||
static DecodeStatus decodeCallOperand(MCInst &Inst, uint64_t Imm,
|
||||
int64_t Address, const void *Decoder) {
|
||||
assert(isUInt<18>(Imm) && "Invalid immediate");
|
||||
Inst.addOperand(MCOperand::createImm(SignExtend64<20>(Imm << 2)));
|
||||
Inst.addOperand(
|
||||
MCOperand::createImm(SignExtend64<20>(Imm << 2) + (Address & 0x3)));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
@@ -200,6 +201,16 @@ static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm,
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static DecodeStatus decodeLoopOperand(MCInst &Inst, uint64_t Imm,
|
||||
int64_t Address, const void *Decoder) {
|
||||
|
||||
assert(isUInt<8>(Imm) && "Invalid immediate");
|
||||
if (!tryAddingSymbolicOperand(Imm + 4 + Address, true, Address, 0, 3, Inst,
|
||||
Decoder))
|
||||
Inst.addOperand(MCOperand::createImm(Imm));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm,
|
||||
int64_t Address, const void *Decoder) {
|
||||
|
||||
@@ -326,6 +337,13 @@ static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm,
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static DecodeStatus decodeImm7_22Operand(MCInst &Inst, uint64_t Imm,
|
||||
int64_t Address, const void *Decoder) {
|
||||
assert(isUInt<4>(Imm) && "Invalid immediate");
|
||||
Inst.addOperand(MCOperand::createImm(Imm + 7));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm,
|
||||
int64_t Address, const void *Decoder) {
|
||||
assert(isUInt<12>(Imm) && "Invalid immediate");
|
||||
|
||||
@@ -64,7 +64,8 @@ XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
|
||||
MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
|
||||
{"fixup_xtensa_l32r_16", 8, 16,
|
||||
MCFixupKindInfo::FKF_IsPCRel |
|
||||
MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}};
|
||||
MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
|
||||
{"fixup_xtensa_loop_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}};
|
||||
|
||||
if (Kind < FirstTargetFixupKind)
|
||||
return MCAsmBackend::getFixupKindInfo(Kind);
|
||||
@@ -116,6 +117,11 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
|
||||
if (Value & 0x3)
|
||||
Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned");
|
||||
return (Value & 0xffffc) >> 2;
|
||||
case Xtensa::fixup_xtensa_loop_8:
|
||||
Value -= 4;
|
||||
if (!isUInt<8>(Value))
|
||||
Ctx.reportError(Fixup.getLoc(), "loop fixup value out of range");
|
||||
return (Value & 0xff);
|
||||
case Xtensa::fixup_xtensa_l32r_16:
|
||||
unsigned Offset = Fixup.getOffset();
|
||||
if (Offset & 0x3)
|
||||
|
||||
@@ -22,6 +22,7 @@ enum FixupKind {
|
||||
fixup_xtensa_jump_18,
|
||||
fixup_xtensa_call_18,
|
||||
fixup_xtensa_l32r_16,
|
||||
fixup_xtensa_loop_8,
|
||||
fixup_xtensa_invalid,
|
||||
LastTargetFixupKind,
|
||||
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
|
||||
|
||||
@@ -90,70 +90,103 @@ void XtensaInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
|
||||
printOperand(MI, OpNum + 1, OS);
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printBranchTarget(const MCInst *MI, int OpNum,
|
||||
raw_ostream &OS) {
|
||||
void XtensaInstPrinter::printBranchTarget(const MCInst *MI, uint64_t Address,
|
||||
int OpNum, raw_ostream &O) {
|
||||
const MCOperand &MC = MI->getOperand(OpNum);
|
||||
if (MI->getOperand(OpNum).isImm()) {
|
||||
int64_t Val = MC.getImm() + 4;
|
||||
OS << ". ";
|
||||
if (Val > 0)
|
||||
OS << '+';
|
||||
OS << Val;
|
||||
printPCRelImm(Address, Val, O);
|
||||
} else if (MC.isExpr())
|
||||
MC.getExpr()->print(OS, &MAI);
|
||||
MC.getExpr()->print(O, &MAI);
|
||||
else
|
||||
llvm_unreachable("Invalid operand");
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printJumpTarget(const MCInst *MI, int OpNum,
|
||||
raw_ostream &OS) {
|
||||
void XtensaInstPrinter::printLoopTarget(const MCInst *MI, uint64_t Address,
|
||||
int OpNum, raw_ostream &O) {
|
||||
const MCOperand &MC = MI->getOperand(OpNum);
|
||||
if (MI->getOperand(OpNum).isImm()) {
|
||||
int64_t Val = MC.getImm() + 4;
|
||||
printPCRelImm(Address, Val, O);
|
||||
} else if (MC.isExpr())
|
||||
MC.getExpr()->print(O, &MAI, true);
|
||||
else
|
||||
llvm_unreachable("Invalid operand");
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printJumpTarget(const MCInst *MI, uint64_t Address,
|
||||
int OpNum, raw_ostream &O) {
|
||||
const MCOperand &MC = MI->getOperand(OpNum);
|
||||
if (MC.isImm()) {
|
||||
int64_t Val = MC.getImm() + 4;
|
||||
OS << ". ";
|
||||
if (Val > 0)
|
||||
OS << '+';
|
||||
OS << Val;
|
||||
printPCRelImm(Address, Val, O);
|
||||
} else if (MC.isExpr())
|
||||
MC.getExpr()->print(OS, &MAI);
|
||||
MC.getExpr()->print(O, &MAI);
|
||||
else
|
||||
llvm_unreachable("Invalid operand");
|
||||
;
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printCallOperand(const MCInst *MI, int OpNum,
|
||||
raw_ostream &OS) {
|
||||
void XtensaInstPrinter::printCallOperand(const MCInst *MI, uint64_t Address,
|
||||
int OpNum, raw_ostream &O) {
|
||||
const MCOperand &MC = MI->getOperand(OpNum);
|
||||
if (MC.isImm()) {
|
||||
int64_t Val = MC.getImm() + 4;
|
||||
OS << ". ";
|
||||
if (Val > 0)
|
||||
OS << '+';
|
||||
OS << Val;
|
||||
} else if (MC.isExpr())
|
||||
MC.getExpr()->print(OS, &MAI);
|
||||
else
|
||||
llvm_unreachable("Invalid operand");
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printL32RTarget(const MCInst *MI, int OpNum,
|
||||
raw_ostream &O) {
|
||||
const MCOperand &MC = MI->getOperand(OpNum);
|
||||
if (MC.isImm()) {
|
||||
int64_t Value = MI->getOperand(OpNum).getImm();
|
||||
int64_t InstrOff = Value & 0x3;
|
||||
Value -= InstrOff;
|
||||
assert((Value >= -262144 && Value <= -4) &&
|
||||
"Invalid argument, value must be in ranges [-262144,-4]");
|
||||
Value += ((InstrOff + 0x3) & 0x4) - InstrOff;
|
||||
O << ". ";
|
||||
O << Value;
|
||||
if (PrintBranchImmAsAddress) {
|
||||
uint64_t Target = Address;
|
||||
Target &= ~0x3;
|
||||
Target += Val & (~0x3);
|
||||
O << formatHex(Target);
|
||||
} else {
|
||||
O << ". ";
|
||||
if (Val > 0)
|
||||
O << '+';
|
||||
O << Val;
|
||||
}
|
||||
} else if (MC.isExpr())
|
||||
MC.getExpr()->print(O, &MAI);
|
||||
else
|
||||
llvm_unreachable("Invalid operand");
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printL32RTarget(const MCInst *MI, uint64_t Address,
|
||||
int OpNum, raw_ostream &O) {
|
||||
const MCOperand &MC = MI->getOperand(OpNum);
|
||||
if (MC.isImm()) {
|
||||
int64_t Value = MI->getOperand(OpNum).getImm();
|
||||
if (PrintBranchImmAsAddress) {
|
||||
uint64_t Target = (Address + 0x3) & (~0x3);
|
||||
Value &= ~0x3;
|
||||
Target += Value;
|
||||
O << formatHex(Target);
|
||||
} else {
|
||||
int64_t InstrOff = Value & 0x3;
|
||||
Value -= InstrOff;
|
||||
assert((Value >= -262144 && Value <= -4) &&
|
||||
"Invalid argument, value must be in ranges [-262144,-4]");
|
||||
Value += ((InstrOff + 0x3) & 0x4) - InstrOff;
|
||||
printPCRelImm(Address, Value, O);
|
||||
}
|
||||
} else if (MC.isExpr())
|
||||
MC.getExpr()->print(O, &MAI);
|
||||
else
|
||||
llvm_unreachable("Invalid operand");
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printPCRelImm(uint64_t Address, int64_t Offset,
|
||||
raw_ostream &O) {
|
||||
if (PrintBranchImmAsAddress) {
|
||||
uint64_t Target = Address + Offset;
|
||||
Target &= 0xffffffff;
|
||||
O << formatHex(Target);
|
||||
} else {
|
||||
O << ". ";
|
||||
if (Offset > 0)
|
||||
O << '+';
|
||||
O << Offset;
|
||||
}
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum,
|
||||
raw_ostream &O) {
|
||||
if (MI->getOperand(OpNum).isImm()) {
|
||||
@@ -404,3 +437,14 @@ void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum,
|
||||
} else
|
||||
printOperand(MI, OpNum, O);
|
||||
}
|
||||
|
||||
void XtensaInstPrinter::printImm7_22_AsmOperand(const MCInst *MI, int OpNum,
|
||||
raw_ostream &O) {
|
||||
if (MI->getOperand(OpNum).isImm()) {
|
||||
int64_t Value = MI->getOperand(OpNum).getImm();
|
||||
assert((Value >= 7 && Value <= 22) &&
|
||||
"Invalid argument, value must be in range <7,22>");
|
||||
O << Value;
|
||||
} else
|
||||
printOperand(MI, OpNum, O);
|
||||
}
|
||||
|
||||
@@ -45,10 +45,17 @@ private:
|
||||
// Print various types of operand.
|
||||
void printOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O);
|
||||
void printBranchTarget(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printJumpTarget(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printCallOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printL32RTarget(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printBranchTarget(const MCInst *MI, uint64_t Address, int OpNum,
|
||||
raw_ostream &O);
|
||||
void printLoopTarget(const MCInst *MI, uint64_t Address, int OpNum,
|
||||
raw_ostream &O);
|
||||
void printJumpTarget(const MCInst *MI, uint64_t Address, int OpNum,
|
||||
raw_ostream &O);
|
||||
void printCallOperand(const MCInst *MI, uint64_t Address, int OpNum,
|
||||
raw_ostream &O);
|
||||
void printL32RTarget(const MCInst *MI, uint64_t Address, int OpNum,
|
||||
raw_ostream &O);
|
||||
void printPCRelImm(uint64_t Address, int64_t Offset, raw_ostream &O);
|
||||
|
||||
void printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
@@ -69,6 +76,7 @@ private:
|
||||
void printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printB4constu_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
void printImm7_22_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
||||
@@ -67,6 +67,10 @@ private:
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
uint32_t getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
@@ -134,6 +138,10 @@ private:
|
||||
uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
uint32_t getImm7_22OpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -220,6 +228,23 @@ uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding(
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
XtensaMCCodeEmitter::getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
const MCOperand &MO = MI.getOperand(OpNum);
|
||||
if (MO.isImm())
|
||||
return static_cast<uint32_t>(MO.getImm());
|
||||
|
||||
assert((MO.isExpr()) && "Unexpected operand value!");
|
||||
|
||||
const MCExpr *Expr = MO.getExpr();
|
||||
|
||||
Fixups.push_back(MCFixup::create(
|
||||
0, Expr, MCFixupKind(Xtensa::fixup_xtensa_loop_8), MI.getLoc()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
XtensaMCCodeEmitter::getCallEncoding(const MCInst &MI, unsigned int OpNum,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
@@ -554,4 +579,17 @@ XtensaMCCodeEmitter::getB4constuOpValue(const MCInst &MI, unsigned OpNo,
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
XtensaMCCodeEmitter::getImm7_22OpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
const MCOperand &MO = MI.getOperand(OpNo);
|
||||
uint32_t res = static_cast<uint32_t>(MO.getImm());
|
||||
|
||||
res -= 7;
|
||||
assert(((res & 0xf) == res) && "Unexpected operand value!");
|
||||
|
||||
return res;
|
||||
}
|
||||
#include "XtensaGenMCCodeEmitter.inc"
|
||||
|
||||
@@ -79,6 +79,10 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) {
|
||||
switch (RegNo) {
|
||||
case Xtensa::BREG:
|
||||
return FeatureBits[Xtensa::FeatureBoolean];
|
||||
case Xtensa::LBEG:
|
||||
case Xtensa::LEND:
|
||||
case Xtensa::LCOUNT:
|
||||
return FeatureBits[Xtensa::FeatureLoop];
|
||||
case Xtensa::WINDOWBASE:
|
||||
case Xtensa::WINDOWSTART:
|
||||
return FeatureBits[Xtensa::FeatureWindowed];
|
||||
|
||||
@@ -22,3 +22,28 @@ def FeatureBoolean : SubtargetFeature<"bool", "HasBoolean", "true",
|
||||
"Enable Xtensa Boolean extension">;
|
||||
def HasBoolean : Predicate<"Subtarget->hasBoolean()">,
|
||||
AssemblerPredicate<(all_of FeatureBoolean)>;
|
||||
|
||||
def FeatureLoop : SubtargetFeature<"loop", "HasLoop", "true",
|
||||
"Enable Xtensa Loop extension">;
|
||||
def HasLoop : Predicate<"Subtarget->hasLoop()">,
|
||||
AssemblerPredicate<(all_of FeatureLoop)>;
|
||||
|
||||
def FeatureSEXT : SubtargetFeature<"sext", "HasSEXT", "true",
|
||||
"Enable Xtensa Sign Extend option">;
|
||||
def HasSEXT : Predicate<"Subtarget->hasSEXT()">,
|
||||
AssemblerPredicate<(all_of FeatureSEXT)>;
|
||||
|
||||
def FeatureCLAMPS : SubtargetFeature<"clamps", "HasCLAMPS", "true",
|
||||
"Enable Xtensa CLAMPS option">;
|
||||
def HasCLAMPS : Predicate<"Subtarget->hasCLAMPS()">,
|
||||
AssemblerPredicate<(all_of FeatureCLAMPS)>;
|
||||
|
||||
def FeatureNSA : SubtargetFeature<"nsa", "HasNSA", "true",
|
||||
"Enable Xtensa NSA option">;
|
||||
def HasNSA : Predicate<"Subtarget->hasNSA()">,
|
||||
AssemblerPredicate<(all_of FeatureNSA)>;
|
||||
|
||||
def FeatureMINMAX : SubtargetFeature<"minmax", "HasMINMAX", "true",
|
||||
"Enable Xtensa MINMAX option">;
|
||||
def HasMINMAX : Predicate<"Subtarget->hasMINMAX()">,
|
||||
AssemblerPredicate<(all_of FeatureMINMAX)>;
|
||||
|
||||
@@ -75,8 +75,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
|
||||
setBooleanContents(ZeroOrOneBooleanContent);
|
||||
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, {MVT::i8, MVT::i16},
|
||||
Subtarget.hasSEXT() ? Legal : Expand);
|
||||
|
||||
setOperationAction(ISD::BITCAST, MVT::i32, Expand);
|
||||
setOperationAction(ISD::BITCAST, MVT::f32, Expand);
|
||||
@@ -141,6 +141,9 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
|
||||
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand);
|
||||
setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand);
|
||||
|
||||
setOperationAction({ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}, MVT::i32,
|
||||
Subtarget.hasMINMAX() ? Legal : Expand);
|
||||
|
||||
// Implement custom stack allocations
|
||||
setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom);
|
||||
// Implement custom stack save and restore
|
||||
|
||||
@@ -868,6 +868,94 @@ let Constraints = "$dr = $r,@earlyclobber $dr" in {
|
||||
"movt\t$r, $s, $t", []>, Requires<[HasBoolean]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SEXT Instruction
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def SEXT : RRR_Inst<0x00, 0x03, 0x02, (outs AR:$r), (ins AR:$s, imm7_22:$imm),
|
||||
"sext\t$r, $s, $imm", []>, Requires<[HasSEXT]> {
|
||||
bits<4> imm;
|
||||
|
||||
let t = imm;
|
||||
}
|
||||
|
||||
def : Pat<(i32 (sext_inreg AR:$s, i8)), (SEXT AR:$s, (i32 7))>;
|
||||
def : Pat<(i32 (sext_inreg AR:$s, i16)), (SEXT AR:$s, (i32 15))>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CLAMPS Instruction
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CLAMPS : RRR_Inst<0x00, 0x03, 0x03, (outs AR:$r), (ins AR:$s, imm7_22:$imm),
|
||||
"clamps\t$r, $s, $imm", []>, Requires<[HasCLAMPS]> {
|
||||
bits<4> imm;
|
||||
|
||||
let t = imm;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// NSA Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def NSA : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s),
|
||||
"nsa\t$t, $s", []>, Requires<[HasNSA]> {
|
||||
let r = 0xE;
|
||||
}
|
||||
|
||||
def NSAU : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s),
|
||||
"nsau\t$t, $s",
|
||||
[(set AR:$t, (ctlz AR:$s))]>, Requires<[HasNSA]> {
|
||||
let r = 0xF;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MINMAX Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let Predicates = [HasMINMAX] in {
|
||||
def MIN : ArithLogic_RRR<0x04, 0x03, "min", smin, 1>;
|
||||
def MAX : ArithLogic_RRR<0x05, 0x03, "max", smax, 1>;
|
||||
def MINU : ArithLogic_RRR<0x06, 0x03, "minu", umin, 1>;
|
||||
def MAXU : ArithLogic_RRR<0x07, 0x03, "maxu", umax, 1>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Loop Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def LOOP : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
|
||||
"loop\t$s, $target", []>, Requires<[HasLoop]> {
|
||||
bits<8> target;
|
||||
|
||||
let r = 0x08;
|
||||
let t = 0x07;
|
||||
let imm8 = target;
|
||||
}
|
||||
|
||||
def : InstAlias<"_loop\t$s, $target", (LOOP AR:$s, ltarget:$target)>;
|
||||
|
||||
def LOOPGTZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
|
||||
"loopgtz\t$s, $target", []>, Requires<[HasLoop]> {
|
||||
bits<8> target;
|
||||
|
||||
let r = 0x0A;
|
||||
let t = 0x07;
|
||||
let imm8 = target;
|
||||
}
|
||||
|
||||
def : InstAlias<"_loopgtz\t$s, $target", (LOOPGTZ AR:$s, ltarget:$target)>;
|
||||
|
||||
def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
|
||||
"loopnez\t$s, $target", []>, Requires<[HasLoop]> {
|
||||
bits<8> target;
|
||||
|
||||
let r = 0x09;
|
||||
let t = 0x07;
|
||||
let imm8 = target;
|
||||
}
|
||||
|
||||
def : InstAlias<"_loopnez\t$s, $target", (LOOPNEZ AR:$s, ltarget:$target)>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DSP Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -167,6 +167,14 @@ def b4constu: Immediate<i32,
|
||||
let EncoderMethod = "getB4constuOpValue";
|
||||
let DecoderMethod = "decodeB4constuOperand";
|
||||
}
|
||||
|
||||
// imm7_22 predicate - Immediate in the range [7,22] for sign extend and clamps
|
||||
def Imm7_22_AsmOperand: ImmAsmOperand<"imm7_22">;
|
||||
def imm7_22: Immediate<i32, [{ return Imm >= 7 && Imm <= 22; }], "Imm7_22_AsmOperand"> {
|
||||
let EncoderMethod = "getImm7_22OpValue";
|
||||
let DecoderMethod = "decodeImm7_22Operand";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Memory address operands
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -214,6 +222,7 @@ def pcrel32call : Operand<iPTR> {
|
||||
let EncoderMethod = "getCallEncoding";
|
||||
let DecoderMethod = "decodeCallOperand";
|
||||
let ParserMatchClass = XtensaPCRelTargetAsmOperand;
|
||||
let OperandType = "OPERAND_PCREL";
|
||||
}
|
||||
|
||||
def brtarget : Operand<OtherVT> {
|
||||
@@ -221,6 +230,7 @@ def brtarget : Operand<OtherVT> {
|
||||
let EncoderMethod = "getBranchTargetEncoding";
|
||||
let DecoderMethod = "decodeBranchOperand";
|
||||
let ParserMatchClass = XtensaPCRelTargetAsmOperand;
|
||||
let OperandType = "OPERAND_PCREL";
|
||||
}
|
||||
|
||||
def jumptarget : Operand<OtherVT> {
|
||||
@@ -228,6 +238,15 @@ def jumptarget : Operand<OtherVT> {
|
||||
let EncoderMethod = "getJumpTargetEncoding";
|
||||
let DecoderMethod = "decodeJumpOperand";
|
||||
let ParserMatchClass = XtensaPCRelTargetAsmOperand;
|
||||
let OperandType = "OPERAND_PCREL";
|
||||
}
|
||||
|
||||
def ltarget : Operand<OtherVT> {
|
||||
let PrintMethod = "printLoopTarget";
|
||||
let EncoderMethod = "getLoopTargetEncoding";
|
||||
let DecoderMethod = "decodeLoopOperand";
|
||||
let ParserMatchClass = XtensaPCRelTargetAsmOperand;
|
||||
let OperandType = "OPERAND_PCREL";
|
||||
}
|
||||
|
||||
def L32Rtarget : Operand<i32> {
|
||||
@@ -235,4 +254,5 @@ def L32Rtarget : Operand<i32> {
|
||||
let EncoderMethod = "getL32RTargetEncoding";
|
||||
let DecoderMethod = "decodeL32ROperand";
|
||||
let ParserMatchClass = XtensaPCRelTargetAsmOperand;
|
||||
let OperandType = "OPERAND_PCREL";
|
||||
}
|
||||
|
||||
@@ -73,6 +73,11 @@ class SRReg<bits<8> num, string n, list<string> alt = []> : XtensaReg<n> {
|
||||
let AltNames = alt;
|
||||
}
|
||||
|
||||
// Loop Option Registers
|
||||
def LBEG : SRReg<0, "lbeg", ["LBEG", "0"]>;
|
||||
def LEND : SRReg<1, "lend", ["LEND", "1"]>;
|
||||
def LCOUNT : SRReg<2, "lcount", ["LCOUNT", "2"]>;
|
||||
|
||||
// Shift Amount Register
|
||||
def SAR : SRReg<3, "sar", ["SAR","3"]>;
|
||||
|
||||
@@ -95,8 +100,8 @@ def MR01 : RegisterClass<"Xtensa", [i32], 32, (add M0, M1)>;
|
||||
def MR23 : RegisterClass<"Xtensa", [i32], 32, (add M2, M3)>;
|
||||
def MR : RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>;
|
||||
|
||||
def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR, BREG, MR,
|
||||
WINDOWBASE, WINDOWSTART)>;
|
||||
def SR : RegisterClass<"Xtensa", [i32], 32, (add
|
||||
LBEG, LEND, LCOUNT, SAR, BREG, MR, WINDOWBASE, WINDOWSTART)>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Boolean registers
|
||||
|
||||
@@ -65,13 +65,14 @@ public:
|
||||
}
|
||||
|
||||
bool hasDensity() const { return HasDensity; }
|
||||
|
||||
bool hasMAC16() const { return HasMAC16; }
|
||||
|
||||
bool hasWindowed() const { return HasWindowed; }
|
||||
|
||||
bool hasBoolean() const { return HasBoolean; }
|
||||
|
||||
bool hasLoop() const { return HasLoop; }
|
||||
bool hasSEXT() const { return HasSEXT; }
|
||||
bool hasCLAMPS() const { return HasCLAMPS; }
|
||||
bool hasNSA() const { return HasNSA; }
|
||||
bool hasMINMAX() const { return HasMINMAX; }
|
||||
bool isWindowedABI() const { return hasWindowed(); }
|
||||
|
||||
// Automatically generated by tblgen.
|
||||
|
||||
52
llvm/test/CodeGen/Xtensa/minmax.ll
Normal file
52
llvm/test/CodeGen/Xtensa/minmax.ll
Normal file
@@ -0,0 +1,52 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
|
||||
; RUN: llc -mtriple=xtensa --mattr=+minmax -verify-machineinstrs < %s \
|
||||
; RUN: | FileCheck -check-prefix=XTENSA %s
|
||||
|
||||
declare i32 @llvm.smin.i32(i32, i32)
|
||||
declare i32 @llvm.umin.i32(i32, i32)
|
||||
declare i32 @llvm.smax.i32(i32, i32)
|
||||
declare i32 @llvm.umax.i32(i32, i32)
|
||||
|
||||
define i32 @test_smin(i32 %x, i32 %y) {
|
||||
; XTENSA-LABEL: test_smin:
|
||||
; XTENSA: .cfi_startproc
|
||||
; XTENSA-NEXT: # %bb.0: # %entry
|
||||
; XTENSA-NEXT: min a2, a2, a3
|
||||
; XTENSA-NEXT: ret
|
||||
entry:
|
||||
%res = call i32 @llvm.smin.i32(i32 %x, i32 %y)
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
define i32 @test_umin(i32 %x, i32 %y) {
|
||||
; XTENSA-LABEL: test_umin:
|
||||
; XTENSA: .cfi_startproc
|
||||
; XTENSA-NEXT: # %bb.0: # %entry
|
||||
; XTENSA-NEXT: minu a2, a2, a3
|
||||
; XTENSA-NEXT: ret
|
||||
entry:
|
||||
%res = call i32 @llvm.umin.i32(i32 %x, i32 %y)
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
define i32 @test_smax(i32 %x, i32 %y) {
|
||||
; XTENSA-LABEL: test_smax:
|
||||
; XTENSA: .cfi_startproc
|
||||
; XTENSA-NEXT: # %bb.0: # %entry
|
||||
; XTENSA-NEXT: max a2, a2, a3
|
||||
; XTENSA-NEXT: ret
|
||||
entry:
|
||||
%res = call i32 @llvm.smax.i32(i32 %x, i32 %y)
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
define i32 @test_umax(i32 %x, i32 %y) {
|
||||
; XTENSA-LABEL: test_umax:
|
||||
; XTENSA: .cfi_startproc
|
||||
; XTENSA-NEXT: # %bb.0: # %entry
|
||||
; XTENSA-NEXT: maxu a2, a2, a3
|
||||
; XTENSA-NEXT: ret
|
||||
entry:
|
||||
%res = call i32 @llvm.umax.i32(i32 %x, i32 %y)
|
||||
ret i32 %res
|
||||
}
|
||||
23
llvm/test/CodeGen/Xtensa/sext.ll
Normal file
23
llvm/test/CodeGen/Xtensa/sext.ll
Normal file
@@ -0,0 +1,23 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
|
||||
; RUN: llc -mtriple=xtensa --mattr=+sext -verify-machineinstrs < %s \
|
||||
; RUN: | FileCheck -check-prefix=XTENSA %s
|
||||
|
||||
define i32 @sext_i8(i8 %a) {
|
||||
; XTENSA-LABEL: sext_i8:
|
||||
; XTENSA: .cfi_startproc
|
||||
; XTENSA-NEXT: # %bb.0:
|
||||
; XTENSA-NEXT: sext a2, a2, 7
|
||||
; XTENSA-NEXT: ret
|
||||
%res = sext i8 %a to i32
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
define i32 @sext_i16(i16 %a) {
|
||||
; XTENSA-LABEL: sext_i16:
|
||||
; XTENSA: .cfi_startproc
|
||||
; XTENSA-NEXT: # %bb.0:
|
||||
; XTENSA-NEXT: sext a2, a2, 15
|
||||
; XTENSA-NEXT: ret
|
||||
%res = sext i16 %a to i32
|
||||
ret i32 %res
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# RUN: not llvm-mc -triple xtensa -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s
|
||||
# RUN: not llvm-mc -triple xtensa --mattr=+loop -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
.align 4
|
||||
|
||||
@@ -8,6 +8,8 @@ LBL0:
|
||||
|
||||
call0 LBL0 # CHECK: :[[@LINE]]:3: error: fixup value must be 4-byte aligned
|
||||
|
||||
loop a3, LBL0 # CHECK: :[[@LINE]]:3: error: loop fixup value out of range
|
||||
|
||||
.space 1<<8
|
||||
LBL1:
|
||||
.space 1<<12
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \
|
||||
# RUN: llvm-mc -triple xtensa --mattr=+density,loop < %s -show-encoding \
|
||||
# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s
|
||||
# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \
|
||||
# RUN: | llvm-objdump --mattr=+density -d - | FileCheck -check-prefix=CHECK-INSTR %s
|
||||
# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density,loop < %s \
|
||||
# RUN: | llvm-objdump --mattr=+density,loop -d - | FileCheck -check-prefix=CHECK-INSTR %s
|
||||
|
||||
|
||||
# Checks that fixups that can be resolved within the same object file are
|
||||
@@ -13,43 +13,43 @@ LBL0:
|
||||
|
||||
beqz.n a2, LBL1
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_6
|
||||
# CHECK-INSTR: beqz.n a2, . +29
|
||||
# CHECK-INSTR: beqz.n a2, 0x29
|
||||
|
||||
beq a0, a1, LBL0
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_8
|
||||
# CHECK-INSTR: beq a0, a1, . -14
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind:
|
||||
# CHECK-INSTR: beq a0, a1, 0x0
|
||||
|
||||
beq a0, a1, LBL1
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_8
|
||||
# CHECK-INSTR: beq a0, a1, . +24
|
||||
# CHECK-INSTR: beq a0, a1, 0x29
|
||||
|
||||
beqz a2, LBL0
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_12
|
||||
# CHECK-INSTR: beqz a2, . -20
|
||||
# CHECK-INSTR: beqz a2, 0x0
|
||||
|
||||
beqz a2, LBL1
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_12
|
||||
# CHECK-INSTR: beqz a2, . +18
|
||||
# CHECK-INSTR: beqz a2, 0x29
|
||||
|
||||
call0 LBL0
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_call_18
|
||||
# CHECK-INSTR: call0 . -24
|
||||
# CHECK-INSTR: call0 0x0
|
||||
|
||||
call0 LBL2
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_call_18
|
||||
# CHECK-INSTR: call0 . +2068
|
||||
# CHECK-INSTR: call0 0x830
|
||||
|
||||
j LBL0
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_jump_18
|
||||
# CHECK-INSTR: j . -32
|
||||
# CHECK-INSTR: j 0x0
|
||||
|
||||
j LBL2
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_jump_18
|
||||
# CHECK-INSTR: j . +2061
|
||||
# CHECK-INSTR: j 0x830
|
||||
|
||||
l32r a1, LBL0
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_l32r_16
|
||||
# CHECK-INSTR: l32r a1, . -38
|
||||
# CHECK-INSTR: l32r a1, 0x0
|
||||
|
||||
LBL1:
|
||||
|
||||
@@ -57,3 +57,11 @@ LBL1:
|
||||
|
||||
.align 4
|
||||
LBL2:
|
||||
|
||||
loop a3, LBL3
|
||||
# CHECK-FIXUP: fixup A - offset: 0, value: LBL3, kind: fixup_xtensa_loop_8
|
||||
# CHECK-INSTR: loop a3, 0x8fb
|
||||
|
||||
.fill 200
|
||||
|
||||
LBL3:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \
|
||||
# RUN: llvm-mc -triple xtensa --mattr=+density,loop < %s -show-encoding \
|
||||
# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
|
||||
# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \
|
||||
# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density,loop < %s \
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s
|
||||
|
||||
# Check prefixes:
|
||||
@@ -183,3 +183,12 @@ l32r a6, func
|
||||
# RELOC: R_XTENSA_SLOT0_OP
|
||||
# INSTR: l32r a6, func
|
||||
# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_l32r_16
|
||||
|
||||
loop a3, LBL
|
||||
# RELOC: R_XTENSA_SLOT0_OP
|
||||
# INSTR: loop a3, LBL
|
||||
# FIXUP: fixup A - offset: 0, value: LBL, kind: fixup_xtensa_loop_8
|
||||
|
||||
.fill 200
|
||||
|
||||
LBL:
|
||||
|
||||
35
llvm/test/MC/Xtensa/loop.s
Normal file
35
llvm/test/MC/Xtensa/loop.s
Normal file
@@ -0,0 +1,35 @@
|
||||
# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+loop \
|
||||
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
|
||||
|
||||
.align 4
|
||||
|
||||
# Instruction format BRI8
|
||||
# CHECK-INST: loop a3, LBL
|
||||
# CHECK: encoding: [0x76,0x83,A]
|
||||
loop a3, LBL
|
||||
|
||||
# Instruction format BRI8
|
||||
# CHECK-INST: loopnez a3, LBL
|
||||
# CHECK: encoding: [0x76,0x93,A]
|
||||
loopnez a3, LBL
|
||||
|
||||
# Instruction format BRI8
|
||||
# CHECK-INST: loopgtz a3, LBL
|
||||
# CHECK: encoding: [0x76,0xa3,A]
|
||||
loopgtz a3, LBL
|
||||
|
||||
# CHECK-INST: xsr a3, lbeg
|
||||
# CHECK: # encoding: [0x30,0x00,0x61]
|
||||
xsr a3, lbeg
|
||||
|
||||
# CHECK-INST: xsr a3, lend
|
||||
# CHECK: # encoding: [0x30,0x01,0x61]
|
||||
xsr a3, lend
|
||||
|
||||
# CHECK-INST: xsr a3, lcount
|
||||
# CHECK: # encoding: [0x30,0x02,0x61]
|
||||
xsr a3, lcount
|
||||
|
||||
.fill 200
|
||||
|
||||
LBL:
|
||||
24
llvm/test/MC/Xtensa/minmax.s
Normal file
24
llvm/test/MC/Xtensa/minmax.s
Normal file
@@ -0,0 +1,24 @@
|
||||
# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+minmax \
|
||||
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
|
||||
|
||||
.align 4
|
||||
|
||||
# Instruction format RRR
|
||||
# CHECK-INST: max a3, a4, a5
|
||||
# CHECK: encoding: [0x50,0x34,0x53]
|
||||
max a3, a4, a5
|
||||
|
||||
# Instruction format RRR
|
||||
# CHECK-INST: maxu a3, a4, a5
|
||||
# CHECK: encoding: [0x50,0x34,0x73]
|
||||
maxu a3, a4, a5
|
||||
|
||||
# Instruction format RRR
|
||||
# CHECK-INST: min a3, a4, a5
|
||||
# CHECK: encoding: [0x50,0x34,0x43]
|
||||
min a3, a4, a5
|
||||
|
||||
# Instruction format RRR
|
||||
# CHECK-INST: minu a3, a4, a5
|
||||
# CHECK: encoding: [0x50,0x34,0x63]
|
||||
minu a3, a4, a5
|
||||
14
llvm/test/MC/Xtensa/nsau.s
Normal file
14
llvm/test/MC/Xtensa/nsau.s
Normal file
@@ -0,0 +1,14 @@
|
||||
# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+nsa \
|
||||
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
|
||||
|
||||
.align 4
|
||||
|
||||
# Instruction format RRR
|
||||
# CHECK-INST: nsa a3, a4
|
||||
# CHECK: encoding: [0x30,0xe4,0x40]
|
||||
nsa a3, a4
|
||||
|
||||
# Instruction format RRR
|
||||
# CHECK-INST: nsau a3, a4
|
||||
# CHECK: encoding: [0x30,0xf4,0x40]
|
||||
nsau a3, a4
|
||||
9
llvm/test/MC/Xtensa/sext.s
Normal file
9
llvm/test/MC/Xtensa/sext.s
Normal file
@@ -0,0 +1,9 @@
|
||||
# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+sext \
|
||||
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
|
||||
|
||||
.align 4
|
||||
|
||||
# Instruction format RRR
|
||||
# CHECK-INST: sext a3, a4, 7
|
||||
# CHECK: encoding: [0x00,0x34,0x23]
|
||||
sext a3, a4, 7
|
||||
9
llvm/test/MC/Xtensa/sext_invalid.s
Normal file
9
llvm/test/MC/Xtensa/sext_invalid.s
Normal file
@@ -0,0 +1,9 @@
|
||||
# RUN: not llvm-mc -triple xtensa --mattr=+sext %s 2>&1 | FileCheck %s
|
||||
|
||||
.align 4
|
||||
|
||||
# Out of range immediates
|
||||
|
||||
# imm7_22
|
||||
sext a3, a4, 6
|
||||
# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [7, 22]
|
||||
Reference in New Issue
Block a user