-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
[Xtensa] Implement Code Density Option. #119639
Conversation
The Code Density option adds 16-bit encoding for frequently used instructions.
@llvm/pr-subscribers-mc Author: Andrei Safronov (andreisfr) ChangesThe Code Density option adds 16-bit encoding for frequently used instructions. Patch is 25.73 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/119639.diff 14 Files Affected:
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 83b1cfca529bf3..f1d12a51afb485 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -193,6 +193,10 @@ struct XtensaOperand : public MCParsedAsmOperand {
bool isImm1_16() const { return isImm(1, 16); }
+ bool isImm1n_15() const { return (isImm(1, 15) || isImm(-1, -1)); }
+
+ bool isImm32n_95() const { return isImm(-32, 95); }
+
bool isB4const() const {
if (Kind != Immediate)
return false;
@@ -480,6 +484,12 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidImm1_16:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected immediate in range [1, 16]");
+ case Match_InvalidImm1n_15:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "expected immediate in range [-1, 15] except 0");
+ case Match_InvalidImm32n_95:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "expected immediate in range [-32, 95] except 0");
case Match_InvalidShimm1_31:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected immediate in range [1, 31]");
diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
index 2d36b94dd40c77..8bff0f6660b52d 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -38,9 +38,7 @@ class XtensaDisassembler : public MCDisassembler {
XtensaDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool isLE)
: MCDisassembler(STI, Ctx), IsLittleEndian(isLE) {}
- bool hasDensity() const {
- return STI.hasFeature(Xtensa::FeatureDensity);
- }
+ bool hasDensity() const { return STI.hasFeature(Xtensa::FeatureDensity); }
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
@@ -99,8 +97,8 @@ static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
uint64_t InstSize, MCInst &MI,
const void *Decoder) {
const MCDisassembler *Dis = static_cast<const MCDisassembler *>(Decoder);
- return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch, Offset, /*OpSize=*/0,
- InstSize);
+ return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch, Offset,
+ /*OpSize=*/0, InstSize);
}
static DecodeStatus decodeCallOperand(MCInst &Inst, uint64_t Imm,
@@ -190,6 +188,28 @@ static DecodeStatus decodeImm1_16Operand(MCInst &Inst, uint64_t Imm,
return MCDisassembler::Success;
}
+static DecodeStatus decodeImm1n_15Operand(MCInst &Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder) {
+ assert(isUInt<4>(Imm) && "Invalid immediate");
+ if (!Imm)
+ Inst.addOperand(MCOperand::createImm(-1));
+ else
+ Inst.addOperand(MCOperand::createImm(Imm));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeImm32n_95Operand(MCInst &Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder) {
+ assert(isUInt<7>(Imm) && "Invalid immediate");
+ if ((Imm & 0x60) == 0x60)
+ Inst.addOperand(MCOperand::createImm((~0x1f) | Imm));
+ else
+ Inst.addOperand(MCOperand::createImm(Imm));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm,
int64_t Address,
const void *Decoder) {
@@ -243,9 +263,37 @@ static DecodeStatus decodeMem32Operand(MCInst &Inst, uint64_t Imm,
return MCDisassembler::Success;
}
+static DecodeStatus decodeMem32nOperand(MCInst &Inst, uint64_t Imm,
+ int64_t Address, const void *Decoder) {
+ assert(isUInt<8>(Imm) && "Invalid immediate");
+ DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder);
+ Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3c));
+ return MCDisassembler::Success;
+}
+
+/// Read two bytes from the ArrayRef and return 16 bit data sorted
+/// according to the given endianness.
+static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint64_t &Insn,
+ bool IsLittleEndian) {
+ // We want to read exactly 2 Bytes of data.
+ if (Bytes.size() < 2) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ if (!IsLittleEndian) {
+ llvm_unreachable("Big-endian mode currently is not supported!");
+ } else {
+ Insn = (Bytes[1] << 8) | Bytes[0];
+ }
+
+ return MCDisassembler::Success;
+}
+
/// Read three bytes from the ArrayRef and return 24 bit data
static DecodeStatus readInstruction24(ArrayRef<uint8_t> Bytes, uint64_t Address,
- uint64_t &Size, uint32_t &Insn,
+ uint64_t &Size, uint64_t &Insn,
bool IsLittleEndian) {
// We want to read exactly 3 Bytes of data.
if (Bytes.size() < 3) {
@@ -259,7 +307,6 @@ static DecodeStatus readInstruction24(ArrayRef<uint8_t> Bytes, uint64_t Address,
Insn = (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0);
}
- Size = 3;
return MCDisassembler::Success;
}
@@ -269,13 +316,31 @@ DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address,
raw_ostream &CS) const {
- uint32_t Insn;
+ uint64_t Insn;
DecodeStatus Result;
+ // Parse 16-bit instructions
+ if (hasDensity()) {
+ Result = readInstruction16(Bytes, Address, Size, Insn, IsLittleEndian);
+ if (Result == MCDisassembler::Fail)
+ return MCDisassembler::Fail;
+ LLVM_DEBUG(dbgs() << "Trying Xtensa 16-bit instruction table :\n");
+ Result = decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI);
+ if (Result != MCDisassembler::Fail) {
+ Size = 2;
+ return Result;
+ }
+ }
+
+ // Parse Core 24-bit instructions
Result = readInstruction24(Bytes, Address, Size, Insn, IsLittleEndian);
if (Result == MCDisassembler::Fail)
return MCDisassembler::Fail;
LLVM_DEBUG(dbgs() << "Trying Xtensa 24-bit instruction table :\n");
Result = decodeInstruction(DecoderTable24, MI, Insn, Address, this, STI);
+ if (Result != MCDisassembler::Fail) {
+ Size = 3;
+ return Result;
+ }
return Result;
}
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
index a296a22247a5c0..c1fb46e69e6fbe 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
@@ -88,8 +88,10 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case FK_Data_8:
return Value;
case Xtensa::fixup_xtensa_branch_6: {
+ if (!Value)
+ return 0;
Value -= 4;
- if (!isInt<6>(Value))
+ if (!isUInt<6>(Value))
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
unsigned Hi2 = (Value >> 4) & 0x3;
unsigned Lo4 = Value & 0xf;
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
index e04d7bd211216f..df8a0854f06f41 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
@@ -242,6 +242,28 @@ void XtensaInstPrinter::printImm1_16_AsmOperand(const MCInst *MI, int OpNum,
printOperand(MI, OpNum, O);
}
+void XtensaInstPrinter::printImm1n_15_AsmOperand(const MCInst *MI, int OpNum,
+ raw_ostream &O) {
+ if (MI->getOperand(OpNum).isImm()) {
+ int64_t Value = MI->getOperand(OpNum).getImm();
+ assert((Value >= -1 && (Value != 0) && Value <= 15) &&
+ "Invalid argument, value must be in ranges <-1,-1> or <1,15>");
+ O << Value;
+ } else
+ printOperand(MI, OpNum, O);
+}
+
+void XtensaInstPrinter::printImm32n_95_AsmOperand(const MCInst *MI, int OpNum,
+ raw_ostream &O) {
+ if (MI->getOperand(OpNum).isImm()) {
+ int64_t Value = MI->getOperand(OpNum).getImm();
+ assert((Value >= -32 && Value <= 95) &&
+ "Invalid argument, value must be in ranges <-32,95>");
+ O << Value;
+ } else
+ printOperand(MI, OpNum, O);
+}
+
void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum,
raw_ostream &O) {
if (MI->getOperand(OpNum).isImm()) {
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
index f56d5d1458dc11..e5bc67869e103d 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
@@ -58,6 +58,8 @@ class XtensaInstPrinter : public MCInstPrinter {
void printUimm5_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printShimm1_31_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printImm1_16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+ void printImm1n_15_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+ void printImm32n_95_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
index 1afdbb38f9571a..51d4b8a9cc5fc5 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
@@ -103,6 +103,14 @@ class XtensaMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ uint32_t getImm1n_15OpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ uint32_t getImm32n_95OpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -188,6 +196,11 @@ uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding(
Fixups.push_back(MCFixup::create(
0, Expr, MCFixupKind(Xtensa::fixup_xtensa_branch_12), MI.getLoc()));
return 0;
+ case Xtensa::BEQZ_N:
+ case Xtensa::BNEZ_N:
+ Fixups.push_back(MCFixup::create(
+ 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_branch_6), MI.getLoc()));
+ return 0;
default:
Fixups.push_back(MCFixup::create(
0, Expr, MCFixupKind(Xtensa::fixup_xtensa_branch_8), MI.getLoc()));
@@ -255,14 +268,24 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo,
break;
case Xtensa::S32I:
case Xtensa::L32I:
+ case Xtensa::S32I_N:
+ case Xtensa::L32I_N:
if (Res & 0x3) {
report_fatal_error("Unexpected operand value!");
}
Res >>= 2;
break;
}
-
- assert((isUInt<8>(Res)) && "Unexpected operand value!");
+
+ switch (MI.getOpcode()) {
+ case Xtensa::S32I_N:
+ case Xtensa::L32I_N:
+ assert((isUInt<4>(Res)) && "Unexpected operand value!");
+ break;
+ default:
+ assert((isUInt<8>(Res)) && "Unexpected operand value!");
+ break;
+ }
uint32_t OffBits = Res << 4;
uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI);
@@ -354,6 +377,34 @@ XtensaMCCodeEmitter::getImm1_16OpValue(const MCInst &MI, unsigned OpNo,
return (Res - 1);
}
+uint32_t
+XtensaMCCodeEmitter::getImm1n_15OpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ int32_t Res = static_cast<int32_t>(MO.getImm());
+
+ assert(((Res >= -1) && (Res <= 15) && (Res != 0)) &&
+ "Unexpected operand value!");
+
+ if (Res < 0)
+ Res = 0;
+
+ return Res;
+}
+
+uint32_t
+XtensaMCCodeEmitter::getImm32n_95OpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ int32_t Res = static_cast<int32_t>(MO.getImm());
+
+ assert(((Res >= -32) && (Res <= 95)) && "Unexpected operand value!");
+
+ return Res;
+}
+
uint32_t
XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
index af1110487b4274..ef14095d18efbf 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
@@ -27,10 +27,17 @@ using namespace llvm;
namespace {
class XtensaDAGToDAGISel : public SelectionDAGISel {
+ const XtensaSubtarget *Subtarget = nullptr;
+
public:
- XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel)
+ explicit XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel)
: SelectionDAGISel(TM, OptLevel) {}
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ Subtarget = &MF.getSubtarget<XtensaSubtarget>();
+ return SelectionDAGISel::runOnMachineFunction(MF);
+ }
+
void Select(SDNode *Node) override;
bool SelectInlineAsmMemoryOperand(const SDValue &Op,
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 7e43c03ee72cac..6dfda02b7622b8 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -506,7 +506,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
SDValue Memcpy = DAG.getMemcpy(
Chain, DL, Address, ArgValue, SizeNode, Flags.getNonZeroByValAlign(),
/*isVolatile=*/false, /*AlwaysInline=*/false,
- /*CI=*/nullptr, std::nullopt, MachinePointerInfo(), MachinePointerInfo());
+ /*CI=*/nullptr, std::nullopt, MachinePointerInfo(),
+ MachinePointerInfo());
MemOpChains.push_back(Memcpy);
} else {
assert(VA.isMemLoc() && "Argument not register or memory");
@@ -1319,10 +1320,12 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter(
case Xtensa::S8I:
case Xtensa::S16I:
case Xtensa::S32I:
+ case Xtensa::S32I_N:
case Xtensa::L8UI:
case Xtensa::L16SI:
case Xtensa::L16UI:
- case Xtensa::L32I: {
+ case Xtensa::L32I:
+ case Xtensa::L32I_N: {
// 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/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index e21de0448aa5ae..699d0d6cf80445 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -577,3 +577,104 @@ let usesCustomInserter = 1 in {
"!select $dst, $lhs, $rhs, $t, $f, $cond",
[(set i32:$dst, (Xtensa_select_cc i32:$lhs, i32:$rhs, i32:$t, i32:$f, imm:$cond))]>;
}
+
+//===----------------------------------------------------------------------===//
+// Code Density instructions
+//===----------------------------------------------------------------------===//
+
+class ArithLogic_RRRN<bits<4> oper0, string instrAsm,
+ SDPatternOperator opNode, bit isComm = 0>
+ : RRRN_Inst<oper0, (outs AR:$r), (ins AR:$s, AR:$t),
+ instrAsm#"\t$r, $s, $t",
+ [(set AR:$r, (opNode AR:$s, AR:$t))]>, Requires<[HasDensity]> {
+ let isCommutable = isComm;
+ let isReMaterializable = 0;
+}
+
+def ADD_N : ArithLogic_RRRN<0x0a, "add.n", add, 1>;
+
+def ADDI_N : RRRN_Inst<0x0B, (outs AR:$r), (ins AR:$s, imm1n_15:$imm),
+ "addi.n\t$r, $s, $imm",
+ [(set AR:$r, (add AR:$s, imm1n_15:$imm))]>, Requires<[HasDensity]> {
+ bits<4> imm;
+
+ let t = imm;
+}
+
+// Conditional branch instructions.
+let isBranch = 1, isTerminator = 1 in {
+ def BEQZ_N : RI6_Inst<0xC, 0x1, 0x0, (outs), (ins AR:$s, brtarget:$target),
+ "beqz.n\t$s, $target", []>, Requires<[HasDensity]> {
+ bits<6> target;
+
+ let imm6 = target;
+ }
+
+ def BNEZ_N : RI6_Inst<0xC, 0x1, 0x1, (outs), (ins AR:$s, brtarget:$target),
+ "bnez.n\t$s, $target", []>, Requires<[HasDensity]> {
+ bits<6> target;
+
+ let imm6 = target;
+ }
+}
+
+def ILL_N : RRRN_Inst<0x0D, (outs), (ins),
+ "ill.n", []>, Requires<[HasDensity]> {
+ let r = 0xF;
+ let s = 0x0;
+ let t = 0x6;
+}
+
+def MOV_N : RRRN_Inst<0x0D, (outs AR:$t), (ins AR:$s),
+ "mov.n\t$t, $s", []>, Requires<[HasDensity]> {
+ let r = 0;
+}
+
+def : InstAlias<"mov\t $t, $s", (OR AR:$t, AR:$s, AR:$s)>;
+
+def MOVI_N : RI7_Inst<0xc, 0x0, (outs AR:$s), (ins imm32n_95:$imm7),
+ "movi.n\t$s, $imm7",
+ [(set AR:$s, imm32n_95:$imm7)]>, Requires<[HasDensity]>;
+
+def : InstAlias<"_movi.n\t$s, $imm7", (MOVI_N AR:$s, imm32n_95:$imm7)>;
+
+def NOP_N : RRRN_Inst<0x0D, (outs), (ins),
+ "nop.n", []>, Requires<[HasDensity]> {
+ let r = 0xF;
+ let s = 0x0;
+ let t = 0x3;
+}
+
+// Load instruction
+let mayLoad = 1, usesCustomInserter = 1 in {
+ def L32I_N : RRRN_Inst<0x8, (outs AR:$t), (ins mem32n:$addr),
+ "l32i.n\t$t, $addr", []>, Requires<[HasDensity]> {
+ bits<8> addr;
+
+ let r{3-0} = addr{7-4};
+ let s{3-0} = addr{3-0};
+ }
+}
+
+// Store instruction
+let mayStore = 1, usesCustomInserter = 1 in {
+ def S32I_N : RRRN_Inst<0x9, (outs), (ins AR:$t, mem32n:$addr),
+ "s32i.n\t$t, $addr", []>, Requires<[HasDensity]> {
+ bits<8> addr;
+
+ let r{3-0} = addr{7-4};
+ let s{3-0} = addr{3-0};
+ }
+}
+
+//Return instruction
+let isReturn = 1, isTerminator = 1,
+ isBarrier = 1, Uses = [A0] in {
+ def RET_N : RRRN_Inst<0x0D, (outs), (ins),
+ "ret.n", [(Xtensa_ret)]>,
+ Requires<[HasDensity]> {
+ let r = 0x0F;
+ let s = 0;
+ let t = 0;
+ }
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td
index f41081f9bf2f96..aa72fa0a56a6f5 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperands.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperands.td
@@ -72,6 +72,20 @@ def imm1_16 : Immediate<i32, [{ return Imm >= 1 && Imm <= 16; }], "Imm1_16_AsmOp
let DecoderMethod = "decodeImm1_16Operand";
}
+// imm1n_15 predicate - Immediate in the range [-1,15], except 0
+def Imm1n_15_AsmOperand: ImmAsmOperand<"Imm1n_15">;
+def imm1n_15: Immediate<i32, [{ return Imm >= -1 && Imm <= 15 && Imm != 0; }], "Imm1n_15_AsmOperand"> {
+ let EncoderMethod = "getImm1n_15OpValue";
+ let DecoderMethod = "decodeImm1n_15Operand";
+}
+
+// imm32n_95 predicate - Immediate in the range [-32,95]
+def Imm32n_95_AsmOperand: ImmAsmOperand<"Imm32n_95">;
+def imm32n_95: Immediate<i32, [{ return Imm >= -32 && Imm <= 95; }], "Imm32n_95_AsmOperand"> {
+ let EncoderMethod = "g...
[truncated]
|
Unrelated but can you open a PR to add the xtensa paths to .github/new-prs-labeler.yml |
@@ -193,6 +193,10 @@ struct XtensaOperand : public MCParsedAsmOperand { | |||
|
|||
bool isImm1_16() const { return isImm(1, 16); } | |||
|
|||
bool isImm1n_15() const { return (isImm(1, 15) || isImm(-1, -1)); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra parens. Not sure I understand the what || isImm(-1, -1) is doing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for review. I removed parens and added a comment.
@@ -0,0 +1,17 @@ | |||
# RUN: not llvm-mc -triple xtensa --mattr=+density %s 2>&1 | FileCheck %s | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the point of having an "Options" subdirectory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry, you mean that we don't need to create specific directory for Xtensa architecture options(extensions) tests in "../MC/Xtensa/"? Or use other directory structure, for example for each option(extension) create correspondence directory "../MC/Xtensa/CodeDensity"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean just leave it in test/MC/Xtensa. I also wouldn't really call a subtarget feature an option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved tests to MC/Xtensa from Option directory.
@@ -190,6 +188,28 @@ static DecodeStatus decodeImm1_16Operand(MCInst &Inst, uint64_t Imm, | |||
return MCDisassembler::Success; | |||
} | |||
|
|||
static DecodeStatus decodeImm1n_15Operand(MCInst &Inst, uint64_t Imm, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing disassembler tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added disassembler test.
LLVM_DEBUG(dbgs() << "Trying Xtensa 16-bit instruction table :\n"); | ||
Result = decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the disassembler test, make sure to test mismatches (e.g. !hasDensity and there are encoded values using the extension)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean try to disassemble 16-bit code with the hasDensity option disabled and check that it produces erroneous decoding?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should not crash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this verification to the disassembler test.
"expected immediate in range [-1, 15] except 0"); | ||
case Match_InvalidImm32n_95: | ||
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), | ||
"expected immediate in range [-32, 95] except 0"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isImm1n_15
checks -1..15, except 0 and the error message is reflecting this.isImm32n_95
, as implemented, includes 0, but the error here says that it does not.
Either the implementation, or the error message seems to be incorrect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for comments. I fixed error message.
# Out of range immediates | ||
|
||
# imm1n_15 | ||
addi.n a2, a3, 20 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you please add a test case for imm=0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added test case.
# Instruction format RRRN | ||
# CHECK-INST: addi.n a2, a3, 3 | ||
# CHECK: encoding: [0x3b,0x23] | ||
addi.n a2, a3, 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you please add a test case for imm=-1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added test case.
} | ||
|
||
if (!IsLittleEndian) { | ||
llvm_unreachable("Big-endian mode currently is not supported!"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is reachable with some triple option it shouldn't be an assert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed "llvm_unreachable" in readInstruction16 to "report_fatal_error", like it is done in readInstruction24.
Hypothetically, the Xtensa architecture could have a big endian implementation, but in practice it is hard to find such hardware (at least I don't see such an example). So we don't expect such a triple variant at this time.
Thank you for advice. I created PR #120133 |
Link to tracking issue espressif#4 |
The Code Density option adds 16-bit encoding for frequently used instructions.
|
||
0x4a 0x23 | ||
# CHECK-DENSITY: add.n a2, a3, a4 | ||
# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test fails at HEAD. It's recommended to use [0x4a 0x23]
so that llvm-mc will disassemble the bytes as a whole and not fallback (skip one byte and continue disassembling), leading to weird diagnostics.
You could utilize the recent --hex
so that you can do [4a23]
For llvm-mc, s/< %s/%s/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MaskRay, thank you very much for comment, I'm sorry, I tried to reproduce test fail using "check-llvm" but without success, may I ask you for advice about how to reproduce the problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can reproduce with just ninja check-llvm-mc-disassembler-xtensa
. Is the test skipped in your build?
You could change llvm/test/MC/Disassembler/Xtensa/lit.local.cfg
locally to see whether Xtensa is in config.root.targets
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry, that was some misunderstanding on my part. I created PR #121073, could you PTAL?
@@ -0,0 +1,64 @@ | |||
# RUN: llvm-mc -triple=xtensa -mattr=+density -disassemble < %s | FileCheck -check-prefixes=CHECK-DENSITY %s | |||
# RUN: llvm-mc -triple=xtensa -disassemble %s &> %t | |||
# RUN: FileCheck -check-prefixes=CHECK-CORE < %t %s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--implicit-check-not=warning: is useful to ensure that there are no additional warnings
The Code Density option adds 16-bit encoding for frequently used instructions.