Skip to content
Merged
13 changes: 12 additions & 1 deletion llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class X86InstructionSelector : public InstructionSelector {
unsigned getPtrLoadStoreOp(const LLT &Ty, const RegisterBank &RB,
unsigned Opc) const;

bool checkMemoryOpSize(const MachineInstr &MI, unsigned NumBytes) const;

bool selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI,
MachineFunction &MF) const;
bool selectFrameIndexOrGep(MachineInstr &I, MachineRegisterInfo &MRI,
Expand Down Expand Up @@ -355,6 +357,15 @@ bool X86InstructionSelector::selectCopy(MachineInstr &I,
return true;
}

bool X86InstructionSelector::checkMemoryOpSize(const MachineInstr &MI,
unsigned NumBytes) const {
if (!MI.mayLoadOrStore())
return false;
assert(MI.hasOneMemOperand() &&
"Expected load/store to have only one mem op!");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the use context I would expect MI.mayLoadOrStore to be implied

return (*MI.memoperands_begin())->getSize() == NumBytes;
}

bool X86InstructionSelector::select(MachineInstr &I) {
assert(I.getParent() && "Instruction should be in a basic block!");
assert(I.getParent()->getParent() && "Instruction should be in a function!");
Expand All @@ -364,7 +375,7 @@ bool X86InstructionSelector::select(MachineInstr &I) {
MachineRegisterInfo &MRI = MF.getRegInfo();

unsigned Opcode = I.getOpcode();
if (!isPreISelGenericOpcode(Opcode)) {
if (!isPreISelGenericOpcode(Opcode) && !I.isPreISelOpcode()) {
// Certain non-generic instructions also need some special handling.

if (Opcode == TargetOpcode::LOAD_STACK_GUARD)
Expand Down
92 changes: 89 additions & 3 deletions llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/DerivedTypes.h"
Expand Down Expand Up @@ -498,7 +499,16 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
(typePairInSet(0, 1, {{s64, s32}})(Query) ||
(Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
})
.clampScalar(1, s32, sMaxScalar)
.customIf([=](const LegalityQuery &Query) -> bool {
if (!UseX87)
return false;
if ((typeIs(0, s32)(Query) && HasSSE1) ||
(typeIs(0, s64)(Query) && HasSSE2))
return false;
return typeInSet(0, {s32, s64, s80})(Query) &&
typeInSet(1, {s16, s32, s64})(Query);
})
.clampScalar(1, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
.widenScalarToNextPow2(1)
.clampScalar(0, s32, HasSSE2 ? s64 : s32)
.widenScalarToNextPow2(0);
Expand All @@ -512,9 +522,18 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
(typePairInSet(0, 1, {{s32, s64}})(Query) ||
(Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
})
.clampScalar(1, s32, HasSSE2 ? s64 : s32)
.customIf([=](const LegalityQuery &Query) -> bool {
if (!UseX87)
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the new format that pulls the predicate out of the legality query?

if ((typeIs(1, s32)(Query) && HasSSE1) ||
(typeIs(1, s64)(Query) && HasSSE2))
return false;
return typeInSet(0, {s16, s32, s64})(Query) &&
typeInSet(1, {s32, s64, s80})(Query);
})
.clampScalar(0, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
.widenScalarToNextPow2(0)
.clampScalar(0, s32, sMaxScalar)
.clampScalar(1, s32, HasSSE2 ? s64 : s32)
.widenScalarToNextPow2(1);

// For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
Expand Down Expand Up @@ -671,10 +690,77 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
return legalizeUITOFP(MI, MRI, Helper);
case TargetOpcode::G_STORE:
return legalizeNarrowingStore(MI, MRI, Helper);
case TargetOpcode::G_SITOFP:
return legalizeSITOFP(MI, MRI, Helper);
case TargetOpcode::G_FPTOSI:
return legalizeFPTOSI(MI, MRI, Helper);
}
llvm_unreachable("expected switch to return");
}

bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const {
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
MachineFunction &MF = *MI.getMF();
auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();

assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
SrcTy.getSizeInBits() == 64) &&
"Unexpected source type for SITOFP in X87 mode.");

const LLT p0 = LLT::pointer(0, MF.getTarget().getPointerSizeInBits(0));
int MemSize = SrcTy.getSizeInBytes();
int StackSlot =
MF.getFrameInfo().CreateStackObject(MemSize, Align(MemSize), false);

auto SlotPointer = MIRBuilder.buildFrameIndex(p0, StackSlot);
MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(MF, StackSlot);
MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use LegalizerHelper::createStackTemporary?


// Store the integer value on the FPU stack.
MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);

MachineMemOperand *LoadMMO = MF.getMachineMemOperand(
PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
MIRBuilder.buildInstr(X86::G_FILD)
.addDef(Dst)
.addUse(SlotPointer.getReg(0))
.addMemOperand(LoadMMO);

MI.eraseFromParent();
return true;
}

bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const {
MachineFunction &MF = *MI.getMF();
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
const LLT p0 = LLT::pointer(0, MF.getTarget().getPointerSizeInBits(0));
auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();

unsigned MemSize = DstTy.getSizeInBytes();
int StackSlot =
MF.getFrameInfo().CreateStackObject(MemSize, Align(MemSize), false);

auto SlotPointer = MIRBuilder.buildFrameIndex(p0, StackSlot);

MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(MF, StackSlot);
MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto


MIRBuilder.buildInstr(X86::G_FIST)
.addUse(Src)
.addUse(SlotPointer.getReg(0))
.addMemOperand(StoreMMO);

MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
MI.eraseFromParent();
return true;
}

bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const {
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ class X86LegalizerInfo : public LegalizerInfo {

bool legalizeNarrowingStore(MachineInstr &MI, MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const;

bool legalizeSITOFP(MachineInstr &MI, MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const;

bool legalizeFPTOSI(MachineInstr &MI, MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const;
};
} // namespace llvm
#endif
12 changes: 12 additions & 0 deletions llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ bool X86RegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
case TargetOpcode::G_FPTOSI:
case TargetOpcode::G_FPTOUI:
case TargetOpcode::G_FCMP:
case X86::G_FIST:
case TargetOpcode::G_LROUND:
case TargetOpcode::G_LLROUND:
case TargetOpcode::G_INTRINSIC_TRUNC:
Expand All @@ -129,6 +130,7 @@ bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
switch (MI.getOpcode()) {
case TargetOpcode::G_SITOFP:
case TargetOpcode::G_UITOFP:
case X86::G_FILD:
return true;
default:
break;
Expand Down Expand Up @@ -296,6 +298,16 @@ X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
// VECRReg)
getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
break;
case X86::G_FIST:
case X86::G_FILD: {
auto &Op0 = MI.getOperand(0);
auto &Op1 = MI.getOperand(1);
const LLT Ty0 = MRI.getType(Op0.getReg());
const LLT Ty1 = MRI.getType(Op1.getReg());
OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ true);
OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ false);
break;
}
case TargetOpcode::G_SITOFP:
case TargetOpcode::G_FPTOSI:
case TargetOpcode::G_UITOFP:
Expand Down
28 changes: 22 additions & 6 deletions llvm/lib/Target/X86/X86InstrFragments.td
Original file line number Diff line number Diff line change
Expand Up @@ -841,13 +841,21 @@ def X86fldf80 : PatFrag<(ops node:$ptr), (X86fld node:$ptr), [{

def X86fild16 : PatFrag<(ops node:$ptr), (X86fild node:$ptr), [{
return cast<MemIntrinsicSDNode>(N)->getMemoryVT() == MVT::i16;
}]>;
}]> {
let GISelPredicateCode = [{ return checkMemoryOpSize(MI, 2); }];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do this in terms of LLT instead of the byte size, like the dag version

}

def X86fild32 : PatFrag<(ops node:$ptr), (X86fild node:$ptr), [{
return cast<MemIntrinsicSDNode>(N)->getMemoryVT() == MVT::i32;
}]>;
}]> {
let GISelPredicateCode = [{ return checkMemoryOpSize(MI, 4); }];
}

def X86fild64 : PatFrag<(ops node:$ptr), (X86fild node:$ptr), [{
return cast<MemIntrinsicSDNode>(N)->getMemoryVT() == MVT::i64;
}]>;
}]> {
let GISelPredicateCode = [{ return checkMemoryOpSize(MI, 8); }];
}

def X86fist32 : PatFrag<(ops node:$val, node:$ptr),
(X86fist node:$val, node:$ptr), [{
Expand All @@ -862,15 +870,23 @@ def X86fist64 : PatFrag<(ops node:$val, node:$ptr),
def X86fp_to_i16mem : PatFrag<(ops node:$val, node:$ptr),
(X86fp_to_mem node:$val, node:$ptr), [{
return cast<MemIntrinsicSDNode>(N)->getMemoryVT() == MVT::i16;
}]>;
}]> {
let GISelPredicateCode = [{ return checkMemoryOpSize(MI, 2); }];
}

def X86fp_to_i32mem : PatFrag<(ops node:$val, node:$ptr),
(X86fp_to_mem node:$val, node:$ptr), [{
return cast<MemIntrinsicSDNode>(N)->getMemoryVT() == MVT::i32;
}]>;
}]> {
let GISelPredicateCode = [{ return checkMemoryOpSize(MI, 4); }];
}

