Skip to content

[LLVM][AArch64]Add assembly/disassembly for compare-and-branch instr… #113461

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 1 commit into from
Oct 23, 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
135 changes: 135 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,46 @@ def uimm16 : Operand<i16>, ImmLeaf<i16, [{return Imm >= 0 && Imm < 65536;}]>{
let ParserMatchClass = AsmImmRange<0, 65535>;
}

def uimm6_64b : Operand<i64>, ImmLeaf<i64, [{ return Imm >= 0 && Imm < 64; }]> {
let ParserMatchClass = UImm6Operand;
}

def uimm6_32b : Operand<i32>, ImmLeaf<i32, [{ return Imm >= 0 && Imm < 64; }]> {
let ParserMatchClass = UImm6Operand;
}

def UImm6Plus1Operand : AsmOperandClass {
let Name = "UImm6P1";
let DiagnosticType = "InvalidImm1_64";
let RenderMethod = "addImmOperands";
let ParserMethod = "tryParseAdjImm0_63<-1>";
let PredicateMethod = "isImmInRange<0,63>";
}

def UImm6Minus1Operand : AsmOperandClass {
let Name = "UImm6M1";
let DiagnosticType = "InvalidImmM1_62";
let RenderMethod = "addImmOperands";
let ParserMethod = "tryParseAdjImm0_63<1>";
let PredicateMethod = "isImmInRange<0,63>";
}

def uimm6p1_32b : Operand<i32> {
let ParserMatchClass = UImm6Plus1Operand;
}

def uimm6p1_64b : Operand<i64> {
let ParserMatchClass = UImm6Plus1Operand;
}

def uimm6m1_32b : Operand<i32> {
let ParserMatchClass = UImm6Minus1Operand;
}

def uimm6m1_64b : Operand<i64> {
let ParserMatchClass = UImm6Minus1Operand;
}

