Skip to content

Commit

Permalink
Re-land "[AArch64] Add FEAT_PAuthLR assembler support" (#75947)
Browse files Browse the repository at this point in the history
This reverts commit 199a0f9.
Fixed the left-shift of signed integer which was causing UB.
  • Loading branch information
tmatheson-arm committed Dec 21, 2023
1 parent 34a6598 commit 192f720
Show file tree
Hide file tree
Showing 15 changed files with 518 additions and 4 deletions.
9 changes: 7 additions & 2 deletions llvm/lib/Target/AArch64/AArch64.td
Expand Up @@ -622,8 +622,13 @@ def FeatureLdpAlignedOnly : SubtargetFeature<"ldp-aligned-only", "HasLdpAlignedO
def FeatureStpAlignedOnly : SubtargetFeature<"stp-aligned-only", "HasStpAlignedOnly",
"true", "In order to emit stp, first check if the store will be aligned to 2 * element_size">;

// AArch64 2023 Architecture Extensions (v9.5-A)

def FeatureCPA : SubtargetFeature<"cpa", "HasCPA", "true",
"Enable ARMv9.5-A Checked Pointer Arithmetic (FEAT_CPA)">;
"Enable Armv9.5-A Checked Pointer Arithmetic (FEAT_CPA)">;

def FeaturePAuthLR : SubtargetFeature<"pauth-lr", "HasPAuthLR",
"true", "Enable Armv9.5-A PAC enhancements (FEAT_PAuth_LR)">;

//===----------------------------------------------------------------------===//
// Architectures.
Expand Down Expand Up @@ -810,7 +815,7 @@ def SMEUnsupported : AArch64Unsupported {
SME2Unsupported.F);
}

let F = [HasPAuth] in
let F = [HasPAuth, HasPAuthLR] in
def PAUnsupported : AArch64Unsupported;

include "AArch64SchedA53.td"
Expand Down
74 changes: 74 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrFormats.td
Expand Up @@ -2368,6 +2368,80 @@ class ClearAuth<bits<1> data, string asm>
let Inst{4-0} = Rd;
}

// v9.5-A FEAT_PAuth_LR

class SignAuthFixedRegs<bits<5> opcode2, bits<6> opcode, string asm>
: I<(outs), (ins), asm, "", "", []>,
Sched<[WriteI, ReadI]> {
let Inst{31} = 0b1; // sf
let Inst{30} = 0b1;
let Inst{29} = 0b0; // S
let Inst{28-21} = 0b11010110;
let Inst{20-16} = opcode2;
let Inst{15-10} = opcode;
let Inst{9-5} = 0b11111; // Rn
let Inst{4-0} = 0b11110; // Rd
}

def PAuthPCRelLabel16Operand : PCRelLabel<16> {
let Name = "PAuthPCRelLabel16";
let PredicateMethod = "isPAuthPCRelLabel16Operand";
}
def am_pauth_pcrel : Operand<OtherVT> {
let EncoderMethod = "getPAuthPCRelOpValue";
let DecoderMethod = "DecodePCRelLabel16";
let PrintMethod = "printAlignedLabel";
let ParserMatchClass = PAuthPCRelLabel16Operand;
let OperandType = "OPERAND_PCREL";
}

class SignAuthPCRel<bits<2> opc, string asm>
: I<(outs), (ins am_pauth_pcrel:$label), asm, "\t$label", "", []>,
Sched<[]> {
bits<16> label;
let Inst{31} = 0b1; // sf
let Inst{30-23} = 0b11100111;
let Inst{22-21} = opc;
let Inst{20-5} = label; // imm
let Inst{4-0} = 0b11111; // Rd
}

class SignAuthOneReg<bits<5> opcode2, bits<6> opcode, string asm>
: I<(outs), (ins GPR64:$Rn), asm, "\t$Rn", "", []>,
Sched<[]> {
bits<5> Rn;
let Inst{31} = 0b1; // sf
let Inst{30} = 0b1;
let Inst{29} = 0b0; // S
let Inst{28-21} = 0b11010110;
let Inst{20-16} = opcode2;
let Inst{15-10} = opcode;
let Inst{9-5} = Rn;
let Inst{4-0} = 0b11110; // Rd
}

