mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
[AArch64][GlobalISel] Add isel support for G_BLOCK_ADDR.
Also refactors some existing code to materialize addresses for the large code model so it can be shared between G_GLOBAL_VALUE and G_BLOCK_ADDR. This implements PR36390. Differential Revision: https://reviews.llvm.org/D49903 llvm-svn: 338337
This commit is contained in:
parent
d6b9e05a84
commit
6a47e74b23
@ -21,6 +21,7 @@
|
||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
|
||||
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
@ -94,6 +95,10 @@ private:
|
||||
|
||||
void renderTruncImm(MachineInstrBuilder &MIB, const MachineInstr &MI) const;
|
||||
|
||||
// Materialize a GlobalValue or BlockAddress using a movz+movk sequence.
|
||||
void materializeLargeCMVal(MachineInstr &I, const Value *V,
|
||||
unsigned char OpFlags) const;
|
||||
|
||||
const AArch64TargetMachine &TM;
|
||||
const AArch64Subtarget &STI;
|
||||
const AArch64InstrInfo &TII;
|
||||
@ -655,6 +660,45 @@ bool AArch64InstructionSelector::selectVaStartDarwin(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AArch64InstructionSelector::materializeLargeCMVal(
|
||||
MachineInstr &I, const Value *V, unsigned char OpFlags) const {
|
||||
MachineBasicBlock &MBB = *I.getParent();
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
MachineIRBuilder MIB(I);
|
||||
|
||||
auto MovZ = MIB.buildInstr(AArch64::MOVZXi, &AArch64::GPR64RegClass);
|
||||
MovZ->addOperand(MF, I.getOperand(1));
|
||||
MovZ->getOperand(1).setTargetFlags(OpFlags | AArch64II::MO_G0 |
|
||||
AArch64II::MO_NC);
|
||||
MovZ->addOperand(MF, MachineOperand::CreateImm(0));
|
||||
constrainSelectedInstRegOperands(*MovZ, TII, TRI, RBI);
|
||||
|
||||
auto BuildMovK = [&](unsigned SrcReg, unsigned char Flags, unsigned Offset,
|
||||
unsigned ForceDstReg) {
|
||||
unsigned DstReg = ForceDstReg
|
||||
? ForceDstReg
|
||||
: MRI.createVirtualRegister(&AArch64::GPR64RegClass);
|
||||
auto MovI = MIB.buildInstr(AArch64::MOVKXi).addDef(DstReg).addUse(SrcReg);
|
||||
if (auto *GV = dyn_cast<GlobalValue>(V)) {
|
||||
MovI->addOperand(MF, MachineOperand::CreateGA(
|
||||
GV, MovZ->getOperand(1).getOffset(), Flags));
|
||||
} else {
|
||||
MovI->addOperand(
|
||||
MF, MachineOperand::CreateBA(cast<BlockAddress>(V),
|
||||
MovZ->getOperand(1).getOffset(), Flags));
|
||||
}
|
||||
MovI->addOperand(MF, MachineOperand::CreateImm(Offset));
|
||||
constrainSelectedInstRegOperands(*MovI, TII, TRI, RBI);
|
||||
return DstReg;
|
||||
};
|
||||
unsigned DstReg = BuildMovK(MovZ->getOperand(0).getReg(),
|
||||
AArch64II::MO_G1 | AArch64II::MO_NC, 16, 0);
|
||||
DstReg = BuildMovK(DstReg, AArch64II::MO_G2 | AArch64II::MO_NC, 32, 0);
|
||||
BuildMovK(DstReg, AArch64II::MO_G3, 48, I.getOperand(0).getReg());
|
||||
return;
|
||||
}
|
||||
|
||||
bool AArch64InstructionSelector::select(MachineInstr &I,
|
||||
CodeGenCoverage &CoverageInfo) const {
|
||||
assert(I.getParent() && "Instruction should be in a basic block!");
|
||||
@ -936,36 +980,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I,
|
||||
I.getOperand(1).setTargetFlags(OpFlags);
|
||||
} else if (TM.getCodeModel() == CodeModel::Large) {
|
||||
// Materialize the global using movz/movk instructions.
|
||||
unsigned MovZDstReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
|
||||
auto InsertPt = std::next(I.getIterator());
|
||||
auto MovZ =
|
||||
BuildMI(MBB, InsertPt, I.getDebugLoc(), TII.get(AArch64::MOVZXi))
|
||||
.addDef(MovZDstReg);
|
||||
MovZ->addOperand(MF, I.getOperand(1));
|
||||
MovZ->getOperand(1).setTargetFlags(OpFlags | AArch64II::MO_G0 |
|
||||
AArch64II::MO_NC);
|
||||
MovZ->addOperand(MF, MachineOperand::CreateImm(0));
|
||||
constrainSelectedInstRegOperands(*MovZ, TII, TRI, RBI);
|
||||
|
||||
auto BuildMovK = [&](unsigned SrcReg, unsigned char Flags,
|
||||
unsigned Offset, unsigned ForceDstReg) {
|
||||
unsigned DstReg =
|
||||
ForceDstReg ? ForceDstReg
|
||||
: MRI.createVirtualRegister(&AArch64::GPR64RegClass);
|
||||
auto MovI = BuildMI(MBB, InsertPt, MovZ->getDebugLoc(),
|
||||
TII.get(AArch64::MOVKXi))
|
||||
.addDef(DstReg)
|
||||
.addReg(SrcReg);
|
||||
MovI->addOperand(MF, MachineOperand::CreateGA(
|
||||
GV, MovZ->getOperand(1).getOffset(), Flags));
|
||||
MovI->addOperand(MF, MachineOperand::CreateImm(Offset));
|
||||
constrainSelectedInstRegOperands(*MovI, TII, TRI, RBI);
|
||||
return DstReg;
|
||||
};
|
||||
unsigned DstReg = BuildMovK(MovZ->getOperand(0).getReg(),
|
||||
AArch64II::MO_G1 | AArch64II::MO_NC, 16, 0);
|
||||
DstReg = BuildMovK(DstReg, AArch64II::MO_G2 | AArch64II::MO_NC, 32, 0);
|
||||
BuildMovK(DstReg, AArch64II::MO_G3, 48, I.getOperand(0).getReg());
|
||||
materializeLargeCMVal(I, GV, OpFlags);
|
||||
I.eraseFromParent();
|
||||
return true;
|
||||
} else {
|
||||
@ -1482,7 +1497,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I,
|
||||
.addImm(1);
|
||||
I.eraseFromParent();
|
||||
return true;
|
||||
case TargetOpcode::G_IMPLICIT_DEF:
|
||||
case TargetOpcode::G_IMPLICIT_DEF: {
|
||||
I.setDesc(TII.get(TargetOpcode::IMPLICIT_DEF));
|
||||
const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
|
||||
const unsigned DstReg = I.getOperand(0).getReg();
|
||||
@ -1492,6 +1507,25 @@ bool AArch64InstructionSelector::select(MachineInstr &I,
|
||||
RBI.constrainGenericRegister(DstReg, *DstRC, MRI);
|
||||
return true;
|
||||
}
|
||||
case TargetOpcode::G_BLOCK_ADDR: {
|
||||
if (TM.getCodeModel() == CodeModel::Large) {
|
||||
materializeLargeCMVal(I, I.getOperand(1).getBlockAddress(), 0);
|
||||
I.eraseFromParent();
|
||||
return true;
|
||||
} else {
|
||||
I.setDesc(TII.get(AArch64::MOVaddrBA));
|
||||
auto MovMI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::MOVaddrBA),
|
||||
I.getOperand(0).getReg())
|
||||
.addBlockAddress(I.getOperand(1).getBlockAddress(),
|
||||
/* Offset */ 0, AArch64II::MO_PAGE)
|
||||
.addBlockAddress(
|
||||
I.getOperand(1).getBlockAddress(), /* Offset */ 0,
|
||||
AArch64II::MO_NC | AArch64II::MO_PAGEOFF);
|
||||
I.eraseFromParent();
|
||||
return constrainSelectedInstRegOperands(*MovMI, TII, TRI, RBI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
64
test/CodeGen/AArch64/GlobalISel/select-blockaddress.mir
Normal file
64
test/CodeGen/AArch64/GlobalISel/select-blockaddress.mir
Normal file
@ -0,0 +1,64 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=aarch64-unknown-unknown -o - -verify-machineinstrs -run-pass=instruction-select %s | FileCheck %s
|
||||
# RUN: llc -mtriple=aarch64-unknown-unknown -o - -verify-machineinstrs -run-pass=instruction-select -code-model=large %s | FileCheck %s --check-prefix=LARGE
|
||||
--- |
|
||||
; ModuleID = 'blockaddress.ll'
|
||||
source_filename = "blockaddress.ll"
|
||||
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-none-linux-gnu"
|
||||
|
||||
@addr = global i8* null
|
||||
|
||||
define void @test_blockaddress() {
|
||||
store i8* blockaddress(@test_blockaddress, %block), i8** @addr
|
||||
indirectbr i8* blockaddress(@test_blockaddress, %block), [label %block]
|
||||
|
||||
block: ; preds = %0
|
||||
ret void
|
||||
}
|
||||
|
||||
...
|
||||
---
|
||||
name: test_blockaddress
|
||||
alignment: 2
|
||||
legalized: true
|
||||
regBankSelected: true
|
||||
tracksRegLiveness: true
|
||||
registers:
|
||||
- { id: 0, class: gpr }
|
||||
- { id: 1, class: gpr }
|
||||
body: |
|
||||
; CHECK-LABEL: name: test_blockaddress
|
||||
; CHECK: bb.0 (%ir-block.0):
|
||||
; CHECK: successors: %bb.1(0x80000000)
|
||||
; CHECK: [[MOVaddrBA:%[0-9]+]]:gpr64 = MOVaddrBA target-flags(aarch64-page) blockaddress(@test_blockaddress, %ir-block.block), target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@test_blockaddress, %ir-block.block)
|
||||
; CHECK: [[MOVaddr:%[0-9]+]]:gpr64common = MOVaddr target-flags(aarch64-page) @addr, target-flags(aarch64-pageoff, aarch64-nc) @addr
|
||||
; CHECK: STRXui [[MOVaddrBA]], [[MOVaddr]], 0 :: (store 8 into @addr)
|
||||
; CHECK: BR [[MOVaddrBA]]
|
||||
; CHECK: bb.1.block (address-taken):
|
||||
; CHECK: RET_ReallyLR
|
||||
; LARGE-LABEL: name: test_blockaddress
|
||||
; LARGE: bb.0 (%ir-block.0):
|
||||
; LARGE: successors: %bb.1(0x80000000)
|
||||
; LARGE: [[MOVZXi:%[0-9]+]]:gpr64 = MOVZXi target-flags(aarch64-g0, aarch64-nc) blockaddress(@test_blockaddress, %ir-block.block), 0
|
||||
; LARGE: [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[MOVZXi]], target-flags(aarch64-g1, aarch64-nc) blockaddress(@test_blockaddress, %ir-block.block), 16
|
||||
; LARGE: [[MOVKXi1:%[0-9]+]]:gpr64 = MOVKXi [[MOVKXi]], target-flags(aarch64-g2, aarch64-nc) blockaddress(@test_blockaddress, %ir-block.block), 32
|
||||
; LARGE: [[MOVKXi2:%[0-9]+]]:gpr64 = MOVKXi [[MOVKXi1]], target-flags(aarch64-g3) blockaddress(@test_blockaddress, %ir-block.block), 48
|
||||
; LARGE: [[MOVZXi1:%[0-9]+]]:gpr64 = MOVZXi target-flags(aarch64-g0, aarch64-nc) @addr, 0
|
||||
; LARGE: [[MOVKXi3:%[0-9]+]]:gpr64 = MOVKXi [[MOVZXi1]], target-flags(aarch64-g1, aarch64-nc) @addr, 16
|
||||
; LARGE: [[MOVKXi4:%[0-9]+]]:gpr64 = MOVKXi [[MOVKXi3]], target-flags(aarch64-g2, aarch64-nc) @addr, 32
|
||||
; LARGE: [[MOVKXi5:%[0-9]+]]:gpr64common = MOVKXi [[MOVKXi4]], target-flags(aarch64-g3) @addr, 48
|
||||
; LARGE: STRXui [[MOVKXi2]], [[MOVKXi5]], 0 :: (store 8 into @addr)
|
||||
; LARGE: BR [[MOVKXi2]]
|
||||
; LARGE: bb.1.block (address-taken):
|
||||
; LARGE: RET_ReallyLR
|
||||
bb.1 (%ir-block.0):
|
||||
%0:gpr(p0) = G_BLOCK_ADDR blockaddress(@test_blockaddress, %ir-block.block)
|
||||
%1:gpr(p0) = G_GLOBAL_VALUE @addr
|
||||
G_STORE %0(p0), %1(p0) :: (store 8 into @addr)
|
||||
G_BRINDIRECT %0(p0)
|
||||
|
||||
bb.2.block (address-taken):
|
||||
RET_ReallyLR
|
||||
|
||||
...
|
Loading…
x
Reference in New Issue
Block a user