Skip to content

[Xtensa] Implement Code Density Option. #119639

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

Merged
merged 5 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]");
Expand Down
81 changes: 73 additions & 8 deletions llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing disassembler tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added disassembler test.

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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}

Expand All @@ -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);
Comment on lines +327 to +328
Copy link
Contributor

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)

Copy link
Contributor Author

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?

Copy link
Contributor

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

Copy link
Contributor Author

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.

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;
}
4 changes: 3 additions & 1 deletion llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 22 additions & 0 deletions llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
55 changes: 53 additions & 2 deletions llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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".
Expand Down
Loading
Loading