Skip to content

Commit 3b32d6e

Browse files
authored
[X86][GlobalISel] Support fp80 for G_FPTRUNC and G_FPEXT (#141611)
Introduce `G_FPEXTLOAD` and `G_FPTRUNCSTORE` for extending load and truncating store of a floating point value. * Introduce `IfFPExtend` and `IfFPTrunc` into `GINodeEquiv` to dispatch SDAG patterns to the newly introduced opcodes similarly to `G_SEXTLOAD` and `G_ZEXTLOAD`. * Added narrowing and widening for the opcodes. However they aren't used anywhere. * Supported lowering of `G_FPEXTLOAD` and `G_FPTRUNCSTORE` for X86 by using X87. * Added `lowerFPExtAndTruncMem` as default lowering for `G_FPTRUNC` and `G_FPEXT` using memory. * Dropped autogenerated line from `legalizer-info-validation.mir` as scripts can't update them anymore. * Updated `match-table-cxx.td` with regexps. This is not the first PR that updates the whole test after opcode introduction.
1 parent c4fc27c commit 3b32d6e

25 files changed

Lines changed: 688 additions & 128 deletions

llvm/docs/GlobalISel/GenericOpcode.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,21 @@ Unlike in SelectionDAG, atomic loads are expressed with the same
930930
opcodes as regular loads. G_LOAD, G_SEXTLOAD and G_ZEXTLOAD may all
931931
have atomic memory operands.
932932

933+
G_FPEXTLOAD
934+
^^^^^^^^^^^
935+
936+
Generic floating-point extending load. Expects a MachineMemOperand in addition
937+
to explicit operands. Loads a floating-point value from memory and extends it
938+
to a larger floating-point type.
939+
940+
The memory size must be smaller than the result type. For example, loading an
941+
f32 value from memory and extending it to f64, or loading an f16 value and
942+
extending it to f32.
943+
944+
.. code-block:: none
945+
946+
%1:_(s64) = G_FPEXTLOAD %0:_(p0) :: (load (s32))
947+
933948
G_INDEXED_LOAD
934949
^^^^^^^^^^^^^^
935950

@@ -956,6 +971,21 @@ the high bits are implicitly truncated. If this is a vector store, the
956971
high elements are discarded (i.e. this does not function as a per-lane
957972
vector, truncating store)
958973

974+
G_FPTRUNCSTORE
975+
^^^^^^^^^^^^^^
976+
977+
Generic floating-point truncating store. Expects a MachineMemOperand in
978+
addition to explicit operands. Truncates a floating-point value to a smaller
979+
floating-point type and stores it to memory.
980+
981+
The memory size must be smaller than the source value type. For example,
982+
truncating an f64 value to f32 and storing it, or truncating an f32 value
983+
to f16 and storing it.
984+
985+
.. code-block:: none
986+
987+
G_FPTRUNCSTORE %0:_(s64), %1:_(p0) :: (store (s32))
988+
959989
G_INDEXED_STORE
960990
^^^^^^^^^^^^^^^
961991

llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class GMemOperation : public GenericMachineInstr {
8080
};
8181

8282
/// Represents any type of generic load or store.
83-
/// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD.
83+
/// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD, G_FPEXTLOAD, G_FPTRUNCSTORE.
8484
class GLoadStore : public GMemOperation {
8585
public:
8686
/// Get the source register of the pointer value.
@@ -92,6 +92,8 @@ class GLoadStore : public GMemOperation {
9292
case TargetOpcode::G_STORE:
9393
case TargetOpcode::G_ZEXTLOAD:
9494
case TargetOpcode::G_SEXTLOAD:
95+
case TargetOpcode::G_FPEXTLOAD:
96+
case TargetOpcode::G_FPTRUNCSTORE:
9597
return true;
9698
default:
9799
return false;
@@ -197,6 +199,7 @@ class GAnyLoad : public GLoadStore {
197199
case TargetOpcode::G_LOAD:
198200
case TargetOpcode::G_ZEXTLOAD:
199201
case TargetOpcode::G_SEXTLOAD:
202+
case TargetOpcode::G_FPEXTLOAD:
200203
return true;
201204
default:
202205
return false;
@@ -212,12 +215,13 @@ class GLoad : public GAnyLoad {
212215
}
213216
};
214217

215-
/// Represents either a G_SEXTLOAD or G_ZEXTLOAD.
218+
/// Represents either a G_SEXTLOAD, G_ZEXTLOAD, or G_FPEXTLOAD.
216219
class GExtLoad : public GAnyLoad {
217220
public:
218221
static bool classof(const MachineInstr *MI) {
219222
return MI->getOpcode() == TargetOpcode::G_SEXTLOAD ||
220-
MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
223+
MI->getOpcode() == TargetOpcode::G_ZEXTLOAD ||
224+
MI->getOpcode() == TargetOpcode::G_FPEXTLOAD;
221225
}
222226
};
223227

@@ -237,17 +241,47 @@ class GZExtLoad : public GExtLoad {
237241
}
238242
};
239243

240-
/// Represents a G_STORE.
241-
class GStore : public GLoadStore {
244+
/// Represents a G_FPEXTLOAD.
245+
class GFPExtLoad : public GAnyLoad {
246+
public:
247+
static bool classof(const MachineInstr *MI) {
248+
return MI->getOpcode() == TargetOpcode::G_FPEXTLOAD;
249+
}
250+
};
251+
252+
/// Represents any generic store, including truncating variants.
253+
class GAnyStore : public GLoadStore {
242254
public:
243255
/// Get the stored value register.
244256
Register getValueReg() const { return getOperand(0).getReg(); }
245257

258+
static bool classof(const MachineInstr *MI) {
259+
switch (MI->getOpcode()) {
260+
case TargetOpcode::G_STORE:
261+
case TargetOpcode::G_FPTRUNCSTORE:
262+
return true;
263+
default:
264+
return false;
265+
}
266+
}
267+
};
268+
269+
/// Represents a G_STORE.
270+
class GStore : public GAnyStore {
271+
public:
246272
static bool classof(const MachineInstr *MI) {
247273
return MI->getOpcode() == TargetOpcode::G_STORE;
248274
}
249275
};
250276

277+
/// Represents a G_FPTRUNCSTORE.
278+
class GFPTruncStore : public GAnyStore {
279+
public:
280+
static bool classof(const MachineInstr *MI) {
281+
return MI->getOpcode() == TargetOpcode::G_FPTRUNCSTORE;
282+
}
283+
};
284+
251285
/// Represents a G_UNMERGE_VALUES.
252286
class GUnmerge : public GenericMachineInstr {
253287
public:

llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ class LegalizerHelper {
523523
LLVM_ABI LegalizeResult lowerFPTOSI(MachineInstr &MI);
524524
LLVM_ABI LegalizeResult lowerFPTOINT_SAT(MachineInstr &MI);
525525

526+
LLVM_ABI LegalizeResult lowerFPExtAndTruncMem(MachineInstr &MI);
526527
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_F16(MachineInstr &MI);
527528
LLVM_ABI LegalizeResult lowerFPTRUNC_F32_TO_BF16(MachineInstr &MI);
528529
LLVM_ABI LegalizeResult lowerFPTRUNC(MachineInstr &MI);

llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,15 @@ class LegalizeRuleSet {
685685
LegalityPredicates::typePairAndMemDescInSet(
686686
typeIdx(0), typeIdx(1), /*MMOIdx*/ 0, TypesAndMemDesc));
687687
}
688+
LegalizeRuleSet &legalForTypesWithMemDesc(
689+
bool Pred, std::initializer_list<LegalityPredicates::TypePairAndMemDesc>
690+
TypesAndMemDesc) {
691+
if (!Pred)
692+
return *this;
693+
return actionIf(LegalizeAction::Legal,
694+
LegalityPredicates::typePairAndMemDescInSet(
695+
typeIdx(0), typeIdx(1), /*MMOIdx=*/0, TypesAndMemDesc));
696+
}
688697
/// The instruction is legal when type indexes 0 and 1 are both in the given
689698
/// list. That is, the type pair is in the cartesian product of the list.
690699
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types) {

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,19 @@ class LLVM_ABI MachineIRBuilder {
10831083
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr,
10841084
MachineMemOperand &MMO);
10851085

1086+
/// Build and insert `<opcode> Val, Addr, MMO`.
1087+
///
1088+
/// Stores the value \p Val to \p Addr.
1089+
///
1090+
/// \pre setBasicBlock or setMI must have been called.
1091+
/// \pre \p Val must be a generic virtual register.
1092+
/// \pre \p Addr must be a generic virtual register with pointer type.
1093+
///
1094+
/// \return a MachineInstrBuilder for the newly created instruction.
1095+
MachineInstrBuilder buildStoreInstr(unsigned Opcode, const SrcOp &Val,
1096+
const SrcOp &Addr,
1097+
MachineMemOperand &MMO);
1098+
10861099
/// Build and insert a G_STORE instruction, while constructing the
10871100
/// MachineMemOperand.
10881101
MachineInstrBuilder

llvm/include/llvm/Support/TargetOpcodes.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,9 @@ HANDLE_TARGET_OPCODE(G_SEXTLOAD)
409409
/// Generic zeroext load
410410
HANDLE_TARGET_OPCODE(G_ZEXTLOAD)
411411

412+
/// Generic floating-point extending load
413+
HANDLE_TARGET_OPCODE(G_FPEXTLOAD)
414+
412415
/// Generic indexed load (including anyext load)
413416
HANDLE_TARGET_OPCODE(G_INDEXED_LOAD)
414417

@@ -421,6 +424,9 @@ HANDLE_TARGET_OPCODE(G_INDEXED_ZEXTLOAD)
421424
/// Generic store.
422425
HANDLE_TARGET_OPCODE(G_STORE)
423426

427+
/// Generic floating-point truncating store
428+
HANDLE_TARGET_OPCODE(G_FPTRUNCSTORE)
429+
424430
/// Generic indexed store.
425431
HANDLE_TARGET_OPCODE(G_INDEXED_STORE)
426432

llvm/include/llvm/Target/GenericOpcodes.td

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,15 @@ def G_ZEXTLOAD : GenericInstruction {
13611361
let mayLoad = true;
13621362
}
13631363

1364+
// Generic floating-point extending load. Expects a MachineMemOperand in
1365+
// addition to explicit operands.
1366+
def G_FPEXTLOAD : GenericInstruction {
1367+
let OutOperandList = (outs type0:$dst);
1368+
let InOperandList = (ins ptype1:$addr);
1369+
let hasSideEffects = false;
1370+
let mayLoad = true;
1371+
}
1372+
13641373
// Generic indexed load. Combines a GEP with a load. $newaddr is set to $base + $offset.
13651374
// If $am is 0 (post-indexed), then the value is loaded from $base; if $am is 1 (pre-indexed)
13661375
// then the value is loaded from $newaddr.
@@ -1397,6 +1406,15 @@ def G_STORE : GenericInstruction {
13971406
let GISelMatchGenericTypes = 1;
13981407
}
13991408

1409+
// Generic floating-point truncating store. Expects a MachineMemOperand in
1410+
// addition to explicit operands.
1411+
def G_FPTRUNCSTORE : GenericInstruction {
1412+
let OutOperandList = (outs);
1413+
let InOperandList = (ins type0:$src, ptype1:$addr);
1414+
let hasSideEffects = false;
1415+
let mayStore = true;
1416+
}
1417+
14001418
// Combines a store with a GEP. See description of G_INDEXED_LOAD for indexing behaviour.
14011419
def G_INDEXED_STORE : GenericInstruction {
14021420
let OutOperandList = (outs ptype0:$newaddr);

llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ class GINodeEquiv<Instruction i, SDNode node> {
3535
// depending on the predicates on the node.
3636
Instruction IfSignExtend = ?;
3737
Instruction IfZeroExtend = ?;
38+
// In contrast to SelectionDAG we would like not to overload an anyext load
39+
// for floating point truncation and extending stores and loads. Instead we
40+
// assign separate opcodes for it.
41+
Instruction IfFPExtend = ?;
42+
Instruction IfFPTrunc = ?;
3843

3944
// SelectionDAG has one setcc for all compares. This differentiates
4045
// for G_ICMP and G_FCMP.
@@ -236,6 +241,7 @@ def : GINodeEquiv<G_LOAD, ld> {
236241
let CheckMMOIsNonAtomic = true;
237242
let IfSignExtend = G_SEXTLOAD;
238243
let IfZeroExtend = G_ZEXTLOAD;
244+
let IfFPExtend = G_FPEXTLOAD;
239245
}
240246

241247
def : GINodeEquiv<G_ICMP, setcc> {
@@ -249,7 +255,11 @@ def : GINodeEquiv<G_ICMP, setcc> {
249255
// G_STORE handles both atomic and non-atomic stores where as SelectionDAG had
250256
// separate nodes for them. This GINodeEquiv maps the non-atomic stores to
251257
// G_STORE with a non-atomic MachineMemOperand.
252-
def : GINodeEquiv<G_STORE, st> { let CheckMMOIsNonAtomic = true; }
258+
def : GINodeEquiv<G_STORE, st> {
259+
let CheckMMOIsNonAtomic = true;
260+
let IfFPTrunc = G_FPTRUNCSTORE;
261+
}
262+
253263
def : GINodeEquiv<G_STORE, atomic_store> {
254264
let CheckMMOIsNonAtomic = false;
255265
let CheckMMOIsAtomic = true;

0 commit comments

Comments
 (0)