Skip to content

Commit

Permalink
[AArch64][GlobalISel] Import FMOV patterns rather than manually selec…
Browse files Browse the repository at this point in the history
…ting it

There are existing patterns for FMOVHi, FMOVSi, and FMOVDi in
AArch64InstrFormats.td.

Importing these allows us to remove the manual selection code for FMOV.

It also allows us to select FMOVHi for non-zero constants when we have full
fp-16 support.

Refactor some of the code in AArch64InstrFormats.td so that we can create
equivalent custom renderers in GlobalISel.

Differential Revision: https://reviews.llvm.org/D97511
  • Loading branch information
Jessica Paquette committed Feb 27, 2021
1 parent 1d7f8c7 commit f5d5a7d
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 58 deletions.
45 changes: 30 additions & 15 deletions llvm/lib/Target/AArch64/AArch64InstrFormats.td
Expand Up @@ -1155,36 +1155,44 @@ def gi_arith_extended_reg32to64_i64 :
GIComplexPatternEquiv<arith_extended_reg32to64_i64>;

// Floating-point immediate.
def fpimm16 : Operand<f16>,
FPImmLeaf<f16, [{
return AArch64_AM::getFP16Imm(Imm) != -1;
}], SDNodeXForm<fpimm, [{

def fpimm16XForm : SDNodeXForm<fpimm, [{
APFloat InVal = N->getValueAPF();
uint32_t enc = AArch64_AM::getFP16Imm(InVal);
return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i32);
}]>> {
}]>;

def fpimm32XForm : SDNodeXForm<fpimm, [{
APFloat InVal = N->getValueAPF();
uint32_t enc = AArch64_AM::getFP32Imm(InVal);
return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i32);
}]>;

def fpimm64XForm : SDNodeXForm<fpimm, [{
APFloat InVal = N->getValueAPF();
uint32_t enc = AArch64_AM::getFP64Imm(InVal);
return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i32);
}]>;

def fpimm16 : Operand<f16>,
FPImmLeaf<f16, [{
return AArch64_AM::getFP16Imm(Imm) != -1;
}], fpimm16XForm> {
let ParserMatchClass = FPImmOperand;
let PrintMethod = "printFPImmOperand";
}

def fpimm32 : Operand<f32>,
FPImmLeaf<f32, [{
return AArch64_AM::getFP32Imm(Imm) != -1;
}], SDNodeXForm<fpimm, [{
APFloat InVal = N->getValueAPF();
uint32_t enc = AArch64_AM::getFP32Imm(InVal);
return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i32);
}]>> {
}], fpimm32XForm> {
let ParserMatchClass = FPImmOperand;
let PrintMethod = "printFPImmOperand";
}
def fpimm64 : Operand<f64>,
FPImmLeaf<f64, [{
return AArch64_AM::getFP64Imm(Imm) != -1;
}], SDNodeXForm<fpimm, [{
APFloat InVal = N->getValueAPF();
uint32_t enc = AArch64_AM::getFP64Imm(InVal);
return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i32);
}]>> {
}], fpimm64XForm> {
let ParserMatchClass = FPImmOperand;
let PrintMethod = "printFPImmOperand";
}
Expand All @@ -1198,6 +1206,13 @@ def fpimm0 : FPImmLeaf<fAny, [{
return Imm.isExactlyValue(+0.0);
}]>;

def gi_fpimm16 : GICustomOperandRenderer<"renderFPImm16">,
GISDNodeXFormEquiv<fpimm16XForm>;
def gi_fpimm32 : GICustomOperandRenderer<"renderFPImm32">,
GISDNodeXFormEquiv<fpimm32XForm>;
def gi_fpimm64 : GICustomOperandRenderer<"renderFPImm64">,
GISDNodeXFormEquiv<fpimm64XForm>;

