[AArch64][GlobalISel] Select llvm.aarch64.stlxr(i64, i64*)

This adds partial instruction selection support for llvm.aarch64.stlxr. It also
factors out selection for G_INTRINSIC_W_SIDE_EFFECTS into its own function. The
new function removes the restriction that the intrinsic ID on the
G_INTRINSIC_W_SIDE_EFFECTS be on operand 0.

Also add a test, and add a GISel line to arm64-ldxr-stxr.ll.

Differential Revision: https://reviews.llvm.org/D60100

llvm-svn: 357518
This commit is contained in:
Jessica Paquette 2019-04-02 19:57:26 +00:00
parent aac9285377
commit 22c6215c7e
3 changed files with 104 additions and 8 deletions

View File

@ -96,6 +96,8 @@ private:
bool selectConcatVectors(MachineInstr &I, MachineRegisterInfo &MRI) const;
bool selectSplitVectorUnmerge(MachineInstr &I,
MachineRegisterInfo &MRI) const;
bool selectIntrinsicWithSideEffects(MachineInstr &I,
MachineRegisterInfo &MRI) const;
unsigned emitConstantPoolEntry(Constant *CPVal, MachineFunction &MF) const;
MachineInstr *emitLoadFromConstantPool(Constant *CPVal,
@ -1735,14 +1737,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I,
return STI.isTargetDarwin() ? selectVaStartDarwin(I, MF, MRI)
: selectVaStartAAPCS(I, MF, MRI);
case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
if (!I.getOperand(0).isIntrinsicID())
return false;
if (I.getOperand(0).getIntrinsicID() != Intrinsic::trap)
return false;
BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::BRK))
.addImm(1);
I.eraseFromParent();
return true;
return selectIntrinsicWithSideEffects(I, MRI);
case TargetOpcode::G_IMPLICIT_DEF: {
I.setDesc(TII.get(TargetOpcode::IMPLICIT_DEF));
const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
@ -2705,6 +2700,71 @@ bool AArch64InstructionSelector::selectBuildVector(
return true;
}
/// Helper function to emit the correct opcode for a llvm.aarch64.stlxr
/// intrinsic.
static unsigned getStlxrOpcode(unsigned NumBytesToStore) {
switch (NumBytesToStore) {
// TODO: 1, 2, and 4 byte stores.
case 8:
return AArch64::STLXRX;
default:
LLVM_DEBUG(dbgs() << "Unexpected number of bytes to store! ("
<< NumBytesToStore << ")\n");
break;
}
return 0;
}
bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
MachineInstr &I, MachineRegisterInfo &MRI) const {
// Find the intrinsic ID.
auto IntrinOp = find_if(I.operands(), [&](const MachineOperand &Op) {
return Op.isIntrinsicID();
});
if (IntrinOp == I.operands_end())
return false;
unsigned IntrinID = IntrinOp->getIntrinsicID();
MachineIRBuilder MIRBuilder(I);
// Select the instruction.
switch (IntrinID) {
default:
return false;
case Intrinsic::trap:
MIRBuilder.buildInstr(AArch64::BRK, {}, {}).addImm(1);
break;
case Intrinsic::aarch64_stlxr:
unsigned StatReg = I.getOperand(0).getReg();
assert(RBI.getSizeInBits(StatReg, MRI, TRI) == 32 &&
"Status register must be 32 bits!");
unsigned SrcReg = I.getOperand(2).getReg();
if (RBI.getSizeInBits(SrcReg, MRI, TRI) != 64) {
LLVM_DEBUG(dbgs() << "Only support 64-bit sources right now.\n");
return false;
}
unsigned PtrReg = I.getOperand(3).getReg();
assert(MRI.getType(PtrReg).isPointer() && "Expected pointer operand");
// Expect only one memory operand.
if (!I.hasOneMemOperand())
return false;
const MachineMemOperand *MemOp = *I.memoperands_begin();
unsigned NumBytesToStore = MemOp->getSize();
unsigned Opc = getStlxrOpcode(NumBytesToStore);
if (!Opc)
return false;
auto StoreMI = MIRBuilder.buildInstr(Opc, {StatReg}, {SrcReg, PtrReg});
constrainSelectedInstRegOperands(*StoreMI, TII, TRI, RBI);
}
I.eraseFromParent();
return true;
}
/// SelectArithImmed - Select an immediate value that can be represented as
/// a 12-bit value shifted left by either 0 or 12. If so, return true with
/// Val set to the 12-bit value and Shift set to the shifter operand.

View File

@ -0,0 +1,32 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=aarch64-unknown-unknown -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
--- |
define i32 @test_store_release_i64(i32 %a, i64* %addr) {
ret i32 %a
}
...
---
name: test_store_release_i64
alignment: 2
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $x1, $x2
; CHECK-LABEL: name: test_store_release_i64
; CHECK: liveins: $w0, $x1, $x2
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x1
; CHECK: [[COPY1:%[0-9]+]]:gpr64sp = COPY $x2
; CHECK: early-clobber %2:gpr32 = STLXRX [[COPY]], [[COPY1]]
; CHECK: $w0 = COPY %2
; CHECK: RET_ReallyLR implicit $w0
%1:gpr(s64) = COPY $x1
%2:gpr(p0) = COPY $x2
%3:gpr(s32) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.stlxr), %1(s64), %2(p0) :: (volatile store 8 into %ir.addr)
$w0 = COPY %3(s32)
RET_ReallyLR implicit $w0
...

View File

@ -1,4 +1,5 @@
; RUN: llc < %s -mtriple=arm64-linux-gnu | FileCheck %s
; RUN: llc < %s -global-isel -global-isel-abort=2 -pass-remarks-missed=gisel* -mtriple=arm64-linux-gnu 2>&1 | FileCheck %s --check-prefixes=GISEL,FALLBACK
%0 = type { i64, i64 }
@ -257,9 +258,12 @@ define i32 @test_store_release_i32(i32, i32 %val, i32* %addr) {
ret i32 %res
}
; FALLBACK-NOT: remark:{{.*}}test_store_release_i64
define i32 @test_store_release_i64(i32, i64 %val, i64* %addr) {
; CHECK-LABEL: test_store_release_i64:
; CHECK: stlxr w0, x1, [x2]
; GISEL-LABEL: test_store_release_i64:
; GISEL: stlxr w0, x1, [x2]
%res = call i32 @llvm.aarch64.stlxr.p0i64(i64 %val, i64* %addr)
ret i32 %res
}