def X86fp_to_i64mem : PatFrag<(ops node:$val, node:$ptr),
(X86fp_to_mem node:$val, node:$ptr), [{
return cast<MemIntrinsicSDNode>(N)->getMemoryVT() == MVT::i64;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected that we don't need SDAG predicate as well, do we?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The memory type should replace this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that should be done in a separate PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with both options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I will address this in a separate PR.

}]>;
}]> {
let GISelPredicateCode = [{ return checkMemoryOpSize(MI, 8); }];
}

//===----------------------------------------------------------------------===//
// FPStack pattern fragments
Expand Down
31 changes: 31 additions & 0 deletions llvm/lib/Target/X86/X86InstrGISel.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===- X86InstrGISel.td - X86 GISel target specific opcodes -*- tablegen -*===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// X86 GlobalISel target pseudo instruction definitions. This is kept
// separately from the other tablegen files for organizational purposes, but
// share the same infrastructure.
//
//===----------------------------------------------------------------------===//

class X86GenericInstruction : GenericInstruction { let Namespace = "X86"; }

def G_FILD : X86GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins ptype1:$src);
let hasSideEffects = false;
let mayLoad = true;
}
def G_FIST : X86GenericInstruction {
let OutOperandList = (outs);
let InOperandList = (ins type0:$src1, ptype1:$src2);
let hasSideEffects = false;
let mayStore = true;
}

def : GINodeEquiv<G_FILD, X86fild>;
def : GINodeEquiv<G_FIST, X86fp_to_mem>;
5 changes: 5 additions & 0 deletions llvm/lib/Target/X86/X86InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ include "X86InstrFormats.td"
//
include "X86InstrUtils.td"

//===----------------------------------------------------------------------===//
// Global ISel
//
include "X86InstrGISel.td"

//===----------------------------------------------------------------------===//
// Subsystems.
//===----------------------------------------------------------------------===//
Expand Down
Loading
Loading