class SignAuthReturnPCRel<bits<3> opc, bits<5> op2, string asm>
: I<(outs), (ins am_pauth_pcrel:$label), asm, "\t$label", "", []>,
Sched<[WriteAtomic]> {
bits<16> label;
let Inst{31-24} = 0b01010101;
let Inst{23-21} = opc;
let Inst{20-5} = label; // imm16
let Inst{4-0} = op2;
}

class SignAuthReturnReg<bits<6> op3, string asm>
: I<(outs), (ins GPR64common:$Rm), asm, "\t$Rm", "", []>,
Sched<[WriteAtomic]> {
bits<5> Rm;
let Inst{31-25} = 0b1101011;
let Inst{24-21} = 0b0010; // opc
let Inst{20-16} = 0b11111; // op2
let Inst{15-10} = op3;
let Inst{9-5} = 0b11111; // Rn
let Inst{4-0} = Rm; // op4 (Rm)
}

// Base class for the Armv8.4-A 8 and 16-bit flag manipulation instructions
class BaseFlagManipulation<bit sf, bit sz, dag iops, string asm, string ops>
: I<(outs), iops, asm, ops, "", []>,
Expand Down
39 changes: 39 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Expand Up @@ -61,6 +61,9 @@ def HasLOR : Predicate<"Subtarget->hasLOR()">,
def HasPAuth : Predicate<"Subtarget->hasPAuth()">,
AssemblerPredicateWithAll<(all_of FeaturePAuth), "pauth">;

def HasPAuthLR : Predicate<"Subtarget->hasPAuthLR()">,
AssemblerPredicateWithAll<(all_of FeaturePAuthLR), "pauth-lr">;

def HasJS : Predicate<"Subtarget->hasJS()">,
AssemblerPredicateWithAll<(all_of FeatureJS), "jsconv">;

Expand Down Expand Up @@ -1646,6 +1649,42 @@ let Predicates = [HasPAuth] in {

}

// v9.5-A pointer authentication extensions

// Always accept "pacm" as an alias for "hint #39", but don't emit it when
// disassembling if we don't have the pauth-lr feature.
let CRm = 0b0100 in {
def PACM : SystemNoOperands<0b111, "hint\t#39">;
}
def : InstAlias<"pacm", (PACM), 0>;

let Predicates = [HasPAuthLR] in {
let Defs = [LR], Uses = [LR, SP] in {
// opcode2, opcode, asm
def PACIASPPC : SignAuthFixedRegs<0b00001, 0b101000, "paciasppc">;
def PACIBSPPC : SignAuthFixedRegs<0b00001, 0b101001, "pacibsppc">;
def PACNBIASPPC : SignAuthFixedRegs<0b00001, 0b100000, "pacnbiasppc">;
def PACNBIBSPPC : SignAuthFixedRegs<0b00001, 0b100001, "pacnbibsppc">;
// opc, asm
def AUTIASPPCi : SignAuthPCRel<0b00, "autiasppc">;
def AUTIBSPPCi : SignAuthPCRel<0b01, "autibsppc">;
// opcode2, opcode, asm
def AUTIASPPCr : SignAuthOneReg<0b00001, 0b100100, "autiasppc">;
def AUTIBSPPCr : SignAuthOneReg<0b00001, 0b100101, "autibsppc">;
}

let Uses = [LR, SP], isReturn = 1, isTerminator = 1, isBarrier = 1 in {
// opc, op2, asm
def RETAASPPCi : SignAuthReturnPCRel<0b000, 0b11111, "retaasppc">;
def RETABSPPCi : SignAuthReturnPCRel<0b001, 0b11111, "retabsppc">;
// op3, asm
def RETAASPPCr : SignAuthReturnReg<0b000010, "retaasppc">;
def RETABSPPCr : SignAuthReturnReg<0b000011, "retabsppc">;
}
def : InstAlias<"pacm", (PACM), 1>;
}