def SImm9Operand : SImmOperand<9>;
def simm9 : Operand<i64>, ImmLeaf<i64, [{ return Imm >= -256 && Imm < 256; }]> {
let ParserMatchClass = SImm9Operand;
Expand Down Expand Up @@ -657,6 +697,7 @@ class PCRelLabel<int N> : BranchTarget<N> {
def BranchTarget14Operand : BranchTarget<14>;
def BranchTarget26Operand : BranchTarget<26>;
def PCRelLabel19Operand : PCRelLabel<19>;
def PCRelLabel9Operand : PCRelLabel<9>;

def MovWSymbolG3AsmOperand : AsmOperandClass {
let Name = "MovWSymbolG3";
Expand Down Expand Up @@ -2158,6 +2199,17 @@ def am_brcond : Operand<OtherVT> {
let OperandType = "OPERAND_PCREL";
}

// Conditional branch target. 9-bit immediate. The low two bits of the target
// offset are implied zero and so are not part of the immediate.
def am_brcmpcond : Operand<OtherVT> {
let EncoderMethod = "getCondCompBranchTargetOpValue";
let DecoderMethod = "DecodePCRelLabel9";
let PrintMethod = "printAlignedLabel";
let ParserMatchClass = PCRelLabel9Operand;
let OperandType = "OPERAND_PCREL";
}


class BranchCond<bit bit4, string mnemonic>
: I<(outs), (ins ccode:$cond, am_brcond:$target),
mnemonic, ".$cond\t$target", "",
Expand Down Expand Up @@ -12911,6 +12963,89 @@ class MulAccumCPA<bit isSub, string asm>
let Inst{31} = 0b1;
}


//----------------------------------------------------------------------------
// 2024 Armv9.6 Extensions
//----------------------------------------------------------------------------

//---
// Compare-and-branch instructions.
//---

class BaseCmpBranchRegister<RegisterClass regtype, bit sf, bits<3> cc,
bits<2>sz, string asm>
: I<(outs), (ins regtype:$Rt, regtype:$Rm, am_brcmpcond:$target),
asm, "\t$Rt, $Rm, $target", "",
[]>,
Sched<[WriteBr]> {
let isBranch = 1;
let isTerminator = 1;

bits<5> Rm;
bits<5> Rt;
bits<9> target;
let Inst{31} = sf;
let Inst{30-24} = 0b1110100;
let Inst{23-21} = cc;
let Inst{20-16} = Rm;
let Inst{15-14} = sz;
let Inst{13-5} = target;
let Inst{4-0} = Rt;
}

multiclass CmpBranchRegister<bits<3> cc, string asm> {
def Wrr : BaseCmpBranchRegister<GPR32, 0b0, cc, 0b00, asm>;
def Xrr : BaseCmpBranchRegister<GPR64, 0b1, cc, 0b00, asm>;
}

class BaseCmpBranchImmediate<RegisterClass regtype, bit sf, bits<3> cc,
Operand imm_ty, string asm>
: I<(outs), (ins regtype:$Rt, imm_ty:$imm, am_brcmpcond:$target),
asm, "\t$Rt, $imm, $target", "",
[]>,
Sched<[WriteBr]> {
let isBranch = 1;
let isTerminator = 1;

bits<5> Rt;
bits<6> imm;
bits<9> target;
let Inst{31} = sf;
let Inst{30-24} = 0b1110101;
let Inst{23-21} = cc;
let Inst{20-15} = imm;
let Inst{14} = 0b0;
let Inst{13-5} = target;
let Inst{4-0} = Rt;
}

multiclass CmpBranchImmediate<bits<3> cc, string imm_ty, string asm> {
def Wri : BaseCmpBranchImmediate<GPR32, 0b0, cc, !cast<Operand>(imm_ty # "_32b"), asm>;
def Xri : BaseCmpBranchImmediate<GPR64, 0b1, cc, !cast<Operand>(imm_ty # "_64b"), asm>;
}

multiclass CmpBranchImmediateAlias<string mnemonic, string insn, string imm_ty> {
def : InstAlias<mnemonic # "\t$Rt, $imm, $target",
(!cast<Instruction>(insn # "Wri") GPR32:$Rt,
!cast<Operand>(imm_ty # "_32b"):$imm,
am_brcmpcond:$target), 0>;
def : InstAlias<mnemonic # "\t$Rt, $imm, $target",
(!cast<Instruction>(insn # "Xri") GPR64:$Rt,
!cast<Operand>(imm_ty # "_64b"):$imm,
am_brcmpcond:$target), 0>;
}

multiclass CmpBranchWRegisterAlias<string mnemonic, string insn> {
def : InstAlias<mnemonic # "\t$Rt, $Rm, $target",
(!cast<Instruction>(insn # "Wrr") GPR32:$Rm, GPR32:$Rt, am_brcmpcond:$target), 0>;
}

multiclass CmpBranchRegisterAlias<string mnemonic, string insn> {
defm : CmpBranchWRegisterAlias<mnemonic, insn>;

def : InstAlias<mnemonic # "\t$Rt, $Rm, $target",
(!cast<Instruction>(insn # "Xrr") GPR64:$Rm, GPR64:$Rt, am_brcmpcond:$target), 0>;
}
//----------------------------------------------------------------------------
// Allow the size specifier tokens to be upper case, not just lower.
def : TokenAlias<".4B", ".4b">; // Add dot product
Expand Down
51 changes: 51 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -10423,6 +10423,57 @@ defm : PromoteBinaryv8f16Tov4f32<any_fdiv, FDIVv4f32>;
defm : PromoteBinaryv8f16Tov4f32<any_fmul, FMULv4f32>;
defm : PromoteBinaryv8f16Tov4f32<any_fsub, FSUBv4f32>;

let Predicates = [HasCMPBR] in {
defm CBGT : CmpBranchRegister<0b000, "cbgt">;
defm CBGE : CmpBranchRegister<0b001, "cbge">;
defm CBHI : CmpBranchRegister<0b010, "cbhi">;
defm CBHS : CmpBranchRegister<0b011, "cbhs">;
defm CBEQ : CmpBranchRegister<0b110, "cbeq">;
defm CBNE : CmpBranchRegister<0b111, "cbne">;

def CBHGTWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b000, 0b11, "cbhgt">;
def CBHGEWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b001, 0b11, "cbhge">;
def CBHHIWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b010, 0b11, "cbhhi">;
def CBHHSWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b011, 0b11, "cbhhs">;
def CBHEQWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b110, 0b11, "cbheq">;
def CBHNEWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b111, 0b11, "cbhne">;

def CBBGTWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b000, 0b10, "cbbgt">;
def CBBGEWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b001, 0b10, "cbbge">;
def CBBHIWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b010, 0b10, "cbbhi">;
def CBBHSWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b011, 0b10, "cbbhs">;
def CBBEQWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b110, 0b10, "cbbeq">;
def CBBNEWrr : BaseCmpBranchRegister<GPR32, 0b0, 0b111, 0b10, "cbbne">;

defm CBGT : CmpBranchImmediate<0b000, "uimm6", "cbgt">;
defm CBLT : CmpBranchImmediate<0b001, "uimm6", "cblt">;
defm CBHI : CmpBranchImmediate<0b010, "uimm6", "cbhi">;
defm CBLO : CmpBranchImmediate<0b011, "uimm6", "cblo">;
defm CBEQ : CmpBranchImmediate<0b110, "uimm6", "cbeq">;
defm CBNE : CmpBranchImmediate<0b111, "uimm6", "cbne">;

defm : CmpBranchImmediateAlias<"cbge", "CBGT", "uimm6p1">;
defm : CmpBranchImmediateAlias<"cbhs", "CBHI", "uimm6p1">;
defm : CmpBranchImmediateAlias<"cble", "CBLT", "uimm6m1">;
defm : CmpBranchImmediateAlias<"cbls", "CBLO", "uimm6m1">;

defm : CmpBranchRegisterAlias<"cble", "CBGE">;
defm : CmpBranchRegisterAlias<"cblo", "CBHI">;
defm : CmpBranchRegisterAlias<"cbls", "CBHS">;
defm : CmpBranchRegisterAlias<"cblt", "CBGT">;

defm : CmpBranchWRegisterAlias<"cbble", "CBBGE">;
defm : CmpBranchWRegisterAlias<"cbblo", "CBBHI">;
defm : CmpBranchWRegisterAlias<"cbbls", "CBBHS">;
defm : CmpBranchWRegisterAlias<"cbblt", "CBBGT">;

defm : CmpBranchWRegisterAlias<"cbhle", "CBHGE">;
defm : CmpBranchWRegisterAlias<"cbhlo", "CBHHI">;
defm : CmpBranchWRegisterAlias<"cbhls", "CBHHS">;
defm : CmpBranchWRegisterAlias<"cbhlt", "CBHGT">;
} // HasCMPBR


//===-----------------------------------------------------===//
// Atomic floating-point in-memory instructions (FEAT_LSFE)
//===-----------------------------------------------------===//
Expand Down
51 changes: 51 additions & 0 deletions llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2092,6 +2092,20 @@ class AArch64Operand : public MCParsedAsmOperand {
Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
}

void addPCRelLabel9Operands(MCInst &Inst, unsigned N) const {
// Branch operands don't encode the low bits, so shift them off
// here. If it's a label, however, just put it on directly as there's
// not enough information now to do anything.
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
if (!MCE) {
addExpr(Inst, getImm());
return;
}
assert(MCE && "Invalid constant immediate operand!");
Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
}

void addBranchTarget14Operands(MCInst &Inst, unsigned N) const {
// Branch operands don't encode the low bits, so shift them off
// here. If it's a label, however, just put it on directly as there's
Expand Down Expand Up @@ -5987,6 +6001,8 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
return Error(Loc, "immediate must be an integer in range [1, 32].");
case Match_InvalidImm1_64:
return Error(Loc, "immediate must be an integer in range [1, 64].");
case Match_InvalidImmM1_62:
return Error(Loc, "immediate must be an integer in range [-1, 62].");
case Match_InvalidMemoryIndexedRange2UImm0:
return Error(Loc, "vector select offset must be the immediate range 0:1.");
case Match_InvalidMemoryIndexedRange2UImm1:
Expand Down Expand Up @@ -6757,6 +6773,7 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidImm1_16:
case Match_InvalidImm1_32:
case Match_InvalidImm1_64:
case Match_InvalidImmM1_62:
case Match_InvalidMemoryIndexedRange2UImm0:
case Match_InvalidMemoryIndexedRange2UImm1:
case Match_InvalidMemoryIndexedRange2UImm2:
Expand Down Expand Up @@ -8224,3 +8241,37 @@ ParseStatus AArch64AsmParser::tryParseImmRange(OperandVector &Operands) {
AArch64Operand::CreateImmRange(ImmFVal, ImmLVal, S, E, getContext()));
return ParseStatus::Success;
}

template <int Adj>
ParseStatus AArch64AsmParser::tryParseAdjImm0_63(OperandVector &Operands) {
SMLoc S = getLoc();

parseOptionalToken(AsmToken::Hash);
bool IsNegative = parseOptionalToken(AsmToken::Minus);

if (getTok().isNot(AsmToken::Integer))
return ParseStatus::NoMatch;

const MCExpr *Ex;
if (getParser().parseExpression(Ex))
return ParseStatus::NoMatch;

int64_t Imm = dyn_cast<MCConstantExpr>(Ex)->getValue();
if (IsNegative)
Imm = -Imm;

// We want an adjusted immediate in the range [0, 63]. If we don't have one,
// return a value, which is certain to trigger a error message about invalid
// immediate range instead of a non-descriptive invalid operand error.
static_assert(Adj == 1 || Adj == -1, "Unsafe immediate adjustment");
if (Imm == INT64_MIN || Imm == INT64_MAX || Imm + Adj < 0 || Imm + Adj > 63)
Imm = -2;
else
Imm += Adj;

SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
Operands.push_back(AArch64Operand::CreateImm(
MCConstantExpr::create(Imm, getContext()), S, E, getContext()));

return ParseStatus::Success;
}
17 changes: 17 additions & 0 deletions llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ static DecodeStatus DecodePCRelLabel16(MCInst &Inst, unsigned Imm,
static DecodeStatus DecodePCRelLabel19(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodePCRelLabel9(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeMemExtend(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
Expand Down Expand Up @@ -488,6 +491,20 @@ static DecodeStatus DecodePCRelLabel19(MCInst &Inst, unsigned Imm,
return Success;
}

static DecodeStatus DecodePCRelLabel9(MCInst &Inst, unsigned Imm, uint64_t Addr,
const MCDisassembler *Decoder) {
int64_t ImmVal = Imm;

// Sign-extend 9-bit immediate.
if (ImmVal & (1 << (9 - 1)))
ImmVal |= ~((1LL << 9) - 1);

if (!Decoder->tryAddingSymbolicOperand(Inst, (ImmVal * 4), Addr,
Copy link
Collaborator

@momchil-velikov momchil-velikov Oct 23, 2024

Choose a reason for hiding this comment

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

LGTM.

It'd be very nice to include in the commit message information about what was fixed, e.g.
"Replaced a shift left of a possibly negative value with a multiplication in DecodePCRelLabel9"

/*IsBranch=*/true, 0, 0, 4))
Inst.addOperand(MCOperand::createImm(ImmVal));
return Success;
}

static DecodeStatus DecodeMemExtend(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder) {
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class AArch64AsmBackend : public MCAsmBackend {
{"fixup_aarch64_ldst_imm12_scale16", 10, 12, 0},
{"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal},
{"fixup_aarch64_movw", 5, 16, 0},
{"fixup_aarch64_pcrel_branch9", 5, 9, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch16", 5, 16, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal},
Expand Down Expand Up @@ -120,6 +121,7 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
return 2;

case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch9:
case AArch64::fixup_aarch64_pcrel_branch14:
case AArch64::fixup_aarch64_pcrel_branch16:
case AArch64::fixup_aarch64_add_imm12:
Expand Down Expand Up @@ -307,6 +309,14 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target,
}
return Value;
}
case AArch64::fixup_aarch64_pcrel_branch9:
// Signed 11-bit(9bits + 2 shifts) label
if (!isInt<11>(SignedValue))
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
// Low two bits are not encoded (4-byte alignment assumed).
if (Value & 0b11)
Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x1ff;
case AArch64::fixup_aarch64_pcrel_branch14:
// Signed 16-bit immediate
if (!isInt<16>(SignedValue))
Expand Down Expand Up @@ -391,6 +401,7 @@ unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) con
return 8;

case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch9:
case AArch64::fixup_aarch64_pcrel_branch14:
case AArch64::fixup_aarch64_pcrel_branch16:
case AArch64::fixup_aarch64_add_imm12:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
Ctx.reportError(Fixup.getLoc(),
"relocation of PAC/AUT instructions is not supported");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_pcrel_branch9:
Ctx.reportError(
Fixup.getLoc(),
"relocation of compare-and-branch instructions not supported");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_pcrel_branch19:
return R_CLS(CONDBR19);
default:
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64FixupKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ enum Fixups {
// FIXME: comment
fixup_aarch64_movw,

// The high 9 bits of a 11-bit pc-relative immediate.
fixup_aarch64_pcrel_branch9,

// The high 14 bits of a 21-bit pc-relative immediate.
fixup_aarch64_pcrel_branch14,

Expand Down
Loading
Loading