From b9a6a95909b50275cffab3dbb61b9429d4713048 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Thu, 12 Dec 2024 03:25:35 +0300 Subject: [PATCH 1/5] [Xtensa] Implement Code Density Option. The Code Density option adds 16-bit encoding for frequently used instructions. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 10 ++ .../Disassembler/XtensaDisassembler.cpp | 81 ++++++++++++-- .../Xtensa/MCTargetDesc/XtensaAsmBackend.cpp | 4 +- .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 22 ++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 2 + .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 55 +++++++++- llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 9 +- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 7 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 101 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 14 +++ .../MC/Xtensa/Options/code_density-invalid.s | 17 +++ llvm/test/MC/Xtensa/Options/code_density.s | 63 +++++++++++ llvm/test/MC/Xtensa/Relocations/fixups.s | 23 ++-- llvm/test/MC/Xtensa/Relocations/relocations.s | 12 ++- 14 files changed, 395 insertions(+), 25 deletions(-) create mode 100644 llvm/test/MC/Xtensa/Options/code_density-invalid.s create mode 100644 llvm/test/MC/Xtensa/Options/code_density.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 83b1cfca529bf..f1d12a51afb48 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 2d36b94dd40c7..8bff0f6660b52 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 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(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 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 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 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 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 a296a22247a5c..c1fb46e69e6fb 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 e04d7bd211216..df8a0854f06f4 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 f56d5d1458dc1..e5bc67869e103 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 1afdbb38f9571..51d4b8a9cc5fc 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 &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getImm1n_15OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getImm32n_95OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &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 &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = static_cast(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 &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = static_cast(MO.getImm()); + + assert(((Res >= -32) && (Res <= 95)) && "Unexpected operand value!"); + + return Res; +} + uint32_t XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp index af1110487b427..ef14095d18efb 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(); + 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 7e43c03ee72ca..6dfda02b7622b 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 e21de0448aa5a..699d0d6cf8044 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 oper0, string instrAsm, + SDPatternOperator opNode, bit isComm = 0> + : RRRN_Inst, 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 f41081f9bf2f9..aa72fa0a56a6f 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -72,6 +72,20 @@ def imm1_16 : Immediate= 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= -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= -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= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> { diff --git a/llvm/test/MC/Xtensa/Options/code_density-invalid.s b/llvm/test/MC/Xtensa/Options/code_density-invalid.s new file mode 100644 index 0000000000000..8d0c472e3f1da --- /dev/null +++ b/llvm/test/MC/Xtensa/Options/code_density-invalid.s @@ -0,0 +1,17 @@ +# 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 + +# imm32n_95 +movi.n a2, 100 +# CHECK: :[[#@LINE-1]]:12: error: expected immediate in range [-32, 95] except 0 + +# 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/Options/code_density.s b/llvm/test/MC/Xtensa/Options/code_density.s new file mode 100644 index 0000000000000..429b3d6a03daf --- /dev/null +++ b/llvm/test/MC/Xtensa/Options/code_density.s @@ -0,0 +1,63 @@ +# 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 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: diff --git a/llvm/test/MC/Xtensa/Relocations/fixups.s b/llvm/test/MC/Xtensa/Relocations/fixups.s index cd76f2a23322d..0a3a9eeef1159 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 19c2e16352509..339f6cb44bfcf 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 From 9dc207f402f50408f203cd205776ff43056ad405 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 13 Dec 2024 01:31:14 +0300 Subject: [PATCH 2/5] [Xtensa] Minor fix. --- llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index f1d12a51afb48..d2c4537d18dff 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -193,7 +193,8 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isImm1_16() const { return isImm(1, 16); } - bool isImm1n_15() const { return (isImm(1, 15) || isImm(-1, -1)); } + // 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); } From 32270ea222f0a7d7dbf7bb99800635576440003a Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 13 Dec 2024 16:59:16 +0300 Subject: [PATCH 3/5] [Xtensa] Fix asm parser and add disassembler test. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 2 +- .../MC/Disassembler/Xtensa/code_density.txt | 64 +++++++++++++++++++ .../{Options => }/code_density-invalid.s | 6 +- .../MC/Xtensa/{Options => }/code_density.s | 5 ++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 llvm/test/MC/Disassembler/Xtensa/code_density.txt rename llvm/test/MC/Xtensa/{Options => }/code_density-invalid.s (79%) rename llvm/test/MC/Xtensa/{Options => }/code_density.s (92%) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index d2c4537d18dff..731f9535ca251 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -490,7 +490,7 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, "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"); + "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/test/MC/Disassembler/Xtensa/code_density.txt b/llvm/test/MC/Disassembler/Xtensa/code_density.txt new file mode 100644 index 0000000000000..b2c91bcfbaefe --- /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/Xtensa/Options/code_density-invalid.s b/llvm/test/MC/Xtensa/code_density-invalid.s similarity index 79% rename from llvm/test/MC/Xtensa/Options/code_density-invalid.s rename to llvm/test/MC/Xtensa/code_density-invalid.s index 8d0c472e3f1da..b5068cb8d57ab 100644 --- a/llvm/test/MC/Xtensa/Options/code_density-invalid.s +++ b/llvm/test/MC/Xtensa/code_density-invalid.s @@ -8,9 +8,13 @@ LBL0: 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] except 0 +# CHECK: :[[#@LINE-1]]:12: error: expected immediate in range [-32, 95] # Offset4m32 l32i.n a2, a3, 100 diff --git a/llvm/test/MC/Xtensa/Options/code_density.s b/llvm/test/MC/Xtensa/code_density.s similarity index 92% rename from llvm/test/MC/Xtensa/Options/code_density.s rename to llvm/test/MC/Xtensa/code_density.s index 429b3d6a03daf..fe9f7e9177448 100644 --- a/llvm/test/MC/Xtensa/Options/code_density.s +++ b/llvm/test/MC/Xtensa/code_density.s @@ -14,6 +14,11 @@ add.n a2, a3, a4 # 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'] From 343fdac2995c785e9776ba192cd445efe5fb7596 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 13 Dec 2024 18:18:44 +0300 Subject: [PATCH 4/5] [Xtensa] Fix disassembler test. --- llvm/test/MC/Disassembler/Xtensa/lit.local.cfg | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 llvm/test/MC/Disassembler/Xtensa/lit.local.cfg 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 0000000000000..e81bfa773f36a --- /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 From c8c44285f06cddd3752e65a36b6b6ca07306d795 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Mon, 16 Dec 2024 22:18:41 +0300 Subject: [PATCH 5/5] [Xtensa] Minor fixes. --- llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index 8bff0f6660b52..c11c4b7038bdb 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -283,7 +283,7 @@ static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, } if (!IsLittleEndian) { - llvm_unreachable("Big-endian mode currently is not supported!"); + report_fatal_error("Big-endian mode currently is not supported!"); } else { Insn = (Bytes[1] << 8) | Bytes[0]; }