// v8.3a floating point conversion for javascript
let Predicates = [HasJS, HasFPARMv8], Defs = [NZCV] in
def FJCVTZS : BaseFPToIntegerUnscaled<0b01, 0b11, 0b110, FPR64, GPR32,
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AArch64/AArch64SchedA64FX.td
Expand Up @@ -22,7 +22,7 @@ def A64FXModel : SchedMachineModel {

list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F, SVEUnsupported.F,
[HasMTE, HasMatMulInt8, HasBF16,
HasPAuth, HasCPA]);
HasPAuth, HasPAuthLR, HasCPA]);
let FullInstRWOverlapCheck = 0;
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td
Expand Up @@ -19,7 +19,7 @@ def NeoverseN2Model : SchedMachineModel {
let CompleteModel = 1;

list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F,
[HasSVE2p1, HasCPA]);
[HasSVE2p1, HasPAuthLR, HasCPA]);
}

//===----------------------------------------------------------------------===//
Expand Down
28 changes: 28 additions & 0 deletions llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Expand Up @@ -1696,6 +1696,21 @@ class AArch64Operand : public MCParsedAsmOperand {
return DiagnosticPredicateTy::Match;
}

bool isPAuthPCRelLabel16Operand() const {
// PAuth PCRel16 operands are similar to regular branch targets, but only
// negative values are allowed for concrete immediates as signing instr
// should be in a lower address.
if (!isImm())
return false;
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
if (!MCE)
return true;
int64_t Val = MCE->getValue();
if (Val & 0b11)
return false;
return (Val <= 0) && (Val > -(1 << 18));
}

void addExpr(MCInst &Inst, const MCExpr *Expr) const {
// Add as immediates when possible. Null MCExpr = 0.
if (!Expr)
Expand Down Expand Up @@ -1997,6 +2012,19 @@ class AArch64Operand : public MCParsedAsmOperand {
Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
}

void addPAuthPCRelLabel16Operands(MCInst &Inst, unsigned N) const {
// PC-relative 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;
}
Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
}

