1 //===- MipsLegalizerInfo.cpp ------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 /// This file implements the targeting of the Machinelegalizer class for Mips.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
13 #include "MipsLegalizerInfo.h"
14 #include "MipsTargetMachine.h"
15 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
19 struct TypesAndMemOps
{
23 bool MustBeNaturallyAligned
;
27 CheckTy0Ty1MemSizeAlign(const LegalityQuery
&Query
,
28 std::initializer_list
<TypesAndMemOps
> SupportedValues
) {
29 for (auto &Val
: SupportedValues
) {
30 if (Val
.ValTy
!= Query
.Types
[0])
32 if (Val
.PtrTy
!= Query
.Types
[1])
34 if (Val
.MemSize
!= Query
.MMODescrs
[0].SizeInBits
)
36 if (Val
.MustBeNaturallyAligned
&&
37 Query
.MMODescrs
[0].SizeInBits
% Query
.MMODescrs
[0].AlignInBits
!= 0)
44 static bool CheckTyN(unsigned N
, const LegalityQuery
&Query
,
45 std::initializer_list
<LLT
> SupportedValues
) {
46 for (auto &Val
: SupportedValues
)
47 if (Val
== Query
.Types
[N
])
52 MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget
&ST
) {
53 using namespace TargetOpcode
;
55 const LLT s1
= LLT::scalar(1);
56 const LLT s32
= LLT::scalar(32);
57 const LLT s64
= LLT::scalar(64);
58 const LLT v16s8
= LLT::vector(16, 8);
59 const LLT v8s16
= LLT::vector(8, 16);
60 const LLT v4s32
= LLT::vector(4, 32);
61 const LLT v2s64
= LLT::vector(2, 64);
62 const LLT p0
= LLT::pointer(0, 32);
64 getActionDefinitionsBuilder({G_SUB
, G_MUL
})
66 .clampScalar(0, s32
, s32
);
68 getActionDefinitionsBuilder(G_ADD
)
69 .legalIf([=, &ST
](const LegalityQuery
&Query
) {
70 if (CheckTyN(0, Query
, {s32
}))
72 if (ST
.hasMSA() && CheckTyN(0, Query
, {v16s8
, v8s16
, v4s32
, v2s64
}))
76 .clampScalar(0, s32
, s32
);
78 getActionDefinitionsBuilder({G_UADDO
, G_UADDE
, G_USUBO
, G_USUBE
, G_UMULO
})
79 .lowerFor({{s32
, s1
}});
81 getActionDefinitionsBuilder(G_UMULH
)
85 getActionDefinitionsBuilder({G_LOAD
, G_STORE
})
86 .legalIf([=, &ST
](const LegalityQuery
&Query
) {
87 if (CheckTy0Ty1MemSizeAlign(Query
, {{s32
, p0
, 8, ST
.hasMips32r6()},
88 {s32
, p0
, 16, ST
.hasMips32r6()},
89 {s32
, p0
, 32, ST
.hasMips32r6()},
90 {p0
, p0
, 32, ST
.hasMips32r6()},
91 {s64
, p0
, 64, ST
.hasMips32r6()}}))
94 CheckTy0Ty1MemSizeAlign(Query
, {{v16s8
, p0
, 128, false},
95 {v8s16
, p0
, 128, false},
96 {v4s32
, p0
, 128, false},
97 {v2s64
, p0
, 128, false}}))
103 getActionDefinitionsBuilder(G_IMPLICIT_DEF
)
104 .legalFor({s32
, s64
});
106 getActionDefinitionsBuilder(G_UNMERGE_VALUES
)
107 .legalFor({{s32
, s64
}});
109 getActionDefinitionsBuilder(G_MERGE_VALUES
)
110 .legalFor({{s64
, s32
}});
112 getActionDefinitionsBuilder({G_ZEXTLOAD
, G_SEXTLOAD
})
113 .legalForTypesWithMemDesc({{s32
, p0
, 8, 8},
115 .clampScalar(0, s32
, s32
);
117 getActionDefinitionsBuilder({G_ZEXT
, G_SEXT
})
118 .legalIf([](const LegalityQuery
&Query
) { return false; })
121 getActionDefinitionsBuilder(G_TRUNC
)
122 .legalIf([](const LegalityQuery
&Query
) { return false; })
125 getActionDefinitionsBuilder(G_SELECT
)
126 .legalForCartesianProduct({p0
, s32
, s64
}, {s32
})
130 getActionDefinitionsBuilder(G_BRCOND
)
134 getActionDefinitionsBuilder(G_BRJT
)
135 .legalFor({{p0
, s32
}});
137 getActionDefinitionsBuilder(G_BRINDIRECT
)
140 getActionDefinitionsBuilder(G_PHI
)
141 .legalFor({p0
, s32
, s64
})
144 getActionDefinitionsBuilder({G_AND
, G_OR
, G_XOR
})
146 .clampScalar(0, s32
, s32
);
148 getActionDefinitionsBuilder({G_SDIV
, G_SREM
, G_UREM
, G_UDIV
})
153 getActionDefinitionsBuilder({G_SHL
, G_ASHR
, G_LSHR
})
154 .legalFor({{s32
, s32
}})
155 .clampScalar(1, s32
, s32
)
156 .clampScalar(0, s32
, s32
);
158 getActionDefinitionsBuilder(G_ICMP
)
159 .legalForCartesianProduct({s32
}, {s32
, p0
})
160 .clampScalar(1, s32
, s32
)
163 getActionDefinitionsBuilder(G_CONSTANT
)
165 .clampScalar(0, s32
, s32
);
167 getActionDefinitionsBuilder({G_GEP
, G_INTTOPTR
})
168 .legalFor({{p0
, s32
}});
170 getActionDefinitionsBuilder(G_PTRTOINT
)
171 .legalFor({{s32
, p0
}});
173 getActionDefinitionsBuilder(G_FRAME_INDEX
)
176 getActionDefinitionsBuilder({G_GLOBAL_VALUE
, G_JUMP_TABLE
})
179 getActionDefinitionsBuilder(G_DYN_STACKALLOC
)
180 .lowerFor({{p0
, s32
}});
182 getActionDefinitionsBuilder(G_VASTART
)
186 getActionDefinitionsBuilder(G_FCONSTANT
)
187 .legalFor({s32
, s64
});
189 getActionDefinitionsBuilder({G_FADD
, G_FSUB
, G_FMUL
, G_FDIV
, G_FABS
, G_FSQRT
})
190 .legalFor({s32
, s64
});
192 getActionDefinitionsBuilder(G_FCMP
)
193 .legalFor({{s32
, s32
}, {s32
, s64
}})
196 getActionDefinitionsBuilder({G_FCEIL
, G_FFLOOR
})
197 .libcallFor({s32
, s64
});
199 getActionDefinitionsBuilder(G_FPEXT
)
200 .legalFor({{s64
, s32
}});
202 getActionDefinitionsBuilder(G_FPTRUNC
)
203 .legalFor({{s32
, s64
}});
205 // FP to int conversion instructions
206 getActionDefinitionsBuilder(G_FPTOSI
)
207 .legalForCartesianProduct({s32
}, {s64
, s32
})
208 .libcallForCartesianProduct({s64
}, {s64
, s32
})
211 getActionDefinitionsBuilder(G_FPTOUI
)
212 .libcallForCartesianProduct({s64
}, {s64
, s32
})
213 .lowerForCartesianProduct({s32
}, {s64
, s32
})
216 // Int to FP conversion instructions
217 getActionDefinitionsBuilder(G_SITOFP
)
218 .legalForCartesianProduct({s64
, s32
}, {s32
})
219 .libcallForCartesianProduct({s64
, s32
}, {s64
})
222 getActionDefinitionsBuilder(G_UITOFP
)
223 .libcallForCartesianProduct({s64
, s32
}, {s64
})
224 .customForCartesianProduct({s64
, s32
}, {s32
})
227 getActionDefinitionsBuilder(G_SEXT_INREG
).lower();
230 verify(*ST
.getInstrInfo());
233 bool MipsLegalizerInfo::legalizeCustom(MachineInstr
&MI
,
234 MachineRegisterInfo
&MRI
,
235 MachineIRBuilder
&MIRBuilder
,
236 GISelChangeObserver
&Observer
) const {
238 using namespace TargetOpcode
;
240 MIRBuilder
.setInstr(MI
);
241 const MipsSubtarget
&STI
=
242 static_cast<const MipsSubtarget
&>(MIRBuilder
.getMF().getSubtarget());
243 const LLT s32
= LLT::scalar(32);
244 const LLT s64
= LLT::scalar(64);
246 switch (MI
.getOpcode()) {
248 Register Dst
= MI
.getOperand(0).getReg();
249 Register Src
= MI
.getOperand(1).getReg();
250 LLT DstTy
= MRI
.getType(Dst
);
251 LLT SrcTy
= MRI
.getType(Src
);
255 if (DstTy
!= s32
&& DstTy
!= s64
)
258 // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert
259 // unsigned to double. Mantissa has 52 bits so we use following trick:
260 // First make floating point bit mask 0x43300000ABCDEFGH.
261 // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 .
262 // Next, subtract 2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it.
263 // Done. Trunc double to float if needed.
265 MachineInstrBuilder Bitcast
= MIRBuilder
.buildInstr(
266 STI
.isFP64bit() ? Mips::BuildPairF64_64
: Mips::BuildPairF64
, {s64
},
267 {Src
, MIRBuilder
.buildConstant(s32
, UINT32_C(0x43300000))});
268 Bitcast
.constrainAllUses(MIRBuilder
.getTII(), *STI
.getRegisterInfo(),
269 *STI
.getRegBankInfo());
271 MachineInstrBuilder TwoP52FP
= MIRBuilder
.buildFConstant(
272 s64
, BitsToDouble(UINT64_C(0x4330000000000000)));
275 MIRBuilder
.buildFSub(Dst
, Bitcast
, TwoP52FP
);
277 MachineInstrBuilder ResF64
= MIRBuilder
.buildFSub(s64
, Bitcast
, TwoP52FP
);
278 MIRBuilder
.buildFPTrunc(Dst
, ResF64
);
281 MI
.eraseFromParent();
291 static bool SelectMSA3OpIntrinsic(MachineInstr
&MI
, unsigned Opcode
,
292 MachineIRBuilder
&MIRBuilder
,
293 const MipsSubtarget
&ST
) {
294 assert(ST
.hasMSA() && "MSA intrinsic not supported on target without MSA.");
295 if (!MIRBuilder
.buildInstr(Opcode
)
296 .add(MI
.getOperand(0))
297 .add(MI
.getOperand(2))
298 .add(MI
.getOperand(3))
299 .constrainAllUses(MIRBuilder
.getTII(), *ST
.getRegisterInfo(),
300 *ST
.getRegBankInfo()))
302 MI
.eraseFromParent();
306 static bool MSA3OpIntrinsicToGeneric(MachineInstr
&MI
, unsigned Opcode
,
307 MachineIRBuilder
&MIRBuilder
,
308 const MipsSubtarget
&ST
) {
309 assert(ST
.hasMSA() && "MSA intrinsic not supported on target without MSA.");
310 MIRBuilder
.buildInstr(Opcode
)
311 .add(MI
.getOperand(0))
312 .add(MI
.getOperand(2))
313 .add(MI
.getOperand(3));
314 MI
.eraseFromParent();
318 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr
&MI
,
319 MachineRegisterInfo
&MRI
,
320 MachineIRBuilder
&MIRBuilder
) const {
321 const MipsSubtarget
&ST
=
322 static_cast<const MipsSubtarget
&>(MI
.getMF()->getSubtarget());
323 const MipsInstrInfo
&TII
= *ST
.getInstrInfo();
324 const MipsRegisterInfo
&TRI
= *ST
.getRegisterInfo();
325 const RegisterBankInfo
&RBI
= *ST
.getRegBankInfo();
326 MIRBuilder
.setInstr(MI
);
328 switch (MI
.getIntrinsicID()) {
329 case Intrinsic::memcpy
:
330 case Intrinsic::memset
:
331 case Intrinsic::memmove
:
332 if (createMemLibcall(MIRBuilder
, MRI
, MI
) ==
333 LegalizerHelper::UnableToLegalize
)
335 MI
.eraseFromParent();
337 case Intrinsic::trap
: {
338 MachineInstr
*Trap
= MIRBuilder
.buildInstr(Mips::TRAP
);
339 MI
.eraseFromParent();
340 return constrainSelectedInstRegOperands(*Trap
, TII
, TRI
, RBI
);
342 case Intrinsic::vacopy
: {
343 Register Tmp
= MRI
.createGenericVirtualRegister(LLT::pointer(0, 32));
344 MachinePointerInfo MPO
;
345 MIRBuilder
.buildLoad(Tmp
, MI
.getOperand(2),
346 *MI
.getMF()->getMachineMemOperand(
347 MPO
, MachineMemOperand::MOLoad
, 4, 4));
348 MIRBuilder
.buildStore(Tmp
, MI
.getOperand(1),
349 *MI
.getMF()->getMachineMemOperand(
350 MPO
, MachineMemOperand::MOStore
, 4, 4));
351 MI
.eraseFromParent();
354 case Intrinsic::mips_addv_b
:
355 case Intrinsic::mips_addv_h
:
356 case Intrinsic::mips_addv_w
:
357 case Intrinsic::mips_addv_d
:
358 return MSA3OpIntrinsicToGeneric(MI
, TargetOpcode::G_ADD
, MIRBuilder
, ST
);
359 case Intrinsic::mips_addvi_b
:
360 return SelectMSA3OpIntrinsic(MI
, Mips::ADDVI_B
, MIRBuilder
, ST
);
361 case Intrinsic::mips_addvi_h
:
362 return SelectMSA3OpIntrinsic(MI
, Mips::ADDVI_H
, MIRBuilder
, ST
);
363 case Intrinsic::mips_addvi_w
:
364 return SelectMSA3OpIntrinsic(MI
, Mips::ADDVI_W
, MIRBuilder
, ST
);
365 case Intrinsic::mips_addvi_d
:
366 return SelectMSA3OpIntrinsic(MI
, Mips::ADDVI_D
, MIRBuilder
, ST
);