[llvm] c6967ef - [Xtensa] Implement Code Density Option. (#119639)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 18 04:37:12 PST 2024
Author: Andrei Safronov
Date: 2024-12-18T15:37:08+03:00
New Revision: c6967efe780d6cc5d70fc8cadbd227353b6768f1
URL: https://github.com/llvm/llvm-project/commit/c6967efe780d6cc5d70fc8cadbd227353b6768f1
DIFF: https://github.com/llvm/llvm-project/commit/c6967efe780d6cc5d70fc8cadbd227353b6768f1.diff
LOG: [Xtensa] Implement Code Density Option. (#119639)
The Code Density option adds 16-bit encoding for frequently used
instructions.
Added:
llvm/test/MC/Disassembler/Xtensa/code_density.txt
llvm/test/MC/Disassembler/Xtensa/lit.local.cfg
llvm/test/MC/Xtensa/code_density-invalid.s
llvm/test/MC/Xtensa/code_density.s
Modified:
llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
llvm/lib/Target/Xtensa/XtensaInstrInfo.td
llvm/lib/Target/Xtensa/XtensaOperands.td
llvm/test/MC/Xtensa/Relocations/fixups.s
llvm/test/MC/Xtensa/Relocations/relocations.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 83b1cfca529bf3..731f9535ca251f 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -193,6 +193,11 @@ struct XtensaOperand : public MCParsedAsmOperand {
bool isImm1_16() const { return isImm(1, 16); }
+ // Check that value is either equals (-1) or from [1,15] range.
+ 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 +485,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]");
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..c11c4b7038bdb7 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) {
+ report_fatal_error("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 = "getImm32n_95OpValue";
+ let DecoderMethod = "decodeImm32n_95Operand";
+}
+
// shimm1_31 predicate - Immediate in the range [1,31]
def Shimm1_31_AsmOperand : ImmAsmOperand<"Shimm1_31">;
def shimm1_31 : Immediate<i32, [{ return Imm >= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> {
diff --git a/llvm/test/MC/Disassembler/Xtensa/code_density.txt b/llvm/test/MC/Disassembler/Xtensa/code_density.txt
new file mode 100644
index 00000000000000..b2c91bcfbaefec
--- /dev/null
+++ b/llvm/test/MC/Disassembler/Xtensa/code_density.txt
@@ -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
+
+#------------------------------------------------------------------------------
+# Verify that binary code is correctly disassembled with
+# code density option enabled. Also verify that dissasembling without
+# density option generates warnings.
+#------------------------------------------------------------------------------
+
+0x4a 0x23
+# CHECK-DENSITY: add.n a2, a3, a4
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x3b 0x23
+# CHECK-DENSITY: addi.n a2, a3, 3
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x9c 0x03
+# CHECK-DENSITY: beqz.n a3, . +20
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0xcc 0xe3
+# CHECK-DENSITY: bnez.n a3, . +18
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x6d 0xf0
+# CHECK-DENSITY: ill.n
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x28 0x33
+# CHECK-DENSITY: l32i.n a2, a3, 12
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x2d 0x03
+# CHECK-DENSITY: mov.n a2, a3
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x0d 0xf0
+# CHECK-DENSITY: ret.n
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x29 0x33
+# CHECK-DENSITY: s32i.n a2, a3, 12
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x6c 0x02
+# CHECK-DENSITY: movi.n a2, -32
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
+
+0x3d 0xf0
+# CHECK-DENSITY: nop.n
+# CHECK-CORE: [[#@LINE-2]]:1: warning: invalid instruction encoding
+# CHECK-CORE: [[#@LINE-3]]:6: warning: invalid instruction encoding
diff --git a/llvm/test/MC/Disassembler/Xtensa/lit.local.cfg b/llvm/test/MC/Disassembler/Xtensa/lit.local.cfg
new file mode 100644
index 00000000000000..e81bfa773f36a8
--- /dev/null
+++ b/llvm/test/MC/Disassembler/Xtensa/lit.local.cfg
@@ -0,0 +1,2 @@
+if not "Xtensa" in config.root.targets:
+ config.unsupported = True
diff --git a/llvm/test/MC/Xtensa/Relocations/fixups.s b/llvm/test/MC/Xtensa/Relocations/fixups.s
index cd76f2a23322d8..0a3a9eeef1159c 100644
--- a/llvm/test/MC/Xtensa/Relocations/fixups.s
+++ b/llvm/test/MC/Xtensa/Relocations/fixups.s
@@ -1,7 +1,7 @@
-# RUN: llvm-mc -triple xtensa < %s -show-encoding \
+# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \
# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s
-# RUN: llvm-mc -filetype=obj -triple xtensa < %s \
-# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s
+# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \
+# RUN: | llvm-objdump --mattr=+density -d - | FileCheck -check-prefix=CHECK-INSTR %s
# Checks that fixups that can be resolved within the same object file are
@@ -11,9 +11,13 @@ LBL0:
.fill 12
+beqz.n a2, LBL1
+# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_6
+# CHECK-INSTR: beqz.n a2, . +29
+
beq a0, a1, LBL0
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_8
-# CHECK-INSTR: beq a0, a1, . -12
+# CHECK-INSTR: beq a0, a1, . -14
beq a0, a1, LBL1
# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_8
@@ -21,7 +25,7 @@ beq a0, a1, LBL1
beqz a2, LBL0
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_12
-# CHECK-INSTR: beqz a2, . -18
+# CHECK-INSTR: beqz a2, . -20
beqz a2, LBL1
# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_12
@@ -33,22 +37,23 @@ call0 LBL0
call0 LBL2
# CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_call_18
-# CHECK-INSTR: call0 . +2056
+# CHECK-INSTR: call0 . +2068
j LBL0
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_jump_18
-# CHECK-INSTR: j . -30
+# CHECK-INSTR: j . -32
j LBL2
# CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_jump_18
-# CHECK-INSTR: j . +2047
+# CHECK-INSTR: j . +2061
l32r a1, LBL0
# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_l32r_16
-# CHECK-INSTR: l32r a1, . -36
+# CHECK-INSTR: l32r a1, . -38
LBL1:
.fill 2041
+.align 4
LBL2:
diff --git a/llvm/test/MC/Xtensa/Relocations/relocations.s b/llvm/test/MC/Xtensa/Relocations/relocations.s
index 19c2e16352509d..339f6cb44bfcfd 100644
--- a/llvm/test/MC/Xtensa/Relocations/relocations.s
+++ b/llvm/test/MC/Xtensa/Relocations/relocations.s
@@ -1,6 +1,6 @@
-# RUN: llvm-mc -triple xtensa < %s -show-encoding \
+# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \
# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
-# RUN: llvm-mc -filetype=obj -triple xtensa < %s \
+# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s
# Check prefixes:
@@ -76,6 +76,14 @@ beqz a8, func
# INST: beqz a8, func
# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_12
+beqz.n a8, func
+# INST: beqz.n a8, func
+# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_6
+
+bnez.n a8, func
+# INST: bnez.n a8, func
+# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_6
+
bge a14, a2, func
# RELOC: R_XTENSA_SLOT0_OP
# INST: bge a14, a2, func
diff --git a/llvm/test/MC/Xtensa/code_density-invalid.s b/llvm/test/MC/Xtensa/code_density-invalid.s
new file mode 100644
index 00000000000000..b5068cb8d57ab2
--- /dev/null
+++ b/llvm/test/MC/Xtensa/code_density-invalid.s
@@ -0,0 +1,21 @@
+# RUN: not llvm-mc -triple xtensa --mattr=+density %s 2>&1 | FileCheck %s
+
+LBL0:
+
+# Out of range immediates
+
+# imm1n_15
+addi.n a2, a3, 20
+# CHECK: :[[#@LINE-1]]:16: error: expected immediate in range [-1, 15] except 0
+
+# imm1n_15
+addi.n a2, a3, 0
+# CHECK: :[[#@LINE-1]]:16: error: expected immediate in range [-1, 15] except 0
+
+# imm32n_95
+movi.n a2, 100
+# CHECK: :[[#@LINE-1]]:12: error: expected immediate in range [-32, 95]
+
+# Offset4m32
+l32i.n a2, a3, 100
+# CHECK: :[[#@LINE-1]]:16: error: expected immediate in range [0, 60], first 2 bits should be zero
diff --git a/llvm/test/MC/Xtensa/code_density.s b/llvm/test/MC/Xtensa/code_density.s
new file mode 100644
index 00000000000000..fe9f7e91774487
--- /dev/null
+++ b/llvm/test/MC/Xtensa/code_density.s
@@ -0,0 +1,68 @@
+# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+density \
+# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+
+.align 4
+LBL0:
+
+# Instruction format RRRN
+# CHECK-INST: add.n a2, a3, a4
+# CHECK: encoding: [0x4a,0x23]
+add.n a2, a3, a4
+
+# Instruction format RRRN
+# CHECK-INST: addi.n a2, a3, 3
+# CHECK: encoding: [0x3b,0x23]
+addi.n a2, a3, 3
+
+# Instruction format RRRN
+# CHECK-INST: addi.n a2, a3, -1
+# CHECK: encoding: [0x0b,0x23]
+addi.n a2, a3, -1
+
+# Instruction format RI6
+# CHECK-INST: beqz.n a3, LBL1
+# CHECK: encoding: [0x8c'A',0x03'A']
+beqz.n a3, LBL1
+
+# Instruction format RI6
+# CHECK-INST: bnez.n a3, LBL1
+# CHECK: encoding: [0xcc'A',0x03'A']
+bnez.n a3, LBL1
+
+# Instruction format RRRN
+# CHECK-INST: ill.n
+# CHECK: encoding: [0x6d,0xf0]
+ill.n
+
+# Instruction format RRRN
+# CHECK-INST: l32i.n a2, a3, 12
+# CHECK: encoding: [0x28,0x33]
+l32i.n a2, a3, 12
+
+# Instruction format RRRN
+# CHECK-INST: mov.n a2, a3
+# CHECK: encoding: [0x2d,0x03]
+mov.n a2, a3
+
+# Instruction format RI7
+# CHECK-INST: movi.n a2, -32
+# CHECK: encoding: [0x6c,0x02]
+movi.n a2, -32
+
+# Instruction format RRRN
+# CHECK-INST: nop.n
+# CHECK: encoding: [0x3d,0xf0]
+nop.n
+
+# Instruction format RRRN
+# CHECK-INST: ret.n
+# CHECK: encoding: [0x0d,0xf0]
+ret.n
+
+# Instruction format RRRN
+# CHECK-INST: s32i.n a2, a3, 12
+# CHECK: encoding: [0x29,0x33]
+s32i.n a2, a3, 12
+
+.align 4
+LBL1:
More information about the llvm-commits
mailing list