void addPCRelLabel19Operands(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
18 changes: 18 additions & 0 deletions llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
Expand Up @@ -165,6 +165,9 @@ static DecodeStatus DecodeFixedPointScaleImm32(MCInst &Inst, unsigned Imm,
static DecodeStatus DecodeFixedPointScaleImm64(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodePCRelLabel16(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodePCRelLabel19(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
Expand Down Expand Up @@ -887,6 +890,21 @@ static DecodeStatus DecodeFixedPointScaleImm64(MCInst &Inst, unsigned Imm,
return Success;
}

static DecodeStatus DecodePCRelLabel16(MCInst &Inst, unsigned Imm,
uint64_t Addr,
const MCDisassembler *Decoder) {
// Immediate is encoded as the top 16-bits of an unsigned 18-bit negative
// PC-relative offset.
uint64_t ImmVal = Imm;
if (ImmVal < 0 || ImmVal > (1 << 16))

This comment has been minimized.

Copy link
@mikaelholmen

mikaelholmen Dec 22, 2023

Collaborator

Since ImmVal is unsigned, "ImmVal < 0" is always false.
gcc warns about it:

10:05:04 ../lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp: In function 'DecodeStatus DecodePCRelLabel16(llvm::MCInst&, unsigned int, uint64_t, const llvm::MCDisassembler*)':
10:05:04 ../lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp:899:14: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
10:05:04   899 |   if (ImmVal < 0 || ImmVal > (1 << 16))
10:05:04       |       ~~~~~~~^~~
return Fail;
ImmVal = -ImmVal;
if (!Decoder->tryAddingSymbolicOperand(Inst, (ImmVal << 2), Addr,
/*IsBranch=*/false, 0, 0, 4))
Inst.addOperand(MCOperand::createImm(ImmVal));
return Success;
}

static DecodeStatus DecodePCRelLabel19(MCInst &Inst, unsigned Imm,
uint64_t Addr,
const MCDisassembler *Decoder) {
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
Expand Up @@ -67,6 +67,7 @@ class AArch64AsmBackend : public MCAsmBackend {
{"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal},
{"fixup_aarch64_movw", 5, 16, 0},
{"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch16", 5, 16, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal},
{"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal}};
Expand Down Expand Up @@ -121,6 +122,7 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {

case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch14:
case AArch64::fixup_aarch64_pcrel_branch16:
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
case AArch64::fixup_aarch64_ldst_imm12_scale2:
Expand Down Expand Up @@ -314,6 +316,17 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target,
if (Value & 0x3)
Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x3fff;
case AArch64::fixup_aarch64_pcrel_branch16:
// Unsigned PC-relative offset, so invert the negative immediate.
SignedValue = -SignedValue;
Value = static_cast<uint64_t>(SignedValue);
// Check valid 18-bit unsigned range.
if (SignedValue < 0 || SignedValue > ((1 << 18) - 1))
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) & 0xffff;
case AArch64::fixup_aarch64_pcrel_branch26:
case AArch64::fixup_aarch64_pcrel_call26:
if (TheTriple.isOSBinFormatCOFF() && !IsResolved && SignedValue != 0) {
Expand Down Expand Up @@ -380,6 +393,7 @@ unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) con

case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch14:
case AArch64::fixup_aarch64_pcrel_branch16:
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
case AArch64::fixup_aarch64_ldst_imm12_scale2:
Expand Down
Expand Up @@ -186,6 +186,10 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
return R_CLS(LD_PREL_LO19);
case AArch64::fixup_aarch64_pcrel_branch14:
return R_CLS(TSTBR14);
case AArch64::fixup_aarch64_pcrel_branch16:
Ctx.reportError(Fixup.getLoc(),
"relocation of PAC/AUT instructions is not supported");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_pcrel_branch19:
return R_CLS(CONDBR19);
default:
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64FixupKinds.h
Expand Up @@ -43,6 +43,11 @@ enum Fixups {
// The high 14 bits of a 21-bit pc-relative immediate.
fixup_aarch64_pcrel_branch14,

// The high 16 bits of a 18-bit unsigned PC-relative immediate. Used by
// pointer authentication, only within a function, so no relocation can be
// generated.
fixup_aarch64_pcrel_branch16,

// The high 19 bits of a 21-bit pc-relative immediate. Same encoding as
// fixup_aarch64_pcrel_adrhi, except this is use by b.cc and generates
// relocations directly when necessary.
Expand Down
29 changes: 29 additions & 0 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
Expand Up @@ -88,6 +88,12 @@ class AArch64MCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;

/// getPAuthPCRelOpValue - Return the encoded value for a pointer
/// authentication pc-relative operand.
uint32_t getPAuthPCRelOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;

/// getLoadLiteralOpValue - Return the encoded value for a load-literal
/// pc-relative address.
uint32_t getLoadLiteralOpValue(const MCInst &MI, unsigned OpIdx,
Expand Down Expand Up @@ -327,6 +333,29 @@ uint32_t AArch64MCCodeEmitter::getCondBranchTargetOpValue(
return 0;
}

/// getPAuthPCRelOpValue - Return the encoded value for a pointer
/// authentication pc-relative operand.
uint32_t
AArch64MCCodeEmitter::getPAuthPCRelOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpIdx);

// If the destination is an immediate, invert sign as it's a negative value
// that should be encoded as unsigned
if (MO.isImm())
return -(MO.getImm());
assert(MO.isExpr() && "Unexpected target type!");

MCFixupKind Kind = MCFixupKind(AArch64::fixup_aarch64_pcrel_branch16);
Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc()));

++MCNumFixups;

// All of the information is in the fixup.
return 0;
}

/// getLoadLiteralOpValue - Return the encoded value for a load-literal
/// pc-relative address.
uint32_t
Expand Down

0 comments on commit 192f720

Please sign in to comment.