// Vector lane operands
class AsmVectorIndex<int Min, int Max, string NamePrefix=""> : AsmOperandClass {
let Name = NamePrefix # "IndexRange" # Min # "_" # Max;
Expand Down
76 changes: 33 additions & 43 deletions llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
Expand Up @@ -244,12 +244,6 @@ class AArch64InstructionSelector : public InstructionSelector {
Register VecReg, unsigned LaneIdx,
MachineIRBuilder &MIRBuilder) const;

/// Helper function for selecting G_FCONSTANT. If the G_FCONSTANT can be
/// materialized using a FMOV instruction, then update MI and return it.
/// Otherwise, do nothing and return a nullptr.
MachineInstr *emitFMovForFConstant(MachineInstr &MI,
MachineRegisterInfo &MRI) const;

/// Emit a CSet for an integer compare.
///
/// \p DefReg and \p SrcReg are expected to be 32-bit scalar registers.
Expand Down Expand Up @@ -393,6 +387,12 @@ class AArch64InstructionSelector : public InstructionSelector {
int OpIdx = -1) const;
void renderLogicalImm64(MachineInstrBuilder &MIB, const MachineInstr &I,
int OpIdx = -1) const;
void renderFPImm16(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx = -1) const;
void renderFPImm32(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx = -1) const;
void renderFPImm64(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx = -1) const;

// Materialize a GlobalValue or BlockAddress using a movz+movk sequence.
void materializeLargeCMVal(MachineInstr &I, const Value *V,
Expand Down Expand Up @@ -2425,10 +2425,6 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
: (DefSize == 64 ? AArch64::FPR64RegClass
: AArch64::FPR128RegClass);

// Can we use a FMOV instruction to represent the immediate?
if (emitFMovForFConstant(I, MRI))
return true;

// For 64b values, emit a constant pool load instead.
if (DefSize == 64 || DefSize == 128) {
auto *FPImm = I.getOperand(1).getFPImm();
Expand Down Expand Up @@ -4387,39 +4383,6 @@ MachineInstr *AArch64InstructionSelector::emitVectorConcat(
return &*InsElt;
}

MachineInstr *AArch64InstructionSelector::emitFMovForFConstant(
MachineInstr &I, MachineRegisterInfo &MRI) const {
assert(I.getOpcode() == TargetOpcode::G_FCONSTANT &&
"Expected a G_FCONSTANT!");
MachineOperand &ImmOp = I.getOperand(1);
unsigned DefSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();

// Only handle 32 and 64 bit defs for now.
if (DefSize != 32 && DefSize != 64)
return nullptr;

// Don't handle null values using FMOV.
if (ImmOp.getFPImm()->isNullValue())
return nullptr;

// Get the immediate representation for the FMOV.
const APFloat &ImmValAPF = ImmOp.getFPImm()->getValueAPF();
int Imm = DefSize == 32 ? AArch64_AM::getFP32Imm(ImmValAPF)
: AArch64_AM::getFP64Imm(ImmValAPF);

// If this is -1, it means the immediate can't be represented as the requested
// floating point value. Bail.
if (Imm == -1)
return nullptr;

// Update MI to represent the new FMOV instruction, constrain it, and return.
ImmOp.ChangeToImmediate(Imm);
unsigned MovOpc = DefSize == 32 ? AArch64::FMOVSi : AArch64::FMOVDi;
I.setDesc(TII.get(MovOpc));
constrainSelectedInstRegOperands(I, TII, TRI, RBI);
return &I;
}

MachineInstr *
AArch64InstructionSelector::emitCSetForICMP(Register DefReg, unsigned Pred,
MachineIRBuilder &MIRBuilder,
Expand Down Expand Up @@ -5965,6 +5928,33 @@ void AArch64InstructionSelector::renderLogicalImm64(
MIB.addImm(Enc);
}

void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
"Expected G_FCONSTANT");
MIB.addImm(
AArch64_AM::getFP16Imm(MI.getOperand(1).getFPImm()->getValueAPF()));
}

void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
"Expected G_FCONSTANT");
MIB.addImm(
AArch64_AM::getFP32Imm(MI.getOperand(1).getFPImm()->getValueAPF()));
}

void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
"Expected G_FCONSTANT");
MIB.addImm(
AArch64_AM::getFP64Imm(MI.getOperand(1).getFPImm()->getValueAPF()));
}

bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
const MachineInstr &MI, unsigned NumBytes) const {
if (!MI.mayLoadOrStore())
Expand Down
15 changes: 15 additions & 0 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-fp16-fconstant.mir
Expand Up @@ -15,3 +15,18 @@ body: |
%0:fpr(s16) = G_FCONSTANT half 0.0
$h0 = COPY %0(s16)
RET_ReallyLR implicit $h0
...
---
name: one
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
; CHECK-LABEL: name: one
; CHECK: [[FMOVHi:%[0-9]+]]:fpr16 = FMOVHi 112
; CHECK: $h0 = COPY [[FMOVHi]]
; CHECK: RET_ReallyLR implicit $h0
%0:fpr(s16) = G_FCONSTANT half 1.0
$h0 = COPY %0(s16)
RET_ReallyLR implicit $h0

0 comments on commit f5d5a7d

Please sign in to comment.