Skip to content

[ARM][MC] Add GNU Alias for ldrexd and strexd instructions #86507

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
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
57 changes: 35 additions & 22 deletions llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6865,8 +6865,9 @@ static void applyMnemonicAliases(StringRef &Mnemonic,
const FeatureBitset &Features,
unsigned VariantID);

// The GNU assembler has aliases of ldrd and strd with the second register
// omitted. We don't have a way to do that in tablegen, so fix it up here.
// The GNU assembler has aliases of ldrd, strd, ldrexd, strexd, ldaexd, and
// stlexd with the second register omitted. We don't have a way to do that in
// tablegen, so fix it up here.
//
// We have to be careful to not emit an invalid Rt2 here, because the rest of
// the assembly parser could then generate confusing diagnostics refering to
Expand All @@ -6876,13 +6877,19 @@ static void applyMnemonicAliases(StringRef &Mnemonic,
void ARMAsmParser::fixupGNULDRDAlias(StringRef Mnemonic,
OperandVector &Operands,
unsigned MnemonicOpsEndInd) {
if (Mnemonic != "ldrd" && Mnemonic != "strd")
if (Mnemonic != "ldrd" && Mnemonic != "strd" && Mnemonic != "ldrexd" &&
Mnemonic != "strexd" && Mnemonic != "ldaexd" && Mnemonic != "stlexd")
return;
if (Operands.size() < MnemonicOpsEndInd + 2)

unsigned IdX = Mnemonic == "strexd" || Mnemonic == "stlexd"
? MnemonicOpsEndInd + 1
: MnemonicOpsEndInd;

if (Operands.size() < IdX + 2)
return;

ARMOperand &Op2 = static_cast<ARMOperand &>(*Operands[MnemonicOpsEndInd]);
ARMOperand &Op3 = static_cast<ARMOperand &>(*Operands[MnemonicOpsEndInd + 1]);
ARMOperand &Op2 = static_cast<ARMOperand &>(*Operands[IdX]);
ARMOperand &Op3 = static_cast<ARMOperand &>(*Operands[IdX + 1]);

if (!Op2.isReg())
return;
Expand All @@ -6907,7 +6914,7 @@ void ARMAsmParser::fixupGNULDRDAlias(StringRef Mnemonic,
return;

Operands.insert(
Operands.begin() + MnemonicOpsEndInd + 1,
Operands.begin() + IdX + 1,
ARMOperand::CreateReg(PairedReg, Op2.getStartLoc(), Op2.getEndLoc()));
}

Expand Down Expand Up @@ -7336,47 +7343,53 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
static_cast<ARMOperand &>(*Operands[MnemonicOpsEndInd]).isImm())
removeCondCode(Operands, MnemonicOpsEndInd);

// GNU Assembler extension (compatibility).
fixupGNULDRDAlias(Mnemonic, Operands, MnemonicOpsEndInd);

// Adjust operands of ldrexd/strexd to MCK_GPRPair.
// ldrexd/strexd require even/odd GPR pair. To enforce this constraint,
// a single GPRPair reg operand is used in the .td file to replace the two
// GPRs. However, when parsing from asm, the two GRPs cannot be
// automatically
// expressed as a GPRPair, so we have to manually merge them.
// FIXME: We would really like to be able to tablegen'erate this.
if (!isThumb() && Operands.size() > MnemonicOpsEndInd + 1 &&
bool IsLoad = (Mnemonic == "ldrexd" || Mnemonic == "ldaexd");
if (!isThumb() && Operands.size() > MnemonicOpsEndInd + 1 + (!IsLoad) &&
(Mnemonic == "ldrexd" || Mnemonic == "strexd" || Mnemonic == "ldaexd" ||
Mnemonic == "stlexd")) {
bool isLoad = (Mnemonic == "ldrexd" || Mnemonic == "ldaexd");
unsigned Idx = isLoad ? MnemonicOpsEndInd : MnemonicOpsEndInd + 1;
unsigned Idx = IsLoad ? MnemonicOpsEndInd : MnemonicOpsEndInd + 1;
ARMOperand &Op1 = static_cast<ARMOperand &>(*Operands[Idx]);
ARMOperand &Op2 = static_cast<ARMOperand &>(*Operands[Idx + 1]);

const MCRegisterClass &MRC = MRI->getRegClass(ARM::GPRRegClassID);
// Adjust only if Op1 and Op2 are GPRs.
if (Op1.isReg() && Op2.isReg() && MRC.contains(Op1.getReg()) &&
MRC.contains(Op2.getReg())) {
// Adjust only if Op1 is a GPR.
if (Op1.isReg() && MRC.contains(Op1.getReg())) {
unsigned Reg1 = Op1.getReg();
unsigned Reg2 = Op2.getReg();
unsigned Rt = MRI->getEncodingValue(Reg1);
unsigned Reg2 = Op2.getReg();
unsigned Rt2 = MRI->getEncodingValue(Reg2);

// Rt2 must be Rt + 1 and Rt must be even.
if (Rt + 1 != Rt2 || (Rt & 1)) {
// Rt2 must be Rt + 1.
if (Rt + 1 != Rt2)
return Error(Op2.getStartLoc(),
isLoad ? "destination operands must be sequential"
IsLoad ? "destination operands must be sequential"
: "source operands must be sequential");
}

// Rt must be even
if (Rt & 1)
return Error(
Op1.getStartLoc(),
IsLoad ? "destination operands must start start at an even register"
: "source operands must start start at an even register");

unsigned NewReg = MRI->getMatchingSuperReg(
Reg1, ARM::gsub_0, &(MRI->getRegClass(ARM::GPRPairRegClassID)));

Operands[Idx] =
ARMOperand::CreateReg(NewReg, Op1.getStartLoc(), Op2.getEndLoc());
Operands.erase(Operands.begin() + Idx + 1);
}
}

// GNU Assembler extension (compatibility).
fixupGNULDRDAlias(Mnemonic, Operands, MnemonicOpsEndInd);

// FIXME: As said above, this is all a pretty gross hack. This instruction
// does not fit with other "subs" and tblgen.
// Adjust operands of B9.3.19 SUBS PC, LR, #imm (Thumb2) system instruction
Expand Down
8 changes: 8 additions & 0 deletions llvm/test/MC/ARM/basic-arm-instructions.s
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,10 @@ Lforward:
@ CHECK: ldrex r1, [r7] @ encoding: [0x9f,0x1f,0x97,0xe1]
@ CHECK: ldrexd r6, r7, [r8] @ encoding: [0x9f,0x6f,0xb8,0xe1]

@ GNU alias
ldrexd r6, [r8]
@ CHECK: ldrexd r6, r7, [r8] @ encoding: [0x9f,0x6f,0xb8,0xe1]

@------------------------------------------------------------------------------
@ LDRHT
@------------------------------------------------------------------------------
Expand Down Expand Up @@ -2904,6 +2908,10 @@ Lforward:
@ CHECK: strex r2, r1, [r7] @ encoding: [0x91,0x2f,0x87,0xe1]
@ CHECK: strexd r6, r2, r3, [r8] @ encoding: [0x92,0x6f,0xa8,0xe1]

@ GNU alias
strexd r6, r2, [r8]
@ CHECK: strexd r6, r2, r3, [r8] @ encoding: [0x92,0x6f,0xa8,0xe1]

@------------------------------------------------------------------------------
@ STR
@------------------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions llvm/test/MC/ARM/load-store-acquire-release-v8-thumb.s
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
@ CHECK-V7: error: instruction requires: acquire/release
@ CHECK-V7: error: instruction requires: acquire/release

@ GNU alias
ldaexd r6, [r8]
@ CHECK: ldaexd r6, r7, [r8] @ encoding: [0xd8,0xe8,0xff,0x67]

stlexb r1, r3, [r4]
stlexh r4, r2, [r5]
stlex r2, r1, [r7]
Expand All @@ -27,6 +31,10 @@
@ CHECK-V7: error: instruction requires: acquire/release
@ CHECK-V7: error: instruction requires: acquire/release

@ GNU alias
stlexd r6, r2, [r8]
@ CHECK: stlexd r6, r2, r3, [r8] @ encoding: [0xc8,0xe8,0xf6,0x23]

lda r5, [r6]
ldab r5, [r6]
ldah r12, [r9]
Expand Down
17 changes: 16 additions & 1 deletion llvm/test/MC/ARM/load-store-acquire-release-v8.s
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@ RUN: llvm-mc -triple=armv8 -show-encoding < %s | FileCheck %s
@ RUN: not llvm-mc -triple=armv8 -show-encoding < %s 2> %t | FileCheck %s
@ RUN: FileCheck %s < %t --check-prefix=CHECK-ERROR
@ RUN: not llvm-mc -triple=armv7 -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-V7
ldaexb r3, [r4]
ldaexh r2, [r5]
Expand All @@ -14,6 +15,13 @@
@ CHECK-V7: instruction requires: acquire/release
@ CHECK-V7: instruction requires: acquire/release

ldaexd r2, r4, [r8]
@ CHECK-ERROR: error: destination operands must be sequential

@ GNU alias
ldaexd r6, [r8]
@ CHECK: ldaexd r6, r7, [r8] @ encoding: [0x9f,0x6e,0xb8,0xe1]

stlexb r1, r3, [r4]
stlexh r4, r2, [r5]
stlex r2, r1, [r7]
Expand All @@ -27,6 +35,13 @@
@ CHECK-V7: instruction requires: acquire/release
@ CHECK-V7: instruction requires: acquire/release

stlexd r6, r2, r4, [r8]
@ CHECK-ERROR: error: source operands must be sequential

@ GNU alias
stlexd r6, r2, [r8]
@ CHECK: stlexd r6, r2, r3, [r8] @ encoding: [0x92,0x6e,0xa8,0xe1]

lda r5, [r6]
ldab r5, [r6]
ldah r12, [r9]
Expand Down