OLD | NEW |
---|---|
(Empty) | |
1 //===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=// | |
2 // | |
3 // The Subzero Code Generator | |
4 // | |
5 // This file is distributed under the University of Illinois Open Source | |
6 // License. See LICENSE.TXT for details. | |
7 // | |
8 //===----------------------------------------------------------------------===// | |
9 // | |
10 // This file implements the InstX86Base and OperandX86Base template classes that | |
11 // are shared accross all x86 targets. | |
jvoung (off chromium)
2015/07/06 18:58:45
accross -> across
John
2015/07/06 22:30:09
Done.
| |
12 // | |
13 //===----------------------------------------------------------------------===// | |
14 | |
15 #ifndef SUBZERO_SRC_ICEINSTX86BASEIMPL_H | |
16 #define SUBZERO_SRC_ICEINSTX86BASEIMPL_H | |
17 | |
18 #include "IceInstX86Base.h" | |
19 | |
20 #include "IceAssemblerX86Base.h" | |
21 #include "IceCfg.h" | |
22 #include "IceCfgNode.h" | |
23 #include "IceDefs.h" | |
24 #include "IceInst.h" | |
25 #include "IceOperand.h" | |
26 #include "IceTargetLowering.h" | |
27 | |
28 namespace Ice { | |
29 | |
30 namespace X86Internal { | |
31 | |
32 template <class Machine> | |
33 const char *InstX86Base<Machine>::getWidthString(Type Ty) { | |
34 return Traits::TypeAttributes[Ty].WidthString; | |
35 } | |
36 | |
37 template <class Machine> | |
38 const char *InstX86Base<Machine>::getFldString(Type Ty) { | |
39 return Traits::TypeAttributes[Ty].FldString; | |
40 } | |
41 | |
42 template <class Machine> | |
43 typename InstX86Base<Machine>::Traits::Cond::BrCond | |
44 InstX86Base<Machine>::getOppositeCondition(typename Traits::Cond::BrCond Cond) { | |
45 return Traits::InstBrAttributes[Cond].Opposite; | |
46 } | |
47 | |
48 template <class Machine> | |
49 InstX86BaseFakeRMW<Machine>::InstX86BaseFakeRMW(Cfg *Func, Operand *Data, | |
50 Operand *Addr, | |
51 InstArithmetic::OpKind Op, | |
52 Variable *Beacon) | |
53 : InstX86Base<Machine>(Func, InstX86Base<Machine>::FakeRMW, 3, nullptr), | |
54 Op(Op) { | |
55 this->addSource(Data); | |
56 this->addSource(Addr); | |
57 this->addSource(Beacon); | |
58 } | |
59 | |
60 template <class Machine> | |
61 InstX86BaseAdjustStack<Machine>::InstX86BaseAdjustStack(Cfg *Func, SizeT Amount, | |
62 Variable *Esp) | |
63 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Adjuststack, 1, Esp), | |
64 Amount(Amount) { | |
65 this->addSource(Esp); | |
66 } | |
67 | |
68 template <class Machine> | |
69 InstX86BaseMul<Machine>::InstX86BaseMul(Cfg *Func, Variable *Dest, | |
70 Variable *Source1, Operand *Source2) | |
71 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mul, 2, Dest) { | |
72 this->addSource(Source1); | |
73 this->addSource(Source2); | |
74 } | |
75 | |
76 template <class Machine> | |
77 InstX86BaseShld<Machine>::InstX86BaseShld(Cfg *Func, Variable *Dest, | |
78 Variable *Source1, Variable *Source2) | |
79 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shld, 3, Dest) { | |
80 this->addSource(Dest); | |
81 this->addSource(Source1); | |
82 this->addSource(Source2); | |
83 } | |
84 | |
85 template <class Machine> | |
86 InstX86BaseShrd<Machine>::InstX86BaseShrd(Cfg *Func, Variable *Dest, | |
87 Variable *Source1, Variable *Source2) | |
88 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shrd, 3, Dest) { | |
89 this->addSource(Dest); | |
90 this->addSource(Source1); | |
91 this->addSource(Source2); | |
92 } | |
93 | |
94 template <class Machine> | |
95 InstX86BaseLabel<Machine>::InstX86BaseLabel( | |
96 Cfg *Func, typename InstX86Base<Machine>::Traits::TargetLowering *Target) | |
97 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Label, 0, nullptr), | |
98 Number(Target->makeNextLabelNumber()) {} | |
99 | |
100 template <class Machine> | |
101 IceString InstX86BaseLabel<Machine>::getName(const Cfg *Func) const { | |
102 return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number); | |
103 } | |
104 | |
105 template <class Machine> | |
106 InstX86BaseBr<Machine>::InstX86BaseBr( | |
107 Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse, | |
108 const InstX86BaseLabel<Machine> *Label, | |
109 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) | |
110 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Br, 0, nullptr), | |
111 Condition(Condition), TargetTrue(TargetTrue), TargetFalse(TargetFalse), | |
112 Label(Label) {} | |
113 | |
114 template <class Machine> | |
115 bool InstX86BaseBr<Machine>::optimizeBranch(const CfgNode *NextNode) { | |
116 // If there is no next block, then there can be no fallthrough to | |
117 // optimize. | |
118 if (NextNode == nullptr) | |
119 return false; | |
120 // Intra-block conditional branches can't be optimized. | |
121 if (Label) | |
122 return false; | |
123 // If there is no fallthrough node, such as a non-default case label | |
124 // for a switch instruction, then there is no opportunity to | |
125 // optimize. | |
126 if (getTargetFalse() == nullptr) | |
127 return false; | |
128 | |
129 // Unconditional branch to the next node can be removed. | |
130 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None && | |
131 getTargetFalse() == NextNode) { | |
132 assert(getTargetTrue() == nullptr); | |
133 this->setDeleted(); | |
134 return true; | |
135 } | |
136 // If the fallthrough is to the next node, set fallthrough to nullptr | |
137 // to indicate. | |
138 if (getTargetFalse() == NextNode) { | |
139 TargetFalse = nullptr; | |
140 return true; | |
141 } | |
142 // If TargetTrue is the next node, and TargetFalse is not nullptr | |
143 // (which was already tested above), then invert the branch | |
144 // condition, swap the targets, and set new fallthrough to nullptr. | |
145 if (getTargetTrue() == NextNode) { | |
146 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); | |
147 Condition = this->getOppositeCondition(Condition); | |
148 TargetTrue = getTargetFalse(); | |
149 TargetFalse = nullptr; | |
150 return true; | |
151 } | |
152 return false; | |
153 } | |
154 | |
155 template <class Machine> | |
156 bool InstX86BaseBr<Machine>::repointEdge(CfgNode *OldNode, CfgNode *NewNode) { | |
157 if (TargetFalse == OldNode) { | |
158 TargetFalse = NewNode; | |
159 return true; | |
160 } else if (TargetTrue == OldNode) { | |
161 TargetTrue = NewNode; | |
162 return true; | |
163 } | |
164 return false; | |
165 } | |
166 | |
167 template <class Machine> | |
168 InstX86BaseJmp<Machine>::InstX86BaseJmp(Cfg *Func, Operand *Target) | |
169 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Jmp, 1, nullptr) { | |
170 this->addSource(Target); | |
171 } | |
172 | |
173 template <class Machine> | |
174 InstX86BaseCall<Machine>::InstX86BaseCall(Cfg *Func, Variable *Dest, | |
175 Operand *CallTarget) | |
176 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Call, 1, Dest) { | |
177 this->HasSideEffects = true; | |
178 this->addSource(CallTarget); | |
179 } | |
180 | |
181 template <class Machine> | |
182 InstX86BaseCmov<Machine>::InstX86BaseCmov( | |
183 Cfg *Func, Variable *Dest, Operand *Source, | |
184 typename InstX86Base<Machine>::Traits::Cond::BrCond Condition) | |
185 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmov, 2, Dest), | |
186 Condition(Condition) { | |
187 // The final result is either the original Dest, or Source, so mark | |
188 // both as sources. | |
189 this->addSource(Dest); | |
190 this->addSource(Source); | |
191 } | |
192 | |
193 template <class Machine> | |
194 InstX86BaseCmpps<Machine>::InstX86BaseCmpps( | |
195 Cfg *Func, Variable *Dest, Operand *Source, | |
196 typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition) | |
197 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmpps, 2, Dest), | |
198 Condition(Condition) { | |
199 this->addSource(Dest); | |
200 this->addSource(Source); | |
201 } | |
202 | |
203 template <class Machine> | |
204 InstX86BaseCmpxchg<Machine>::InstX86BaseCmpxchg(Cfg *Func, Operand *DestOrAddr, | |
205 Variable *Eax, | |
206 Variable *Desired, bool Locked) | |
207 : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 3, | |
208 llvm::dyn_cast<Variable>(DestOrAddr), | |
209 Locked) { | |
210 assert(Eax->getRegNum() == | |
211 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
212 this->addSource(DestOrAddr); | |
213 this->addSource(Eax); | |
214 this->addSource(Desired); | |
215 } | |
216 | |
217 template <class Machine> | |
218 InstX86BaseCmpxchg8b<Machine>::InstX86BaseCmpxchg8b( | |
219 Cfg *Func, typename InstX86Base<Machine>::Traits::X86OperandMem *Addr, | |
220 Variable *Edx, Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked) | |
221 : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 5, | |
222 nullptr, Locked) { | |
223 assert(Edx->getRegNum() == | |
224 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
225 assert(Eax->getRegNum() == | |
226 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
227 assert(Ecx->getRegNum() == | |
228 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); | |
229 assert(Ebx->getRegNum() == | |
230 InstX86Base<Machine>::Traits::RegisterSet::Reg_ebx); | |
231 this->addSource(Addr); | |
232 this->addSource(Edx); | |
233 this->addSource(Eax); | |
234 this->addSource(Ecx); | |
235 this->addSource(Ebx); | |
236 } | |
237 | |
238 template <class Machine> | |
239 InstX86BaseCvt<Machine>::InstX86BaseCvt(Cfg *Func, Variable *Dest, | |
240 Operand *Source, CvtVariant Variant) | |
241 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cvt, 1, Dest), | |
242 Variant(Variant) { | |
243 this->addSource(Source); | |
244 } | |
245 | |
246 template <class Machine> | |
247 InstX86BaseIcmp<Machine>::InstX86BaseIcmp(Cfg *Func, Operand *Src0, | |
248 Operand *Src1) | |
249 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Icmp, 2, nullptr) { | |
250 this->addSource(Src0); | |
251 this->addSource(Src1); | |
252 } | |
253 | |
254 template <class Machine> | |
255 InstX86BaseUcomiss<Machine>::InstX86BaseUcomiss(Cfg *Func, Operand *Src0, | |
256 Operand *Src1) | |
257 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ucomiss, 2, nullptr) { | |
258 this->addSource(Src0); | |
259 this->addSource(Src1); | |
260 } | |
261 | |
262 template <class Machine> | |
263 InstX86BaseUD2<Machine>::InstX86BaseUD2(Cfg *Func) | |
264 : InstX86Base<Machine>(Func, InstX86Base<Machine>::UD2, 0, nullptr) {} | |
265 | |
266 template <class Machine> | |
267 InstX86BaseTest<Machine>::InstX86BaseTest(Cfg *Func, Operand *Src1, | |
268 Operand *Src2) | |
269 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Test, 2, nullptr) { | |
270 this->addSource(Src1); | |
271 this->addSource(Src2); | |
272 } | |
273 | |
274 template <class Machine> | |
275 InstX86BaseMfence<Machine>::InstX86BaseMfence(Cfg *Func) | |
276 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mfence, 0, nullptr) { | |
277 this->HasSideEffects = true; | |
278 } | |
279 | |
280 template <class Machine> | |
281 InstX86BaseStore<Machine>::InstX86BaseStore( | |
282 Cfg *Func, Operand *Value, | |
283 typename InstX86Base<Machine>::Traits::X86Operand *Mem) | |
284 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Store, 2, nullptr) { | |
285 this->addSource(Value); | |
286 this->addSource(Mem); | |
287 } | |
288 | |
289 template <class Machine> | |
290 InstX86BaseStoreP<Machine>::InstX86BaseStoreP( | |
291 Cfg *Func, Variable *Value, | |
292 typename InstX86Base<Machine>::Traits::X86OperandMem *Mem) | |
293 : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreP, 2, nullptr) { | |
294 this->addSource(Value); | |
295 this->addSource(Mem); | |
296 } | |
297 | |
298 template <class Machine> | |
299 InstX86BaseStoreQ<Machine>::InstX86BaseStoreQ( | |
300 Cfg *Func, Variable *Value, | |
301 typename InstX86Base<Machine>::Traits::X86OperandMem *Mem) | |
302 : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreQ, 2, nullptr) { | |
303 this->addSource(Value); | |
304 this->addSource(Mem); | |
305 } | |
306 | |
307 template <class Machine> | |
308 InstX86BaseNop<Machine>::InstX86BaseNop(Cfg *Func, | |
309 InstX86BaseNop::NopVariant Variant) | |
310 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Nop, 0, nullptr), | |
311 Variant(Variant) {} | |
312 | |
313 template <class Machine> | |
314 InstX86BaseFld<Machine>::InstX86BaseFld(Cfg *Func, Operand *Src) | |
315 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fld, 1, nullptr) { | |
316 this->addSource(Src); | |
317 } | |
318 | |
319 template <class Machine> | |
320 InstX86BaseFstp<Machine>::InstX86BaseFstp(Cfg *Func, Variable *Dest) | |
321 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fstp, 0, Dest) {} | |
322 | |
323 template <class Machine> | |
324 InstX86BasePop<Machine>::InstX86BasePop(Cfg *Func, Variable *Dest) | |
325 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Pop, 0, Dest) { | |
326 // A pop instruction affects the stack pointer and so it should not | |
327 // be allowed to be automatically dead-code eliminated. (The | |
328 // corresponding push instruction doesn't need this treatment | |
329 // because it has no dest variable and therefore won't be dead-code | |
330 // eliminated.) This is needed for late-stage liveness analysis | |
331 // (e.g. asm-verbose mode). | |
332 this->HasSideEffects = true; | |
333 } | |
334 | |
335 template <class Machine> | |
336 InstX86BasePush<Machine>::InstX86BasePush(Cfg *Func, Variable *Source) | |
337 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Push, 1, nullptr) { | |
338 this->addSource(Source); | |
339 } | |
340 | |
341 template <class Machine> | |
342 InstX86BaseRet<Machine>::InstX86BaseRet(Cfg *Func, Variable *Source) | |
343 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ret, Source ? 1 : 0, | |
344 nullptr) { | |
345 if (Source) | |
346 this->addSource(Source); | |
347 } | |
348 | |
349 template <class Machine> | |
350 InstX86BaseSetcc<Machine>::InstX86BaseSetcc( | |
351 Cfg *Func, Variable *Dest, | |
352 typename InstX86Base<Machine>::Traits::Cond::BrCond Cond) | |
353 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Setcc, 0, Dest), | |
354 Condition(Cond) {} | |
355 | |
356 template <class Machine> | |
357 InstX86BaseXadd<Machine>::InstX86BaseXadd(Cfg *Func, Operand *Dest, | |
358 Variable *Source, bool Locked) | |
359 : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Xadd, 2, | |
360 llvm::dyn_cast<Variable>(Dest), Locked) { | |
361 this->addSource(Dest); | |
362 this->addSource(Source); | |
363 } | |
364 | |
365 template <class Machine> | |
366 InstX86BaseXchg<Machine>::InstX86BaseXchg(Cfg *Func, Operand *Dest, | |
367 Variable *Source) | |
368 : InstX86Base<Machine>(Func, InstX86Base<Machine>::Xchg, 2, | |
369 llvm::dyn_cast<Variable>(Dest)) { | |
370 this->addSource(Dest); | |
371 this->addSource(Source); | |
372 } | |
373 | |
374 // ======================== Dump routines ======================== // | |
375 | |
376 template <class Machine> | |
377 void InstX86Base<Machine>::dump(const Cfg *Func) const { | |
378 if (!BuildDefs::dump()) | |
379 return; | |
380 Ostream &Str = Func->getContext()->getStrDump(); | |
381 Str << "[" << Traits::TargetName << "] "; | |
382 Inst::dump(Func); | |
383 } | |
384 | |
385 template <class Machine> | |
386 void InstX86BaseFakeRMW<Machine>::dump(const Cfg *Func) const { | |
387 if (!BuildDefs::dump()) | |
388 return; | |
389 Ostream &Str = Func->getContext()->getStrDump(); | |
390 Type Ty = getData()->getType(); | |
391 Str << "rmw " << InstArithmetic::getOpName(getOp()) << " " << Ty << " *"; | |
392 getAddr()->dump(Func); | |
393 Str << ", "; | |
394 getData()->dump(Func); | |
395 Str << ", beacon="; | |
396 getBeacon()->dump(Func); | |
397 } | |
398 | |
399 template <class Machine> | |
400 void InstX86BaseLabel<Machine>::emit(const Cfg *Func) const { | |
401 if (!BuildDefs::dump()) | |
402 return; | |
403 Ostream &Str = Func->getContext()->getStrEmit(); | |
404 Str << getName(Func) << ":"; | |
405 } | |
406 | |
407 template <class Machine> | |
408 void InstX86BaseLabel<Machine>::emitIAS(const Cfg *Func) const { | |
409 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
410 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
411 Asm->BindLocalLabel(Number); | |
412 } | |
413 | |
414 template <class Machine> | |
415 void InstX86BaseLabel<Machine>::dump(const Cfg *Func) const { | |
416 if (!BuildDefs::dump()) | |
417 return; | |
418 Ostream &Str = Func->getContext()->getStrDump(); | |
419 Str << getName(Func) << ":"; | |
420 } | |
421 | |
422 template <class Machine> | |
423 void InstX86BaseBr<Machine>::emit(const Cfg *Func) const { | |
424 if (!BuildDefs::dump()) | |
425 return; | |
426 Ostream &Str = Func->getContext()->getStrEmit(); | |
427 Str << "\t"; | |
428 | |
429 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { | |
430 Str << "jmp"; | |
431 } else { | |
432 Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].EmitString; | |
433 } | |
434 | |
435 if (Label) { | |
436 Str << "\t" << Label->getName(Func); | |
437 } else { | |
438 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { | |
439 Str << "\t" << getTargetFalse()->getAsmName(); | |
440 } else { | |
441 Str << "\t" << getTargetTrue()->getAsmName(); | |
442 if (getTargetFalse()) { | |
443 Str << "\n\tjmp\t" << getTargetFalse()->getAsmName(); | |
444 } | |
445 } | |
446 } | |
447 } | |
448 | |
449 template <class Machine> | |
450 void InstX86BaseBr<Machine>::emitIAS(const Cfg *Func) const { | |
451 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
452 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
453 if (Label) { | |
454 class Label *L = Asm->GetOrCreateLocalLabel(Label->getNumber()); | |
455 // In all these cases, local Labels should only be used for Near. | |
456 const bool Near = true; | |
457 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { | |
458 Asm->jmp(L, Near); | |
459 } else { | |
460 Asm->j(Condition, L, Near); | |
461 } | |
462 } else { | |
463 // Pessimistically assume it's far. This only affects Labels that | |
464 // are not Bound. | |
465 const bool Near = false; | |
466 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { | |
467 class Label *L = | |
468 Asm->GetOrCreateCfgNodeLabel(getTargetFalse()->getIndex()); | |
469 assert(!getTargetTrue()); | |
470 Asm->jmp(L, Near); | |
471 } else { | |
472 class Label *L = | |
473 Asm->GetOrCreateCfgNodeLabel(getTargetTrue()->getIndex()); | |
474 Asm->j(Condition, L, Near); | |
475 if (getTargetFalse()) { | |
476 class Label *L2 = | |
477 Asm->GetOrCreateCfgNodeLabel(getTargetFalse()->getIndex()); | |
478 Asm->jmp(L2, Near); | |
479 } | |
480 } | |
481 } | |
482 } | |
483 | |
484 template <class Machine> | |
485 void InstX86BaseBr<Machine>::dump(const Cfg *Func) const { | |
486 if (!BuildDefs::dump()) | |
487 return; | |
488 Ostream &Str = Func->getContext()->getStrDump(); | |
489 Str << "br "; | |
490 | |
491 if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) { | |
492 Str << "label %" | |
493 << (Label ? Label->getName(Func) : getTargetFalse()->getName()); | |
494 return; | |
495 } | |
496 | |
497 Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition] | |
498 .DisplayString; | |
499 if (Label) { | |
500 Str << ", label %" << Label->getName(Func); | |
501 } else { | |
502 Str << ", label %" << getTargetTrue()->getName(); | |
503 if (getTargetFalse()) { | |
504 Str << ", label %" << getTargetFalse()->getName(); | |
505 } | |
506 } | |
507 } | |
508 | |
509 template <class Machine> | |
510 void InstX86BaseJmp<Machine>::emit(const Cfg *Func) const { | |
511 if (!BuildDefs::dump()) | |
512 return; | |
513 Ostream &Str = Func->getContext()->getStrEmit(); | |
514 assert(this->getSrcSize() == 1); | |
515 Str << "\tjmp\t*"; | |
516 getJmpTarget()->emit(Func); | |
517 } | |
518 | |
519 template <class Machine> | |
520 void InstX86BaseJmp<Machine>::emitIAS(const Cfg *Func) const { | |
521 // Note: Adapted (mostly copied) from InstX86BaseCall<Machine>::emitIAS(). | |
522 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
523 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
524 Operand *Target = getJmpTarget(); | |
525 if (const auto Var = llvm::dyn_cast<Variable>(Target)) { | |
526 if (Var->hasReg()) { | |
527 Asm->jmp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
528 Var->getRegNum())); | |
529 } else { | |
530 // The jmp instruction with a memory operand should be possible | |
531 // to encode, but it isn't a valid sandboxed instruction, and | |
532 // there shouldn't be a register allocation issue to jump | |
533 // through a scratch register, so we don't really need to bother | |
534 // implementing it. | |
535 llvm::report_fatal_error("Assembler can't jmp to memory operand"); | |
536 } | |
537 } else if (const auto Mem = llvm::dyn_cast< | |
538 typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
539 Target)) { | |
540 (void)Mem; | |
541 assert(Mem->getSegmentRegister() == | |
542 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
543 llvm::report_fatal_error("Assembler can't jmp to memory operand"); | |
544 } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { | |
545 assert(CR->getOffset() == 0 && "We only support jumping to a function"); | |
546 Asm->jmp(CR); | |
547 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) { | |
548 // NaCl trampoline calls refer to an address within the sandbox directly. | |
549 // This is usually only needed for non-IRT builds and otherwise not | |
550 // very portable or stable. Usually this is only done for "calls" | |
551 // and not jumps. | |
552 // TODO(jvoung): Support this when there is a lowering that | |
553 // actually triggers this case. | |
554 (void)Imm; | |
555 llvm::report_fatal_error("Unexpected jmp to absolute address"); | |
556 } else { | |
557 llvm::report_fatal_error("Unexpected operand type"); | |
558 } | |
559 } | |
560 | |
561 template <class Machine> | |
562 void InstX86BaseJmp<Machine>::dump(const Cfg *Func) const { | |
563 if (!BuildDefs::dump()) | |
564 return; | |
565 Ostream &Str = Func->getContext()->getStrDump(); | |
566 Str << "jmp "; | |
567 getJmpTarget()->dump(Func); | |
568 } | |
569 | |
570 template <class Machine> | |
571 void InstX86BaseCall<Machine>::emit(const Cfg *Func) const { | |
572 if (!BuildDefs::dump()) | |
573 return; | |
574 Ostream &Str = Func->getContext()->getStrEmit(); | |
575 assert(this->getSrcSize() == 1); | |
576 Str << "\tcall\t"; | |
577 if (const auto CI = llvm::dyn_cast<ConstantInteger32>(getCallTarget())) { | |
578 // Emit without a leading '$'. | |
579 Str << CI->getValue(); | |
580 } else if (const auto CallTarget = | |
581 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { | |
582 CallTarget->emitWithoutPrefix(Func->getTarget()); | |
583 } else { | |
584 Str << "*"; | |
585 getCallTarget()->emit(Func); | |
586 } | |
587 Func->getTarget()->resetStackAdjustment(); | |
588 } | |
589 | |
590 template <class Machine> | |
591 void InstX86BaseCall<Machine>::emitIAS(const Cfg *Func) const { | |
592 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
593 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
594 Operand *Target = getCallTarget(); | |
595 if (const auto Var = llvm::dyn_cast<Variable>(Target)) { | |
596 if (Var->hasReg()) { | |
597 Asm->call(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
598 Var->getRegNum())); | |
599 } else { | |
600 Asm->call( | |
601 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
602 Func->getTarget()) | |
603 ->stackVarToAsmOperand(Var)); | |
604 } | |
605 } else if (const auto Mem = llvm::dyn_cast< | |
606 typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
607 Target)) { | |
608 assert(Mem->getSegmentRegister() == | |
609 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
610 Asm->call(Mem->toAsmAddress(Asm)); | |
611 } else if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { | |
612 assert(CR->getOffset() == 0 && "We only support calling a function"); | |
613 Asm->call(CR); | |
614 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) { | |
615 Asm->call(Immediate(Imm->getValue())); | |
616 } else { | |
617 llvm_unreachable("Unexpected operand type"); | |
618 } | |
619 Func->getTarget()->resetStackAdjustment(); | |
620 } | |
621 | |
622 template <class Machine> | |
623 void InstX86BaseCall<Machine>::dump(const Cfg *Func) const { | |
624 if (!BuildDefs::dump()) | |
625 return; | |
626 Ostream &Str = Func->getContext()->getStrDump(); | |
627 if (this->getDest()) { | |
628 this->dumpDest(Func); | |
629 Str << " = "; | |
630 } | |
631 Str << "call "; | |
632 getCallTarget()->dump(Func); | |
633 } | |
634 | |
635 // The ShiftHack parameter is used to emit "cl" instead of "ecx" for | |
636 // shift instructions, in order to be syntactically valid. The | |
637 // this->Opcode parameter needs to be char* and not IceString because of | |
638 // template issues. | |
639 template <class Machine> | |
640 void InstX86Base<Machine>::emitTwoAddress(const char *Opcode, const Inst *Inst, | |
641 const Cfg *Func, bool ShiftHack) { | |
642 if (!BuildDefs::dump()) | |
643 return; | |
644 Ostream &Str = Func->getContext()->getStrEmit(); | |
645 assert(Inst->getSrcSize() == 2); | |
646 Operand *Dest = Inst->getDest(); | |
647 if (Dest == nullptr) | |
648 Dest = Inst->getSrc(0); | |
649 assert(Dest == Inst->getSrc(0)); | |
650 Operand *Src1 = Inst->getSrc(1); | |
651 Str << "\t" << Opcode << InstX86Base<Machine>::getWidthString(Dest->getType()) | |
652 << "\t"; | |
653 const auto ShiftReg = llvm::dyn_cast<Variable>(Src1); | |
654 if (ShiftHack && ShiftReg && | |
655 ShiftReg->getRegNum() == | |
656 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx) | |
657 Str << "%cl"; | |
658 else | |
659 Src1->emit(Func); | |
660 Str << ", "; | |
661 Dest->emit(Func); | |
662 } | |
663 | |
664 template <class Machine> | |
665 void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op, | |
666 const typename InstX86Base< | |
667 Machine>::Traits::Assembler::GPREmitterOneOp &Emitter) { | |
668 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
669 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
670 if (const auto Var = llvm::dyn_cast<Variable>(Op)) { | |
671 if (Var->hasReg()) { | |
672 // We cheat a little and use GPRRegister even for byte operations. | |
673 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = | |
674 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( | |
675 Ty, Var->getRegNum()); | |
676 (Asm->*(Emitter.Reg))(Ty, VarReg); | |
677 } else { | |
678 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
679 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
680 Func->getTarget()) | |
681 ->stackVarToAsmOperand(Var)); | |
682 (Asm->*(Emitter.Addr))(Ty, StackAddr); | |
683 } | |
684 } else if (const auto Mem = llvm::dyn_cast< | |
685 typename InstX86Base<Machine>::Traits::X86OperandMem>(Op)) { | |
686 Mem->emitSegmentOverride(Asm); | |
687 (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm)); | |
688 } else { | |
689 llvm_unreachable("Unexpected operand type"); | |
690 } | |
691 } | |
692 | |
693 template <class Machine, bool VarCanBeByte, bool SrcCanBeByte> | |
694 void emitIASRegOpTyGPR( | |
695 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, | |
696 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp | |
697 &Emitter) { | |
698 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
699 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
700 assert(Var->hasReg()); | |
701 // We cheat a little and use GPRRegister even for byte operations. | |
702 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = | |
703 VarCanBeByte | |
704 ? InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( | |
705 Ty, Var->getRegNum()) | |
706 : InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
707 Var->getRegNum()); | |
708 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
709 if (SrcVar->hasReg()) { | |
710 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = | |
711 SrcCanBeByte | |
712 ? InstX86Base<Machine>::Traits::RegisterSet:: | |
713 getEncodedByteRegOrGPR(Ty, SrcVar->getRegNum()) | |
714 : InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
715 SrcVar->getRegNum()); | |
716 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); | |
717 } else { | |
718 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = | |
719 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
720 Func->getTarget()) | |
721 ->stackVarToAsmOperand(SrcVar); | |
722 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr); | |
723 } | |
724 } else if (const auto Mem = llvm::dyn_cast< | |
725 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { | |
726 Mem->emitSegmentOverride(Asm); | |
727 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); | |
728 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { | |
729 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue())); | |
730 } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { | |
731 AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc); | |
732 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Reloc->getOffset(), Fixup)); | |
733 } else if (const auto Split = llvm::dyn_cast< | |
734 typename InstX86Base<Machine>::Traits::VariableSplit>(Src)) { | |
735 (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func)); | |
736 } else { | |
737 llvm_unreachable("Unexpected operand type"); | |
738 } | |
739 } | |
740 | |
741 template <class Machine> | |
742 void emitIASAddrOpTyGPR( | |
743 const Cfg *Func, Type Ty, | |
744 const typename InstX86Base<Machine>::Traits::Address &Addr, | |
745 const Operand *Src, | |
746 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp | |
747 &Emitter) { | |
748 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
749 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
750 // Src can only be Reg or Immediate. | |
751 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
752 assert(SrcVar->hasReg()); | |
753 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = | |
754 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( | |
755 Ty, SrcVar->getRegNum()); | |
756 (Asm->*(Emitter.AddrGPR))(Ty, Addr, SrcReg); | |
757 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { | |
758 (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Imm->getValue())); | |
759 } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { | |
760 AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc); | |
761 (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Reloc->getOffset(), Fixup)); | |
762 } else { | |
763 llvm_unreachable("Unexpected operand type"); | |
764 } | |
765 } | |
766 | |
767 template <class Machine> | |
768 void emitIASAsAddrOpTyGPR( | |
769 const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1, | |
770 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp | |
771 &Emitter) { | |
772 if (const auto Op0Var = llvm::dyn_cast<Variable>(Op0)) { | |
773 assert(!Op0Var->hasReg()); | |
774 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
775 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
776 Func->getTarget()) | |
777 ->stackVarToAsmOperand(Op0Var)); | |
778 emitIASAddrOpTyGPR<Machine>(Func, Ty, StackAddr, Op1, Emitter); | |
779 } else if (const auto Op0Mem = llvm::dyn_cast< | |
780 typename InstX86Base<Machine>::Traits::X86OperandMem>(Op0)) { | |
781 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
782 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
783 Op0Mem->emitSegmentOverride(Asm); | |
784 emitIASAddrOpTyGPR<Machine>(Func, Ty, Op0Mem->toAsmAddress(Asm), Op1, | |
785 Emitter); | |
786 } else if (const auto Split = llvm::dyn_cast< | |
787 typename InstX86Base<Machine>::Traits::VariableSplit>(Op0)) { | |
788 emitIASAddrOpTyGPR<Machine>(Func, Ty, Split->toAsmAddress(Func), Op1, | |
789 Emitter); | |
790 } else { | |
791 llvm_unreachable("Unexpected operand type"); | |
792 } | |
793 } | |
794 | |
795 template <class Machine> | |
796 void InstX86Base<Machine>::emitIASGPRShift( | |
797 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, | |
798 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp | |
799 &Emitter) { | |
800 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
801 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
802 // Technically, the Dest Var can be mem as well, but we only use Reg. | |
803 // We can extend this to check Dest if we decide to use that form. | |
804 assert(Var->hasReg()); | |
805 // We cheat a little and use GPRRegister even for byte operations. | |
806 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg = | |
807 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( | |
808 Ty, Var->getRegNum()); | |
809 // Src must be reg == ECX or an Imm8. | |
810 // This is asserted by the assembler. | |
811 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
812 assert(SrcVar->hasReg()); | |
813 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = | |
814 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteRegOrGPR( | |
815 Ty, SrcVar->getRegNum()); | |
816 (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); | |
817 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { | |
818 (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue())); | |
819 } else { | |
820 llvm_unreachable("Unexpected operand type"); | |
821 } | |
822 } | |
823 | |
824 template <class Machine> | |
825 void emitIASGPRShiftDouble( | |
826 const Cfg *Func, const Variable *Dest, const Operand *Src1Op, | |
827 const Operand *Src2Op, | |
828 const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftD | |
829 &Emitter) { | |
830 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
831 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
832 // Dest can be reg or mem, but we only use the reg variant. | |
833 assert(Dest->hasReg()); | |
834 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister DestReg = | |
835 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
836 Dest->getRegNum()); | |
837 // SrcVar1 must be reg. | |
838 const auto SrcVar1 = llvm::cast<Variable>(Src1Op); | |
839 assert(SrcVar1->hasReg()); | |
840 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg = | |
841 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
842 SrcVar1->getRegNum()); | |
843 Type Ty = SrcVar1->getType(); | |
844 // Src2 can be the implicit CL register or an immediate. | |
845 if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src2Op)) { | |
846 (Asm->*(Emitter.GPRGPRImm))(Ty, DestReg, SrcReg, | |
847 Immediate(Imm->getValue())); | |
848 } else { | |
849 assert(llvm::cast<Variable>(Src2Op)->getRegNum() == | |
850 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); | |
851 (Asm->*(Emitter.GPRGPR))(Ty, DestReg, SrcReg); | |
852 } | |
853 } | |
854 | |
855 template <class Machine> | |
856 void emitIASXmmShift( | |
857 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, | |
858 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp | |
859 &Emitter) { | |
860 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
861 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
862 assert(Var->hasReg()); | |
863 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg = | |
864 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
865 Var->getRegNum()); | |
866 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
867 if (SrcVar->hasReg()) { | |
868 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = | |
869 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
870 SrcVar->getRegNum()); | |
871 (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg); | |
872 } else { | |
873 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = | |
874 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
875 Func->getTarget()) | |
876 ->stackVarToAsmOperand(SrcVar); | |
877 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); | |
878 } | |
879 } else if (const auto Mem = llvm::dyn_cast< | |
880 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { | |
881 assert(Mem->getSegmentRegister() == | |
882 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
883 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); | |
884 } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { | |
885 (Asm->*(Emitter.XmmImm))(Ty, VarReg, Immediate(Imm->getValue())); | |
886 } else { | |
887 llvm_unreachable("Unexpected operand type"); | |
888 } | |
889 } | |
890 | |
891 template <class Machine> | |
892 void emitIASRegOpTyXMM( | |
893 const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, | |
894 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | |
895 &Emitter) { | |
896 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
897 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
898 assert(Var->hasReg()); | |
899 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg = | |
900 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
901 Var->getRegNum()); | |
902 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
903 if (SrcVar->hasReg()) { | |
904 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = | |
905 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
906 SrcVar->getRegNum()); | |
907 (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg); | |
908 } else { | |
909 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = | |
910 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
911 Func->getTarget()) | |
912 ->stackVarToAsmOperand(SrcVar); | |
913 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr); | |
914 } | |
915 } else if (const auto Mem = llvm::dyn_cast< | |
916 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { | |
917 assert(Mem->getSegmentRegister() == | |
918 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
919 (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm)); | |
920 } else if (const auto Imm = llvm::dyn_cast<Constant>(Src)) { | |
921 (Asm->*(Emitter.XmmAddr))( | |
922 Ty, VarReg, | |
923 InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm)); | |
924 } else { | |
925 llvm_unreachable("Unexpected operand type"); | |
926 } | |
927 } | |
928 | |
929 template <class Machine, typename DReg_t, typename SReg_t, | |
930 DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)> | |
931 void emitIASCastRegOp(const Cfg *Func, Type DispatchTy, const Variable *Dest, | |
932 const Operand *Src, | |
933 const typename InstX86Base<Machine>::Traits::Assembler:: | |
934 template CastEmitterRegOp<DReg_t, SReg_t> &Emitter) { | |
935 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
936 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
937 assert(Dest->hasReg()); | |
938 DReg_t DestReg = destEnc(Dest->getRegNum()); | |
939 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
940 if (SrcVar->hasReg()) { | |
941 SReg_t SrcReg = srcEnc(SrcVar->getRegNum()); | |
942 (Asm->*(Emitter.RegReg))(DispatchTy, DestReg, SrcReg); | |
943 } else { | |
944 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = | |
945 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
946 Func->getTarget()) | |
947 ->stackVarToAsmOperand(SrcVar); | |
948 (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, SrcStackAddr); | |
949 } | |
950 } else if (const auto Mem = llvm::dyn_cast< | |
951 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { | |
952 Mem->emitSegmentOverride(Asm); | |
953 (Asm->*(Emitter.RegAddr))(DispatchTy, DestReg, Mem->toAsmAddress(Asm)); | |
954 } else { | |
955 llvm_unreachable("Unexpected operand type"); | |
956 } | |
957 } | |
958 | |
959 template <class Machine, typename DReg_t, typename SReg_t, | |
960 DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)> | |
961 void emitIASThreeOpImmOps( | |
962 const Cfg *Func, Type DispatchTy, const Variable *Dest, const Operand *Src0, | |
963 const Operand *Src1, | |
964 const typename InstX86Base<Machine>::Traits::Assembler:: | |
965 template ThreeOpImmEmitter<DReg_t, SReg_t> Emitter) { | |
966 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
967 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
968 // This only handles Dest being a register, and Src1 being an immediate. | |
969 assert(Dest->hasReg()); | |
970 DReg_t DestReg = destEnc(Dest->getRegNum()); | |
971 Immediate Imm(llvm::cast<ConstantInteger32>(Src1)->getValue()); | |
972 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src0)) { | |
973 if (SrcVar->hasReg()) { | |
974 SReg_t SrcReg = srcEnc(SrcVar->getRegNum()); | |
975 (Asm->*(Emitter.RegRegImm))(DispatchTy, DestReg, SrcReg, Imm); | |
976 } else { | |
977 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = | |
978 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
979 Func->getTarget()) | |
980 ->stackVarToAsmOperand(SrcVar); | |
981 (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm); | |
982 } | |
983 } else if (const auto Mem = llvm::dyn_cast< | |
984 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src0)) { | |
985 Mem->emitSegmentOverride(Asm); | |
986 (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, Mem->toAsmAddress(Asm), | |
987 Imm); | |
988 } else { | |
989 llvm_unreachable("Unexpected operand type"); | |
990 } | |
991 } | |
992 | |
993 template <class Machine> | |
994 void emitIASMovlikeXMM( | |
995 const Cfg *Func, const Variable *Dest, const Operand *Src, | |
996 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterMovOps | |
997 Emitter) { | |
998 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
999 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
1000 if (Dest->hasReg()) { | |
1001 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg = | |
1002 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
1003 Dest->getRegNum()); | |
1004 if (const auto SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
1005 if (SrcVar->hasReg()) { | |
1006 (Asm->*(Emitter.XmmXmm))( | |
1007 DestReg, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
1008 SrcVar->getRegNum())); | |
1009 } else { | |
1010 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
1011 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering | |
1012 *>(Func->getTarget()) | |
1013 ->stackVarToAsmOperand(SrcVar)); | |
1014 (Asm->*(Emitter.XmmAddr))(DestReg, StackAddr); | |
1015 } | |
1016 } else if (const auto SrcMem = llvm::dyn_cast< | |
1017 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { | |
1018 assert(SrcMem->getSegmentRegister() == | |
1019 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
1020 (Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm)); | |
1021 } else { | |
1022 llvm_unreachable("Unexpected operand type"); | |
1023 } | |
1024 } else { | |
1025 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
1026 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1027 Func->getTarget()) | |
1028 ->stackVarToAsmOperand(Dest)); | |
1029 // Src must be a register in this case. | |
1030 const auto SrcVar = llvm::cast<Variable>(Src); | |
1031 assert(SrcVar->hasReg()); | |
1032 (Asm->*(Emitter.AddrXmm))( | |
1033 StackAddr, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
1034 SrcVar->getRegNum())); | |
1035 } | |
1036 } | |
1037 | |
1038 #if 0 | |
1039 TODO(jpp) | |
jvoung (off chromium)
2015/07/06 18:58:45
Can this TODO be addressed as part of this CL (see
John
2015/07/06 22:30:09
It had been handled, I just forgot to remove it.
| |
1040 // In-place ops | |
1041 template <> const char *InstX86BaseBswap::Opcode = "bswap"; | |
1042 template <> const char *InstX86BaseNeg::Opcode = "neg"; | |
1043 // Unary ops | |
1044 template <> const char *InstX86BaseBsf::Opcode = "bsf"; | |
1045 template <> const char *InstX86BaseBsr::Opcode = "bsr"; | |
1046 template <> const char *InstX86BaseLea::Opcode = "lea"; | |
1047 template <> const char *InstX86BaseMovd::Opcode = "movd"; | |
1048 template <> const char *InstX86BaseMovsx::Opcode = "movs"; | |
1049 template <> const char *InstX86BaseMovzx::Opcode = "movz"; | |
1050 template <> const char *InstX86BaseSqrtss::Opcode = "sqrtss"; | |
1051 template <> const char *InstX86BaseCbwdq::Opcode = "cbw/cwd/cdq"; | |
1052 // Mov-like ops | |
1053 template <> const char *InstX86BaseMov::Opcode = "mov"; | |
1054 template <> const char *InstX86BaseMovp::Opcode = "movups"; | |
1055 template <> const char *InstX86BaseMovq::Opcode = "movq"; | |
1056 // Binary ops | |
1057 template <> const char *InstX86BaseAdd::Opcode = "add"; | |
1058 template <> const char *InstX86BaseAddRMW::Opcode = "add"; | |
1059 template <> const char *InstX86BaseAddps::Opcode = "addps"; | |
1060 template <> const char *InstX86BaseAdc::Opcode = "adc"; | |
1061 template <> const char *InstX86BaseAdcRMW::Opcode = "adc"; | |
1062 template <> const char *InstX86BaseAddss::Opcode = "addss"; | |
1063 template <> const char *InstX86BasePadd::Opcode = "padd"; | |
1064 template <> const char *InstX86BaseSub::Opcode = "sub"; | |
1065 template <> const char *InstX86BaseSubRMW::Opcode = "sub"; | |
1066 template <> const char *InstX86BaseSubps::Opcode = "subps"; | |
1067 template <> const char *InstX86BaseSubss::Opcode = "subss"; | |
1068 template <> const char *InstX86BaseSbb::Opcode = "sbb"; | |
1069 template <> const char *InstX86BaseSbbRMW::Opcode = "sbb"; | |
1070 template <> const char *InstX86BasePsub::Opcode = "psub"; | |
1071 template <> const char *InstX86BaseAnd::Opcode = "and"; | |
1072 template <> const char *InstX86BaseAndRMW::Opcode = "and"; | |
1073 template <> const char *InstX86BasePand::Opcode = "pand"; | |
1074 template <> const char *InstX86BasePandn::Opcode = "pandn"; | |
1075 template <> const char *InstX86BaseOr::Opcode = "or"; | |
1076 template <> const char *InstX86BaseOrRMW::Opcode = "or"; | |
1077 template <> const char *InstX86BasePor::Opcode = "por"; | |
1078 template <> const char *InstX86BaseXor::Opcode = "xor"; | |
1079 template <> const char *InstX86BaseXorRMW::Opcode = "xor"; | |
1080 template <> const char *InstX86BasePxor::Opcode = "pxor"; | |
1081 template <> const char *InstX86BaseImul::Opcode = "imul"; | |
1082 template <> const char *InstX86BaseMulps::Opcode = "mulps"; | |
1083 template <> const char *InstX86BaseMulss::Opcode = "mulss"; | |
1084 template <> const char *InstX86BasePmull::Opcode = "pmull"; | |
1085 template <> const char *InstX86BasePmuludq::Opcode = "pmuludq"; | |
1086 template <> const char *InstX86BaseDiv::Opcode = "div"; | |
1087 template <> const char *InstX86BaseDivps::Opcode = "divps"; | |
1088 template <> const char *InstX86BaseIdiv::Opcode = "idiv"; | |
1089 template <> const char *InstX86BaseDivss::Opcode = "divss"; | |
1090 template <> const char *InstX86BaseRol::Opcode = "rol"; | |
1091 template <> const char *InstX86BaseShl::Opcode = "shl"; | |
1092 template <> const char *InstX86BasePsll::Opcode = "psll"; | |
1093 template <> const char *InstX86BaseShr::Opcode = "shr"; | |
1094 template <> const char *InstX86BaseSar::Opcode = "sar"; | |
1095 template <> const char *InstX86BasePsra::Opcode = "psra"; | |
1096 template <> const char *InstX86BasePsrl::Opcode = "psrl"; | |
1097 template <> const char *InstX86BasePcmpeq::Opcode = "pcmpeq"; | |
1098 template <> const char *InstX86BasePcmpgt::Opcode = "pcmpgt"; | |
1099 template <> const char *InstX86BaseMovssRegs::Opcode = "movss"; | |
1100 // Ternary ops | |
1101 template <> const char *InstX86BaseInsertps::Opcode = "insertps"; | |
1102 template <> const char *InstX86BaseShufps::Opcode = "shufps"; | |
1103 template <> const char *InstX86BasePinsr::Opcode = "pinsr"; | |
1104 template <> const char *InstX86BaseBlendvps::Opcode = "blendvps"; | |
1105 template <> const char *InstX86BasePblendvb::Opcode = "pblendvb"; | |
1106 // Three address ops | |
1107 template <> const char *InstX86BasePextr::Opcode = "pextr"; | |
1108 template <> const char *InstX86BasePshufd::Opcode = "pshufd"; | |
1109 | |
1110 // Inplace GPR ops | |
1111 template <> | |
1112 const InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp InstX86BaseBswap: :Emitter = { | |
1113 &InstX86Base<Machine>::Traits::Assembler::bswap, nullptr /* only a reg form exists */ | |
1114 }; | |
1115 template <> | |
1116 const InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp InstX86BaseNeg::E mitter = { | |
1117 &InstX86Base<Machine>::Traits::Assembler::neg, &InstX86Base<Machine>::Traits ::Assembler::neg}; | |
jvoung (off chromium)
2015/07/06 18:58:45
wonder why clang-format doesn't move stuff to the
John
2015/07/06 22:30:09
Maybe?... :)
| |
1118 | |
1119 // Unary GPR ops | |
1120 template <> | |
1121 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseBsf::E mitter = { | |
1122 &InstX86Base<Machine>::Traits::Assembler::bsf, &InstX86Base<Machine>::Traits ::Assembler::bsf, nullptr}; | |
1123 template <> | |
1124 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseBsr::E mitter = { | |
1125 &InstX86Base<Machine>::Traits::Assembler::bsr, &InstX86Base<Machine>::Traits ::Assembler::bsr, nullptr}; | |
1126 template <> | |
1127 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseLea::E mitter = { | |
1128 /* reg/reg and reg/imm are illegal */ nullptr, &InstX86Base<Machine>::Traits ::Assembler::lea, | |
1129 nullptr}; | |
1130 template <> | |
1131 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseMovsx: :Emitter = { | |
1132 &InstX86Base<Machine>::Traits::Assembler::movsx, &InstX86Base<Machine>::Trai ts::Assembler::movsx, nullptr}; | |
1133 template <> | |
1134 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseMovzx: :Emitter = { | |
1135 &InstX86Base<Machine>::Traits::Assembler::movzx, &InstX86Base<Machine>::Trai ts::Assembler::movzx, nullptr}; | |
1136 | |
1137 // Unary XMM ops | |
1138 template <> | |
1139 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseSqrtss ::Emitter = { | |
1140 &InstX86Base<Machine>::Traits::Assembler::sqrtss, &InstX86Base<Machine>::Tra its::Assembler::sqrtss}; | |
1141 | |
1142 // Binary GPR ops | |
1143 template <> | |
1144 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseAdd::E mitter = { | |
1145 &InstX86Base<Machine>::Traits::Assembler::add, &InstX86Base<Machine>::Traits ::Assembler::add, | |
1146 &InstX86Base<Machine>::Traits::Assembler::add}; | |
1147 template <> | |
1148 const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseAddRM W::Emitter = { | |
1149 &InstX86Base<Machine>::Traits::Assembler::add, &InstX86Base<Machine>::Traits ::Assembler::add}; | |
1150 template <> | |
1151 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseAdc::E mitter = { | |
1152 &InstX86Base<Machine>::Traits::Assembler::adc, &InstX86Base<Machine>::Traits ::Assembler::adc, | |
1153 &InstX86Base<Machine>::Traits::Assembler::adc}; | |
1154 template <> | |
1155 const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseAdcRM W::Emitter = { | |
1156 &InstX86Base<Machine>::Traits::Assembler::adc, &InstX86Base<Machine>::Traits ::Assembler::adc}; | |
1157 template <> | |
1158 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseAnd::E mitter = { | |
1159 &InstX86Base<Machine>::Traits::Assembler::And, &InstX86Base<Machine>::Traits ::Assembler::And, | |
1160 &InstX86Base<Machine>::Traits::Assembler::And}; | |
1161 template <> | |
1162 const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseAndRM W::Emitter = { | |
1163 &InstX86Base<Machine>::Traits::Assembler::And, &InstX86Base<Machine>::Traits ::Assembler::And}; | |
1164 template <> | |
1165 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseOr::Em itter = { | |
1166 &InstX86Base<Machine>::Traits::Assembler::Or, &InstX86Base<Machine>::Traits: :Assembler::Or, | |
1167 &InstX86Base<Machine>::Traits::Assembler::Or}; | |
1168 template <> | |
1169 const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseOrRMW ::Emitter = { | |
1170 &InstX86Base<Machine>::Traits::Assembler::Or, &InstX86Base<Machine>::Traits: :Assembler::Or}; | |
1171 template <> | |
1172 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseSbb::E mitter = { | |
1173 &InstX86Base<Machine>::Traits::Assembler::sbb, &InstX86Base<Machine>::Traits ::Assembler::sbb, | |
1174 &InstX86Base<Machine>::Traits::Assembler::sbb}; | |
1175 template <> | |
1176 const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseSbbRM W::Emitter = { | |
1177 &InstX86Base<Machine>::Traits::Assembler::sbb, &InstX86Base<Machine>::Traits ::Assembler::sbb}; | |
1178 template <> | |
1179 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseSub::E mitter = { | |
1180 &InstX86Base<Machine>::Traits::Assembler::sub, &InstX86Base<Machine>::Traits ::Assembler::sub, | |
1181 &InstX86Base<Machine>::Traits::Assembler::sub}; | |
1182 template <> | |
1183 const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseSubRM W::Emitter = { | |
1184 &InstX86Base<Machine>::Traits::Assembler::sub, &InstX86Base<Machine>::Traits ::Assembler::sub}; | |
1185 template <> | |
1186 const InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp InstX86BaseXor::E mitter = { | |
1187 &InstX86Base<Machine>::Traits::Assembler::Xor, &InstX86Base<Machine>::Traits ::Assembler::Xor, | |
1188 &InstX86Base<Machine>::Traits::Assembler::Xor}; | |
1189 template <> | |
1190 const InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp InstX86BaseXorRM W::Emitter = { | |
1191 &InstX86Base<Machine>::Traits::Assembler::Xor, &InstX86Base<Machine>::Traits ::Assembler::Xor}; | |
1192 | |
1193 // Binary Shift GPR ops | |
1194 template <> | |
1195 const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseRol: :Emitter = { | |
1196 &InstX86Base<Machine>::Traits::Assembler::rol, &InstX86Base<Machine>::Traits ::Assembler::rol}; | |
1197 template <> | |
1198 const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseSar: :Emitter = { | |
1199 &InstX86Base<Machine>::Traits::Assembler::sar, &InstX86Base<Machine>::Traits ::Assembler::sar}; | |
1200 template <> | |
1201 const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseShl: :Emitter = { | |
1202 &InstX86Base<Machine>::Traits::Assembler::shl, &InstX86Base<Machine>::Traits ::Assembler::shl}; | |
1203 template <> | |
1204 const InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp InstX86BaseShr: :Emitter = { | |
1205 &InstX86Base<Machine>::Traits::Assembler::shr, &InstX86Base<Machine>::Traits ::Assembler::shr}; | |
1206 | |
1207 // Binary XMM ops | |
1208 template <> | |
1209 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseAddss: :Emitter = { | |
1210 &InstX86Base<Machine>::Traits::Assembler::addss, &InstX86Base<Machine>::Trai ts::Assembler::addss}; | |
1211 template <> | |
1212 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseAddps: :Emitter = { | |
1213 &InstX86Base<Machine>::Traits::Assembler::addps, &InstX86Base<Machine>::Trai ts::Assembler::addps}; | |
1214 template <> | |
1215 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseDivss: :Emitter = { | |
1216 &InstX86Base<Machine>::Traits::Assembler::divss, &InstX86Base<Machine>::Trai ts::Assembler::divss}; | |
1217 template <> | |
1218 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseDivps: :Emitter = { | |
1219 &InstX86Base<Machine>::Traits::Assembler::divps, &InstX86Base<Machine>::Trai ts::Assembler::divps}; | |
1220 template <> | |
1221 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseMulss: :Emitter = { | |
1222 &InstX86Base<Machine>::Traits::Assembler::mulss, &InstX86Base<Machine>::Trai ts::Assembler::mulss}; | |
1223 template <> | |
1224 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseMulps: :Emitter = { | |
1225 &InstX86Base<Machine>::Traits::Assembler::mulps, &InstX86Base<Machine>::Trai ts::Assembler::mulps}; | |
1226 template <> | |
1227 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePadd:: Emitter = { | |
1228 &InstX86Base<Machine>::Traits::Assembler::padd, &InstX86Base<Machine>::Trait s::Assembler::padd}; | |
1229 template <> | |
1230 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePand:: Emitter = { | |
1231 &InstX86Base<Machine>::Traits::Assembler::pand, &InstX86Base<Machine>::Trait s::Assembler::pand}; | |
1232 template <> | |
1233 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePandn: :Emitter = { | |
1234 &InstX86Base<Machine>::Traits::Assembler::pandn, &InstX86Base<Machine>::Trai ts::Assembler::pandn}; | |
1235 template <> | |
1236 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePcmpeq ::Emitter = { | |
1237 &InstX86Base<Machine>::Traits::Assembler::pcmpeq, &InstX86Base<Machine>::Tra its::Assembler::pcmpeq}; | |
1238 template <> | |
1239 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePcmpgt ::Emitter = { | |
1240 &InstX86Base<Machine>::Traits::Assembler::pcmpgt, &InstX86Base<Machine>::Tra its::Assembler::pcmpgt}; | |
1241 template <> | |
1242 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePmull: :Emitter = { | |
1243 &InstX86Base<Machine>::Traits::Assembler::pmull, &InstX86Base<Machine>::Trai ts::Assembler::pmull}; | |
1244 template <> | |
1245 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePmulud q::Emitter = { | |
1246 &InstX86Base<Machine>::Traits::Assembler::pmuludq, &InstX86Base<Machine>::Tr aits::Assembler::pmuludq}; | |
1247 template <> | |
1248 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePor::E mitter = { | |
1249 &InstX86Base<Machine>::Traits::Assembler::por, &InstX86Base<Machine>::Traits ::Assembler::por}; | |
1250 template <> | |
1251 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePsub:: Emitter = { | |
1252 &InstX86Base<Machine>::Traits::Assembler::psub, &InstX86Base<Machine>::Trait s::Assembler::psub}; | |
1253 template <> | |
1254 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BasePxor:: Emitter = { | |
1255 &InstX86Base<Machine>::Traits::Assembler::pxor, &InstX86Base<Machine>::Trait s::Assembler::pxor}; | |
1256 template <> | |
1257 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseSubss: :Emitter = { | |
1258 &InstX86Base<Machine>::Traits::Assembler::subss, &InstX86Base<Machine>::Trai ts::Assembler::subss}; | |
1259 template <> | |
1260 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp InstX86BaseSubps: :Emitter = { | |
1261 &InstX86Base<Machine>::Traits::Assembler::subps, &InstX86Base<Machine>::Trai ts::Assembler::subps}; | |
1262 | |
1263 // Binary XMM Shift ops | |
1264 template <> | |
1265 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp InstX86BasePsll ::Emitter = { | |
1266 &InstX86Base<Machine>::Traits::Assembler::psll, &InstX86Base<Machine>::Trait s::Assembler::psll, | |
1267 &InstX86Base<Machine>::Traits::Assembler::psll}; | |
1268 template <> | |
1269 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp InstX86BasePsra ::Emitter = { | |
1270 &InstX86Base<Machine>::Traits::Assembler::psra, &InstX86Base<Machine>::Trait s::Assembler::psra, | |
1271 &InstX86Base<Machine>::Traits::Assembler::psra}; | |
1272 template <> | |
1273 const InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp InstX86BasePsrl ::Emitter = { | |
1274 &InstX86Base<Machine>::Traits::Assembler::psrl, &InstX86Base<Machine>::Trait s::Assembler::psrl, | |
1275 &InstX86Base<Machine>::Traits::Assembler::psrl}; | |
1276 #endif // 0 | |
1277 | |
1278 template <class Machine> | |
1279 void InstX86BaseSqrtss<Machine>::emit(const Cfg *Func) const { | |
1280 if (!BuildDefs::dump()) | |
1281 return; | |
1282 Ostream &Str = Func->getContext()->getStrEmit(); | |
1283 assert(this->getSrcSize() == 1); | |
1284 Type Ty = this->getSrc(0)->getType(); | |
1285 assert(isScalarFloatingType(Ty)); | |
1286 Str << "\tsqrt" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString | |
1287 << "\t"; | |
1288 this->getSrc(0)->emit(Func); | |
1289 Str << ", "; | |
1290 this->getDest()->emit(Func); | |
1291 } | |
1292 | |
1293 template <class Machine> | |
1294 void InstX86BaseAddss<Machine>::emit(const Cfg *Func) const { | |
1295 if (!BuildDefs::dump()) | |
1296 return; | |
1297 char buf[30]; | |
1298 snprintf( | |
1299 buf, llvm::array_lengthof(buf), "add%s", | |
1300 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
1301 .SdSsString); | |
1302 this->emitTwoAddress(buf, this, Func); | |
1303 } | |
1304 | |
1305 template <class Machine> | |
1306 void InstX86BasePadd<Machine>::emit(const Cfg *Func) const { | |
1307 if (!BuildDefs::dump()) | |
1308 return; | |
1309 char buf[30]; | |
1310 snprintf( | |
1311 buf, llvm::array_lengthof(buf), "padd%s", | |
1312 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
1313 .PackString); | |
1314 this->emitTwoAddress(buf, this, Func); | |
1315 } | |
1316 | |
1317 template <class Machine> | |
1318 void InstX86BasePmull<Machine>::emit(const Cfg *Func) const { | |
1319 if (!BuildDefs::dump()) | |
1320 return; | |
1321 char buf[30]; | |
1322 bool TypesAreValid = this->getDest()->getType() == IceType_v4i32 || | |
1323 this->getDest()->getType() == IceType_v8i16; | |
1324 bool InstructionSetIsValid = | |
1325 this->getDest()->getType() == IceType_v8i16 || | |
1326 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1327 Func->getTarget()) | |
1328 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1; | |
1329 (void)TypesAreValid; | |
1330 (void)InstructionSetIsValid; | |
1331 assert(TypesAreValid); | |
1332 assert(InstructionSetIsValid); | |
1333 snprintf( | |
1334 buf, llvm::array_lengthof(buf), "pmull%s", | |
1335 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
1336 .PackString); | |
1337 this->emitTwoAddress(buf, this, Func); | |
1338 } | |
1339 | |
1340 template <class Machine> | |
1341 void InstX86BasePmull<Machine>::emitIAS(const Cfg *Func) const { | |
1342 Type Ty = this->getDest()->getType(); | |
1343 bool TypesAreValid = Ty == IceType_v4i32 || Ty == IceType_v8i16; | |
1344 bool InstructionSetIsValid = | |
1345 Ty == IceType_v8i16 || | |
1346 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1347 Func->getTarget()) | |
1348 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1; | |
1349 (void)TypesAreValid; | |
1350 (void)InstructionSetIsValid; | |
1351 assert(TypesAreValid); | |
1352 assert(InstructionSetIsValid); | |
1353 assert(this->getSrcSize() == 2); | |
1354 Type ElementTy = typeElementType(Ty); | |
1355 emitIASRegOpTyXMM<Machine>(Func, ElementTy, this->getDest(), this->getSrc(1), | |
1356 this->Emitter); | |
1357 } | |
1358 | |
1359 template <class Machine> | |
1360 void InstX86BaseSubss<Machine>::emit(const Cfg *Func) const { | |
1361 if (!BuildDefs::dump()) | |
1362 return; | |
1363 char buf[30]; | |
1364 snprintf( | |
1365 buf, llvm::array_lengthof(buf), "sub%s", | |
1366 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
1367 .SdSsString); | |
1368 this->emitTwoAddress(buf, this, Func); | |
1369 } | |
1370 | |
1371 template <class Machine> | |
1372 void InstX86BasePsub<Machine>::emit(const Cfg *Func) const { | |
1373 if (!BuildDefs::dump()) | |
1374 return; | |
1375 char buf[30]; | |
1376 snprintf( | |
1377 buf, llvm::array_lengthof(buf), "psub%s", | |
1378 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
1379 .PackString); | |
1380 this->emitTwoAddress(buf, this, Func); | |
1381 } | |
1382 | |
1383 template <class Machine> | |
1384 void InstX86BaseMulss<Machine>::emit(const Cfg *Func) const { | |
1385 if (!BuildDefs::dump()) | |
1386 return; | |
1387 char buf[30]; | |
1388 snprintf( | |
1389 buf, llvm::array_lengthof(buf), "mul%s", | |
1390 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
1391 .SdSsString); | |
1392 this->emitTwoAddress(buf, this, Func); | |
1393 } | |
1394 | |
1395 template <class Machine> | |
1396 void InstX86BasePmuludq<Machine>::emit(const Cfg *Func) const { | |
1397 if (!BuildDefs::dump()) | |
1398 return; | |
1399 assert(this->getSrc(0)->getType() == IceType_v4i32 && | |
1400 this->getSrc(1)->getType() == IceType_v4i32); | |
1401 this->emitTwoAddress(this->Opcode, this, Func); | |
1402 } | |
1403 | |
1404 template <class Machine> | |
1405 void InstX86BaseDivss<Machine>::emit(const Cfg *Func) const { | |
1406 if (!BuildDefs::dump()) | |
1407 return; | |
1408 char buf[30]; | |
1409 snprintf( | |
1410 buf, llvm::array_lengthof(buf), "div%s", | |
1411 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
1412 .SdSsString); | |
1413 this->emitTwoAddress(buf, this, Func); | |
1414 } | |
1415 | |
1416 template <class Machine> | |
1417 void InstX86BaseDiv<Machine>::emit(const Cfg *Func) const { | |
1418 if (!BuildDefs::dump()) | |
1419 return; | |
1420 Ostream &Str = Func->getContext()->getStrEmit(); | |
1421 assert(this->getSrcSize() == 3); | |
1422 Operand *Src1 = this->getSrc(1); | |
1423 Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t"; | |
1424 Src1->emit(Func); | |
1425 } | |
1426 | |
1427 template <class Machine> | |
1428 void InstX86BaseDiv<Machine>::emitIAS(const Cfg *Func) const { | |
1429 assert(this->getSrcSize() == 3); | |
1430 const Operand *Src = this->getSrc(1); | |
1431 Type Ty = Src->getType(); | |
1432 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp | |
1433 Emitter = {&InstX86Base<Machine>::Traits::Assembler::div, | |
1434 &InstX86Base<Machine>::Traits::Assembler::div}; | |
1435 emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter); | |
1436 } | |
1437 | |
1438 template <class Machine> | |
1439 void InstX86BaseIdiv<Machine>::emit(const Cfg *Func) const { | |
1440 if (!BuildDefs::dump()) | |
1441 return; | |
1442 Ostream &Str = Func->getContext()->getStrEmit(); | |
1443 assert(this->getSrcSize() == 3); | |
1444 Operand *Src1 = this->getSrc(1); | |
1445 Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t"; | |
1446 Src1->emit(Func); | |
1447 } | |
1448 | |
1449 template <class Machine> | |
1450 void InstX86BaseIdiv<Machine>::emitIAS(const Cfg *Func) const { | |
1451 assert(this->getSrcSize() == 3); | |
1452 const Operand *Src = this->getSrc(1); | |
1453 Type Ty = Src->getType(); | |
1454 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp | |
1455 Emitter = {&InstX86Base<Machine>::Traits::Assembler::idiv, | |
1456 &InstX86Base<Machine>::Traits::Assembler::idiv}; | |
1457 emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter); | |
1458 } | |
1459 | |
1460 // pblendvb and blendvps take xmm0 as a final implicit argument. | |
1461 template <class Machine> | |
1462 void emitVariableBlendInst(const char *Opcode, const Inst *Inst, | |
1463 const Cfg *Func) { | |
1464 if (!BuildDefs::dump()) | |
1465 return; | |
1466 Ostream &Str = Func->getContext()->getStrEmit(); | |
1467 assert(Inst->getSrcSize() == 3); | |
1468 assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() == | |
1469 InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0); | |
1470 Str << "\t" << Opcode << "\t"; | |
1471 Inst->getSrc(1)->emit(Func); | |
1472 Str << ", "; | |
1473 Inst->getDest()->emit(Func); | |
1474 } | |
1475 | |
1476 template <class Machine> | |
1477 void emitIASVariableBlendInst( | |
1478 const Inst *Inst, const Cfg *Func, | |
1479 const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | |
1480 &Emitter) { | |
1481 assert(Inst->getSrcSize() == 3); | |
1482 assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() == | |
1483 InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0); | |
1484 const Variable *Dest = Inst->getDest(); | |
1485 const Operand *Src = Inst->getSrc(1); | |
1486 emitIASRegOpTyXMM<Machine>(Func, Dest->getType(), Dest, Src, Emitter); | |
1487 } | |
1488 | |
1489 template <class Machine> | |
1490 void InstX86BaseBlendvps<Machine>::emit(const Cfg *Func) const { | |
1491 if (!BuildDefs::dump()) | |
1492 return; | |
1493 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1494 Func->getTarget()) | |
1495 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
1496 emitVariableBlendInst<Machine>(this->Opcode, this, Func); | |
1497 } | |
1498 | |
1499 template <class Machine> | |
1500 void InstX86BaseBlendvps<Machine>::emitIAS(const Cfg *Func) const { | |
1501 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1502 Func->getTarget()) | |
1503 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
1504 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | |
1505 Emitter = {&InstX86Base<Machine>::Traits::Assembler::blendvps, | |
1506 &InstX86Base<Machine>::Traits::Assembler::blendvps}; | |
1507 emitIASVariableBlendInst<Machine>(this, Func, Emitter); | |
1508 } | |
1509 | |
1510 template <class Machine> | |
1511 void InstX86BasePblendvb<Machine>::emit(const Cfg *Func) const { | |
1512 if (!BuildDefs::dump()) | |
1513 return; | |
1514 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1515 Func->getTarget()) | |
1516 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
1517 emitVariableBlendInst<Machine>(this->Opcode, this, Func); | |
1518 } | |
1519 | |
1520 template <class Machine> | |
1521 void InstX86BasePblendvb<Machine>::emitIAS(const Cfg *Func) const { | |
1522 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1523 Func->getTarget()) | |
1524 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
1525 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | |
1526 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pblendvb, | |
1527 &InstX86Base<Machine>::Traits::Assembler::pblendvb}; | |
1528 emitIASVariableBlendInst<Machine>(this, Func, Emitter); | |
1529 } | |
1530 | |
1531 template <class Machine> | |
1532 void InstX86BaseImul<Machine>::emit(const Cfg *Func) const { | |
1533 if (!BuildDefs::dump()) | |
1534 return; | |
1535 Ostream &Str = Func->getContext()->getStrEmit(); | |
1536 assert(this->getSrcSize() == 2); | |
1537 Variable *Dest = this->getDest(); | |
1538 if (isByteSizedArithType(Dest->getType())) { | |
1539 // The 8-bit version of imul only allows the form "imul r/m8". | |
1540 const auto Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0)); | |
1541 (void)Src0Var; | |
1542 assert(Src0Var && | |
1543 Src0Var->getRegNum() == | |
1544 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1545 Str << "\timulb\t"; | |
1546 this->getSrc(1)->emit(Func); | |
1547 } else if (llvm::isa<Constant>(this->getSrc(1))) { | |
1548 Str << "\timul" << this->getWidthString(Dest->getType()) << "\t"; | |
1549 this->getSrc(1)->emit(Func); | |
1550 Str << ", "; | |
1551 this->getSrc(0)->emit(Func); | |
1552 Str << ", "; | |
1553 Dest->emit(Func); | |
1554 } else { | |
1555 this->emitTwoAddress("imul", this, Func); | |
1556 } | |
1557 } | |
1558 | |
1559 template <class Machine> | |
1560 void InstX86BaseImul<Machine>::emitIAS(const Cfg *Func) const { | |
1561 assert(this->getSrcSize() == 2); | |
1562 const Variable *Var = this->getDest(); | |
1563 Type Ty = Var->getType(); | |
1564 const Operand *Src = this->getSrc(1); | |
1565 if (isByteSizedArithType(Ty)) { | |
1566 // The 8-bit version of imul only allows the form "imul r/m8". | |
1567 const auto Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0)); | |
1568 (void)Src0Var; | |
1569 assert(Src0Var && | |
1570 Src0Var->getRegNum() == | |
1571 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1572 static const typename InstX86Base< | |
1573 Machine>::Traits::Assembler::GPREmitterOneOp Emitter = { | |
1574 &InstX86Base<Machine>::Traits::Assembler::imul, | |
1575 &InstX86Base<Machine>::Traits::Assembler::imul}; | |
1576 emitIASOpTyGPR<Machine>(Func, Ty, this->getSrc(1), Emitter); | |
1577 } else { | |
1578 // We only use imul as a two-address instruction even though | |
1579 // there is a 3 operand version when one of the operands is a constant. | |
1580 assert(Var == this->getSrc(0)); | |
1581 static const typename InstX86Base< | |
1582 Machine>::Traits::Assembler::GPREmitterRegOp Emitter = { | |
1583 &InstX86Base<Machine>::Traits::Assembler::imul, | |
1584 &InstX86Base<Machine>::Traits::Assembler::imul, | |
1585 &InstX86Base<Machine>::Traits::Assembler::imul}; | |
1586 emitIASRegOpTyGPR<Machine>(Func, Ty, Var, Src, Emitter); | |
1587 } | |
1588 } | |
1589 | |
1590 template <class Machine> | |
1591 void InstX86BaseInsertps<Machine>::emitIAS(const Cfg *Func) const { | |
1592 assert(this->getSrcSize() == 3); | |
1593 assert(static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1594 Func->getTarget()) | |
1595 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
1596 const Variable *Dest = this->getDest(); | |
1597 assert(Dest == this->getSrc(0)); | |
1598 Type Ty = Dest->getType(); | |
1599 static const typename InstX86Base<Machine>::Traits::Assembler:: | |
1600 template ThreeOpImmEmitter< | |
1601 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
1602 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> | |
1603 Emitter = {&InstX86Base<Machine>::Traits::Assembler::insertps, | |
1604 &InstX86Base<Machine>::Traits::Assembler::insertps}; | |
1605 emitIASThreeOpImmOps< | |
1606 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
1607 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
1608 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, | |
1609 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( | |
1610 Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter); | |
1611 } | |
1612 | |
1613 template <class Machine> | |
1614 void InstX86BaseCbwdq<Machine>::emit(const Cfg *Func) const { | |
1615 if (!BuildDefs::dump()) | |
1616 return; | |
1617 Ostream &Str = Func->getContext()->getStrEmit(); | |
1618 assert(this->getSrcSize() == 1); | |
1619 Operand *Src0 = this->getSrc(0); | |
1620 assert(llvm::isa<Variable>(Src0)); | |
1621 assert(llvm::cast<Variable>(Src0)->getRegNum() == | |
1622 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1623 switch (Src0->getType()) { | |
1624 default: | |
1625 llvm_unreachable("unexpected source type!"); | |
1626 break; | |
1627 case IceType_i8: | |
1628 assert(this->getDest()->getRegNum() == | |
1629 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1630 Str << "\tcbtw"; | |
1631 break; | |
1632 case IceType_i16: | |
1633 assert(this->getDest()->getRegNum() == | |
1634 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
1635 Str << "\tcwtd"; | |
1636 break; | |
1637 case IceType_i32: | |
1638 assert(this->getDest()->getRegNum() == | |
1639 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
1640 Str << "\tcltd"; | |
1641 break; | |
1642 } | |
1643 } | |
1644 | |
1645 template <class Machine> | |
1646 void InstX86BaseCbwdq<Machine>::emitIAS(const Cfg *Func) const { | |
1647 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
1648 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
1649 assert(this->getSrcSize() == 1); | |
1650 Operand *Src0 = this->getSrc(0); | |
1651 assert(llvm::isa<Variable>(Src0)); | |
1652 assert(llvm::cast<Variable>(Src0)->getRegNum() == | |
1653 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1654 switch (Src0->getType()) { | |
1655 default: | |
1656 llvm_unreachable("unexpected source type!"); | |
1657 break; | |
1658 case IceType_i8: | |
1659 assert(this->getDest()->getRegNum() == | |
1660 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1661 Asm->cbw(); | |
1662 break; | |
1663 case IceType_i16: | |
1664 assert(this->getDest()->getRegNum() == | |
1665 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
1666 Asm->cwd(); | |
1667 break; | |
1668 case IceType_i32: | |
1669 assert(this->getDest()->getRegNum() == | |
1670 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
1671 Asm->cdq(); | |
1672 break; | |
1673 } | |
1674 } | |
1675 | |
1676 template <class Machine> | |
1677 void InstX86BaseMul<Machine>::emit(const Cfg *Func) const { | |
1678 if (!BuildDefs::dump()) | |
1679 return; | |
1680 Ostream &Str = Func->getContext()->getStrEmit(); | |
1681 assert(this->getSrcSize() == 2); | |
1682 assert(llvm::isa<Variable>(this->getSrc(0))); | |
1683 assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() == | |
1684 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1685 assert( | |
1686 this->getDest()->getRegNum() == | |
1687 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx? | |
1688 Str << "\tmul" << this->getWidthString(this->getDest()->getType()) << "\t"; | |
1689 this->getSrc(1)->emit(Func); | |
1690 } | |
1691 | |
1692 template <class Machine> | |
1693 void InstX86BaseMul<Machine>::emitIAS(const Cfg *Func) const { | |
1694 assert(this->getSrcSize() == 2); | |
1695 assert(llvm::isa<Variable>(this->getSrc(0))); | |
1696 assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() == | |
1697 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | |
1698 assert( | |
1699 this->getDest()->getRegNum() == | |
1700 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx? | |
1701 const Operand *Src = this->getSrc(1); | |
1702 Type Ty = Src->getType(); | |
1703 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp | |
1704 Emitter = {&InstX86Base<Machine>::Traits::Assembler::mul, | |
1705 &InstX86Base<Machine>::Traits::Assembler::mul}; | |
1706 emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter); | |
1707 } | |
1708 | |
1709 template <class Machine> | |
1710 void InstX86BaseMul<Machine>::dump(const Cfg *Func) const { | |
1711 if (!BuildDefs::dump()) | |
1712 return; | |
1713 Ostream &Str = Func->getContext()->getStrDump(); | |
1714 this->dumpDest(Func); | |
1715 Str << " = mul." << this->getDest()->getType() << " "; | |
1716 this->dumpSources(Func); | |
1717 } | |
1718 | |
1719 template <class Machine> | |
1720 void InstX86BaseShld<Machine>::emit(const Cfg *Func) const { | |
1721 if (!BuildDefs::dump()) | |
1722 return; | |
1723 Ostream &Str = Func->getContext()->getStrEmit(); | |
1724 Variable *Dest = this->getDest(); | |
1725 assert(this->getSrcSize() == 3); | |
1726 assert(Dest == this->getSrc(0)); | |
1727 Str << "\tshld" << this->getWidthString(Dest->getType()) << "\t"; | |
1728 if (const auto ShiftReg = llvm::dyn_cast<Variable>(this->getSrc(2))) { | |
1729 (void)ShiftReg; | |
1730 assert(ShiftReg->getRegNum() == | |
1731 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); | |
1732 Str << "%cl"; | |
1733 } else { | |
1734 this->getSrc(2)->emit(Func); | |
1735 } | |
1736 Str << ", "; | |
1737 this->getSrc(1)->emit(Func); | |
1738 Str << ", "; | |
1739 Dest->emit(Func); | |
1740 } | |
1741 | |
1742 template <class Machine> | |
1743 void InstX86BaseShld<Machine>::emitIAS(const Cfg *Func) const { | |
1744 assert(this->getSrcSize() == 3); | |
1745 assert(this->getDest() == this->getSrc(0)); | |
1746 const Variable *Dest = this->getDest(); | |
1747 const Operand *Src1 = this->getSrc(1); | |
1748 const Operand *Src2 = this->getSrc(2); | |
1749 static const typename InstX86Base< | |
1750 Machine>::Traits::Assembler::GPREmitterShiftD Emitter = { | |
1751 &InstX86Base<Machine>::Traits::Assembler::shld, | |
1752 &InstX86Base<Machine>::Traits::Assembler::shld}; | |
1753 emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter); | |
1754 } | |
1755 | |
1756 template <class Machine> | |
1757 void InstX86BaseShld<Machine>::dump(const Cfg *Func) const { | |
1758 if (!BuildDefs::dump()) | |
1759 return; | |
1760 Ostream &Str = Func->getContext()->getStrDump(); | |
1761 this->dumpDest(Func); | |
1762 Str << " = shld." << this->getDest()->getType() << " "; | |
1763 this->dumpSources(Func); | |
1764 } | |
1765 | |
1766 template <class Machine> | |
1767 void InstX86BaseShrd<Machine>::emit(const Cfg *Func) const { | |
1768 if (!BuildDefs::dump()) | |
1769 return; | |
1770 Ostream &Str = Func->getContext()->getStrEmit(); | |
1771 Variable *Dest = this->getDest(); | |
1772 assert(this->getSrcSize() == 3); | |
1773 assert(Dest == this->getSrc(0)); | |
1774 Str << "\tshrd" << this->getWidthString(Dest->getType()) << "\t"; | |
1775 if (const auto ShiftReg = llvm::dyn_cast<Variable>(this->getSrc(2))) { | |
1776 (void)ShiftReg; | |
1777 assert(ShiftReg->getRegNum() == | |
1778 InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx); | |
1779 Str << "%cl"; | |
1780 } else { | |
1781 this->getSrc(2)->emit(Func); | |
1782 } | |
1783 Str << ", "; | |
1784 this->getSrc(1)->emit(Func); | |
1785 Str << ", "; | |
1786 Dest->emit(Func); | |
1787 } | |
1788 | |
1789 template <class Machine> | |
1790 void InstX86BaseShrd<Machine>::emitIAS(const Cfg *Func) const { | |
1791 assert(this->getSrcSize() == 3); | |
1792 assert(this->getDest() == this->getSrc(0)); | |
1793 const Variable *Dest = this->getDest(); | |
1794 const Operand *Src1 = this->getSrc(1); | |
1795 const Operand *Src2 = this->getSrc(2); | |
1796 static const typename InstX86Base< | |
1797 Machine>::Traits::Assembler::GPREmitterShiftD Emitter = { | |
1798 &InstX86Base<Machine>::Traits::Assembler::shrd, | |
1799 &InstX86Base<Machine>::Traits::Assembler::shrd}; | |
1800 emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter); | |
1801 } | |
1802 | |
1803 template <class Machine> | |
1804 void InstX86BaseShrd<Machine>::dump(const Cfg *Func) const { | |
1805 if (!BuildDefs::dump()) | |
1806 return; | |
1807 Ostream &Str = Func->getContext()->getStrDump(); | |
1808 this->dumpDest(Func); | |
1809 Str << " = shrd." << this->getDest()->getType() << " "; | |
1810 this->dumpSources(Func); | |
1811 } | |
1812 | |
1813 template <class Machine> | |
1814 void InstX86BaseCmov<Machine>::emit(const Cfg *Func) const { | |
1815 if (!BuildDefs::dump()) | |
1816 return; | |
1817 Ostream &Str = Func->getContext()->getStrEmit(); | |
1818 Variable *Dest = this->getDest(); | |
1819 Str << "\t"; | |
1820 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); | |
1821 assert(this->getDest()->hasReg()); | |
1822 Str << "cmov" | |
1823 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString | |
1824 << this->getWidthString(Dest->getType()) << "\t"; | |
1825 this->getSrc(1)->emit(Func); | |
1826 Str << ", "; | |
1827 Dest->emit(Func); | |
1828 } | |
1829 | |
1830 template <class Machine> | |
1831 void InstX86BaseCmov<Machine>::emitIAS(const Cfg *Func) const { | |
1832 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); | |
1833 assert(this->getDest()->hasReg()); | |
1834 assert(this->getSrcSize() == 2); | |
1835 Operand *Src = this->getSrc(1); | |
1836 Type SrcTy = Src->getType(); | |
1837 assert(SrcTy == IceType_i16 || SrcTy == IceType_i32); | |
1838 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
1839 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
1840 if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) { | |
1841 if (SrcVar->hasReg()) { | |
1842 Asm->cmov(SrcTy, Condition, | |
1843 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
1844 this->getDest()->getRegNum()), | |
1845 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
1846 SrcVar->getRegNum())); | |
1847 } else { | |
1848 Asm->cmov( | |
1849 SrcTy, Condition, | |
1850 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
1851 this->getDest()->getRegNum()), | |
1852 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1853 Func->getTarget()) | |
1854 ->stackVarToAsmOperand(SrcVar)); | |
1855 } | |
1856 } else if (const auto Mem = llvm::dyn_cast< | |
1857 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { | |
1858 assert(Mem->getSegmentRegister() == | |
1859 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
1860 Asm->cmov(SrcTy, Condition, | |
1861 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
1862 this->getDest()->getRegNum()), | |
1863 Mem->toAsmAddress(Asm)); | |
1864 } else { | |
1865 llvm_unreachable("Unexpected operand type"); | |
1866 } | |
1867 } | |
1868 | |
1869 template <class Machine> | |
1870 void InstX86BaseCmov<Machine>::dump(const Cfg *Func) const { | |
1871 if (!BuildDefs::dump()) | |
1872 return; | |
1873 Ostream &Str = Func->getContext()->getStrDump(); | |
1874 Str << "cmov" | |
1875 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString | |
1876 << "."; | |
1877 Str << this->getDest()->getType() << " "; | |
1878 this->dumpDest(Func); | |
1879 Str << ", "; | |
1880 this->dumpSources(Func); | |
1881 } | |
1882 | |
1883 template <class Machine> | |
1884 void InstX86BaseCmpps<Machine>::emit(const Cfg *Func) const { | |
1885 if (!BuildDefs::dump()) | |
1886 return; | |
1887 Ostream &Str = Func->getContext()->getStrEmit(); | |
1888 assert(this->getSrcSize() == 2); | |
1889 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); | |
1890 Str << "\t"; | |
1891 Str << "cmp" | |
1892 << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString | |
1893 << "ps" | |
1894 << "\t"; | |
1895 this->getSrc(1)->emit(Func); | |
1896 Str << ", "; | |
1897 this->getDest()->emit(Func); | |
1898 } | |
1899 | |
1900 template <class Machine> | |
1901 void InstX86BaseCmpps<Machine>::emitIAS(const Cfg *Func) const { | |
1902 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
1903 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
1904 assert(this->getSrcSize() == 2); | |
1905 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); | |
1906 // Assuming there isn't any load folding for cmpps, and vector constants | |
1907 // are not allowed in PNaCl. | |
1908 assert(llvm::isa<Variable>(this->getSrc(1))); | |
1909 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); | |
1910 if (SrcVar->hasReg()) { | |
1911 Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
1912 this->getDest()->getRegNum()), | |
1913 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
1914 SrcVar->getRegNum()), | |
1915 Condition); | |
1916 } else { | |
1917 typename InstX86Base<Machine>::Traits::Address SrcStackAddr = | |
1918 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
1919 Func->getTarget()) | |
1920 ->stackVarToAsmOperand(SrcVar); | |
1921 Asm->cmpps(InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
1922 this->getDest()->getRegNum()), | |
1923 SrcStackAddr, Condition); | |
1924 } | |
1925 } | |
1926 | |
1927 template <class Machine> | |
1928 void InstX86BaseCmpps<Machine>::dump(const Cfg *Func) const { | |
1929 if (!BuildDefs::dump()) | |
1930 return; | |
1931 Ostream &Str = Func->getContext()->getStrDump(); | |
1932 assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid); | |
1933 this->dumpDest(Func); | |
1934 Str << " = cmp" | |
1935 << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString | |
1936 << "ps" | |
1937 << "\t"; | |
1938 this->dumpSources(Func); | |
1939 } | |
1940 | |
1941 template <class Machine> | |
1942 void InstX86BaseCmpxchg<Machine>::emit(const Cfg *Func) const { | |
1943 if (!BuildDefs::dump()) | |
1944 return; | |
1945 Ostream &Str = Func->getContext()->getStrEmit(); | |
1946 assert(this->getSrcSize() == 3); | |
1947 if (this->Locked) { | |
1948 Str << "\tlock"; | |
1949 } | |
1950 Str << "\tcmpxchg" << this->getWidthString(this->getSrc(0)->getType()) | |
1951 << "\t"; | |
1952 this->getSrc(2)->emit(Func); | |
1953 Str << ", "; | |
1954 this->getSrc(0)->emit(Func); | |
1955 } | |
1956 | |
1957 template <class Machine> | |
1958 void InstX86BaseCmpxchg<Machine>::emitIAS(const Cfg *Func) const { | |
1959 assert(this->getSrcSize() == 3); | |
1960 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
1961 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
1962 Type Ty = this->getSrc(0)->getType(); | |
1963 const auto Mem = | |
1964 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
1965 this->getSrc(0)); | |
1966 assert(Mem->getSegmentRegister() == | |
1967 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
1968 const typename InstX86Base<Machine>::Traits::Address Addr = | |
1969 Mem->toAsmAddress(Asm); | |
1970 const auto VarReg = llvm::cast<Variable>(this->getSrc(2)); | |
1971 assert(VarReg->hasReg()); | |
1972 const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = | |
1973 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
1974 VarReg->getRegNum()); | |
1975 Asm->cmpxchg(Ty, Addr, Reg, this->Locked); | |
1976 } | |
1977 | |
1978 template <class Machine> | |
1979 void InstX86BaseCmpxchg<Machine>::dump(const Cfg *Func) const { | |
1980 if (!BuildDefs::dump()) | |
1981 return; | |
1982 Ostream &Str = Func->getContext()->getStrDump(); | |
1983 if (this->Locked) { | |
1984 Str << "lock "; | |
1985 } | |
1986 Str << "cmpxchg." << this->getSrc(0)->getType() << " "; | |
1987 this->dumpSources(Func); | |
1988 } | |
1989 | |
1990 template <class Machine> | |
1991 void InstX86BaseCmpxchg8b<Machine>::emit(const Cfg *Func) const { | |
1992 if (!BuildDefs::dump()) | |
1993 return; | |
1994 Ostream &Str = Func->getContext()->getStrEmit(); | |
1995 assert(this->getSrcSize() == 5); | |
1996 if (this->Locked) { | |
1997 Str << "\tlock"; | |
1998 } | |
1999 Str << "\tcmpxchg8b\t"; | |
2000 this->getSrc(0)->emit(Func); | |
2001 } | |
2002 | |
2003 template <class Machine> | |
2004 void InstX86BaseCmpxchg8b<Machine>::emitIAS(const Cfg *Func) const { | |
2005 assert(this->getSrcSize() == 5); | |
2006 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2007 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2008 const auto Mem = | |
2009 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
2010 this->getSrc(0)); | |
2011 assert(Mem->getSegmentRegister() == | |
2012 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
2013 const typename InstX86Base<Machine>::Traits::Address Addr = | |
2014 Mem->toAsmAddress(Asm); | |
2015 Asm->cmpxchg8b(Addr, this->Locked); | |
2016 } | |
2017 | |
2018 template <class Machine> | |
2019 void InstX86BaseCmpxchg8b<Machine>::dump(const Cfg *Func) const { | |
2020 if (!BuildDefs::dump()) | |
2021 return; | |
2022 Ostream &Str = Func->getContext()->getStrDump(); | |
2023 if (this->Locked) { | |
2024 Str << "lock "; | |
2025 } | |
2026 Str << "cmpxchg8b "; | |
2027 this->dumpSources(Func); | |
2028 } | |
2029 | |
2030 template <class Machine> | |
2031 void InstX86BaseCvt<Machine>::emit(const Cfg *Func) const { | |
2032 if (!BuildDefs::dump()) | |
2033 return; | |
2034 Ostream &Str = Func->getContext()->getStrEmit(); | |
2035 assert(this->getSrcSize() == 1); | |
2036 Str << "\tcvt"; | |
2037 if (isTruncating()) | |
2038 Str << "t"; | |
2039 Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) | |
2040 ->getType()] | |
2041 .CvtString << "2" | |
2042 << InstX86Base< | |
2043 Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
2044 .CvtString << "\t"; | |
2045 this->getSrc(0)->emit(Func); | |
2046 Str << ", "; | |
2047 this->getDest()->emit(Func); | |
2048 } | |
2049 | |
2050 template <class Machine> | |
2051 void InstX86BaseCvt<Machine>::emitIAS(const Cfg *Func) const { | |
2052 assert(this->getSrcSize() == 1); | |
2053 const Variable *Dest = this->getDest(); | |
2054 const Operand *Src = this->getSrc(0); | |
2055 Type DestTy = Dest->getType(); | |
2056 Type SrcTy = Src->getType(); | |
2057 switch (Variant) { | |
2058 case Si2ss: { | |
2059 assert(isScalarIntegerType(SrcTy)); | |
2060 assert(typeWidthInBytes(SrcTy) <= 4); | |
2061 assert(isScalarFloatingType(DestTy)); | |
2062 static const typename InstX86Base<Machine>::Traits::Assembler:: | |
2063 template CastEmitterRegOp< | |
2064 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
2065 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister> | |
2066 Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvtsi2ss, | |
2067 &InstX86Base<Machine>::Traits::Assembler::cvtsi2ss}; | |
2068 emitIASCastRegOp< | |
2069 Machine, | |
2070 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
2071 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | |
2072 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, | |
2073 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR>( | |
2074 Func, DestTy, Dest, Src, Emitter); | |
2075 return; | |
2076 } | |
2077 case Tss2si: { | |
2078 assert(isScalarFloatingType(SrcTy)); | |
2079 assert(isScalarIntegerType(DestTy)); | |
2080 assert(typeWidthInBytes(DestTy) <= 4); | |
2081 static const typename InstX86Base<Machine>::Traits::Assembler:: | |
2082 template CastEmitterRegOp< | |
2083 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | |
2084 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> | |
2085 Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvttss2si, | |
2086 &InstX86Base<Machine>::Traits::Assembler::cvttss2si}; | |
2087 emitIASCastRegOp< | |
2088 Machine, | |
2089 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | |
2090 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
2091 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR, | |
2092 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( | |
2093 Func, SrcTy, Dest, Src, Emitter); | |
2094 return; | |
2095 } | |
2096 case Float2float: { | |
2097 assert(isScalarFloatingType(SrcTy)); | |
2098 assert(isScalarFloatingType(DestTy)); | |
2099 assert(DestTy != SrcTy); | |
2100 static const typename InstX86Base< | |
2101 Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = { | |
2102 &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float, | |
2103 &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float}; | |
2104 emitIASRegOpTyXMM<Machine>(Func, SrcTy, Dest, Src, Emitter); | |
2105 return; | |
2106 } | |
2107 case Dq2ps: { | |
2108 assert(isVectorIntegerType(SrcTy)); | |
2109 assert(isVectorFloatingType(DestTy)); | |
2110 static const typename InstX86Base< | |
2111 Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = { | |
2112 &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps, | |
2113 &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps}; | |
2114 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter); | |
2115 return; | |
2116 } | |
2117 case Tps2dq: { | |
2118 assert(isVectorFloatingType(SrcTy)); | |
2119 assert(isVectorIntegerType(DestTy)); | |
2120 static const typename InstX86Base< | |
2121 Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = { | |
2122 &InstX86Base<Machine>::Traits::Assembler::cvttps2dq, | |
2123 &InstX86Base<Machine>::Traits::Assembler::cvttps2dq}; | |
2124 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter); | |
2125 return; | |
2126 } | |
2127 } | |
2128 } | |
2129 | |
2130 template <class Machine> | |
2131 void InstX86BaseCvt<Machine>::dump(const Cfg *Func) const { | |
2132 if (!BuildDefs::dump()) | |
2133 return; | |
2134 Ostream &Str = Func->getContext()->getStrDump(); | |
2135 this->dumpDest(Func); | |
2136 Str << " = cvt"; | |
2137 if (isTruncating()) | |
2138 Str << "t"; | |
2139 Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) | |
2140 ->getType()] | |
2141 .CvtString << "2" | |
2142 << InstX86Base< | |
2143 Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
2144 .CvtString << " "; | |
2145 this->dumpSources(Func); | |
2146 } | |
2147 | |
2148 template <class Machine> | |
2149 void InstX86BaseIcmp<Machine>::emit(const Cfg *Func) const { | |
2150 if (!BuildDefs::dump()) | |
2151 return; | |
2152 Ostream &Str = Func->getContext()->getStrEmit(); | |
2153 assert(this->getSrcSize() == 2); | |
2154 Str << "\tcmp" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; | |
2155 this->getSrc(1)->emit(Func); | |
2156 Str << ", "; | |
2157 this->getSrc(0)->emit(Func); | |
2158 } | |
2159 | |
2160 template <class Machine> | |
2161 void InstX86BaseIcmp<Machine>::emitIAS(const Cfg *Func) const { | |
2162 assert(this->getSrcSize() == 2); | |
2163 const Operand *Src0 = this->getSrc(0); | |
2164 const Operand *Src1 = this->getSrc(1); | |
2165 Type Ty = Src0->getType(); | |
2166 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp | |
2167 RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::cmp, | |
2168 &InstX86Base<Machine>::Traits::Assembler::cmp, | |
2169 &InstX86Base<Machine>::Traits::Assembler::cmp}; | |
2170 static const typename InstX86Base< | |
2171 Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = { | |
2172 &InstX86Base<Machine>::Traits::Assembler::cmp, | |
2173 &InstX86Base<Machine>::Traits::Assembler::cmp}; | |
2174 if (const auto SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { | |
2175 if (SrcVar0->hasReg()) { | |
2176 emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter); | |
2177 return; | |
2178 } | |
2179 } | |
2180 emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter); | |
2181 } | |
2182 | |
2183 template <class Machine> | |
2184 void InstX86BaseIcmp<Machine>::dump(const Cfg *Func) const { | |
2185 if (!BuildDefs::dump()) | |
2186 return; | |
2187 Ostream &Str = Func->getContext()->getStrDump(); | |
2188 Str << "cmp." << this->getSrc(0)->getType() << " "; | |
2189 this->dumpSources(Func); | |
2190 } | |
2191 | |
2192 template <class Machine> | |
2193 void InstX86BaseUcomiss<Machine>::emit(const Cfg *Func) const { | |
2194 if (!BuildDefs::dump()) | |
2195 return; | |
2196 Ostream &Str = Func->getContext()->getStrEmit(); | |
2197 assert(this->getSrcSize() == 2); | |
2198 Str << "\tucomi" | |
2199 << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) | |
2200 ->getType()] | |
2201 .SdSsString << "\t"; | |
2202 this->getSrc(1)->emit(Func); | |
2203 Str << ", "; | |
2204 this->getSrc(0)->emit(Func); | |
2205 } | |
2206 | |
2207 template <class Machine> | |
2208 void InstX86BaseUcomiss<Machine>::emitIAS(const Cfg *Func) const { | |
2209 assert(this->getSrcSize() == 2); | |
2210 // Currently src0 is always a variable by convention, to avoid having | |
2211 // two memory operands. | |
2212 assert(llvm::isa<Variable>(this->getSrc(0))); | |
2213 const auto Src0Var = llvm::cast<Variable>(this->getSrc(0)); | |
2214 Type Ty = Src0Var->getType(); | |
2215 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | |
2216 Emitter = {&InstX86Base<Machine>::Traits::Assembler::ucomiss, | |
2217 &InstX86Base<Machine>::Traits::Assembler::ucomiss}; | |
2218 emitIASRegOpTyXMM<Machine>(Func, Ty, Src0Var, this->getSrc(1), Emitter); | |
2219 } | |
2220 | |
2221 template <class Machine> | |
2222 void InstX86BaseUcomiss<Machine>::dump(const Cfg *Func) const { | |
2223 if (!BuildDefs::dump()) | |
2224 return; | |
2225 Ostream &Str = Func->getContext()->getStrDump(); | |
2226 Str << "ucomiss." << this->getSrc(0)->getType() << " "; | |
2227 this->dumpSources(Func); | |
2228 } | |
2229 | |
2230 template <class Machine> | |
2231 void InstX86BaseUD2<Machine>::emit(const Cfg *Func) const { | |
2232 if (!BuildDefs::dump()) | |
2233 return; | |
2234 Ostream &Str = Func->getContext()->getStrEmit(); | |
2235 assert(this->getSrcSize() == 0); | |
2236 Str << "\tud2"; | |
2237 } | |
2238 | |
2239 template <class Machine> | |
2240 void InstX86BaseUD2<Machine>::emitIAS(const Cfg *Func) const { | |
2241 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2242 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2243 Asm->ud2(); | |
2244 } | |
2245 | |
2246 template <class Machine> | |
2247 void InstX86BaseUD2<Machine>::dump(const Cfg *Func) const { | |
2248 if (!BuildDefs::dump()) | |
2249 return; | |
2250 Ostream &Str = Func->getContext()->getStrDump(); | |
2251 Str << "ud2"; | |
2252 } | |
2253 | |
2254 template <class Machine> | |
2255 void InstX86BaseTest<Machine>::emit(const Cfg *Func) const { | |
2256 if (!BuildDefs::dump()) | |
2257 return; | |
2258 Ostream &Str = Func->getContext()->getStrEmit(); | |
2259 assert(this->getSrcSize() == 2); | |
2260 Str << "\ttest" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; | |
2261 this->getSrc(1)->emit(Func); | |
2262 Str << ", "; | |
2263 this->getSrc(0)->emit(Func); | |
2264 } | |
2265 | |
2266 template <class Machine> | |
2267 void InstX86BaseTest<Machine>::emitIAS(const Cfg *Func) const { | |
2268 assert(this->getSrcSize() == 2); | |
2269 const Operand *Src0 = this->getSrc(0); | |
2270 const Operand *Src1 = this->getSrc(1); | |
2271 Type Ty = Src0->getType(); | |
2272 // The Reg/Addr form of test is not encodeable. | |
2273 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp | |
2274 RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::test, nullptr, | |
2275 &InstX86Base<Machine>::Traits::Assembler::test}; | |
2276 static const typename InstX86Base< | |
2277 Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = { | |
2278 &InstX86Base<Machine>::Traits::Assembler::test, | |
2279 &InstX86Base<Machine>::Traits::Assembler::test}; | |
2280 if (const auto SrcVar0 = llvm::dyn_cast<Variable>(Src0)) { | |
2281 if (SrcVar0->hasReg()) { | |
2282 emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter); | |
2283 return; | |
2284 } | |
2285 } | |
2286 llvm_unreachable("Nothing actually generates this so it's untested"); | |
2287 emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter); | |
2288 } | |
2289 | |
2290 template <class Machine> | |
2291 void InstX86BaseTest<Machine>::dump(const Cfg *Func) const { | |
2292 if (!BuildDefs::dump()) | |
2293 return; | |
2294 Ostream &Str = Func->getContext()->getStrDump(); | |
2295 Str << "test." << this->getSrc(0)->getType() << " "; | |
2296 this->dumpSources(Func); | |
2297 } | |
2298 | |
2299 template <class Machine> | |
2300 void InstX86BaseMfence<Machine>::emit(const Cfg *Func) const { | |
2301 if (!BuildDefs::dump()) | |
2302 return; | |
2303 Ostream &Str = Func->getContext()->getStrEmit(); | |
2304 assert(this->getSrcSize() == 0); | |
2305 Str << "\tmfence"; | |
2306 } | |
2307 | |
2308 template <class Machine> | |
2309 void InstX86BaseMfence<Machine>::emitIAS(const Cfg *Func) const { | |
2310 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2311 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2312 Asm->mfence(); | |
2313 } | |
2314 | |
2315 template <class Machine> | |
2316 void InstX86BaseMfence<Machine>::dump(const Cfg *Func) const { | |
2317 if (!BuildDefs::dump()) | |
2318 return; | |
2319 Ostream &Str = Func->getContext()->getStrDump(); | |
2320 Str << "mfence"; | |
2321 } | |
2322 | |
2323 template <class Machine> | |
2324 void InstX86BaseStore<Machine>::emit(const Cfg *Func) const { | |
2325 if (!BuildDefs::dump()) | |
2326 return; | |
2327 Ostream &Str = Func->getContext()->getStrEmit(); | |
2328 assert(this->getSrcSize() == 2); | |
2329 Type Ty = this->getSrc(0)->getType(); | |
2330 Str << "\tmov" << this->getWidthString(Ty) | |
2331 << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t"; | |
2332 this->getSrc(0)->emit(Func); | |
2333 Str << ", "; | |
2334 this->getSrc(1)->emit(Func); | |
2335 } | |
2336 | |
2337 template <class Machine> | |
2338 void InstX86BaseStore<Machine>::emitIAS(const Cfg *Func) const { | |
2339 assert(this->getSrcSize() == 2); | |
2340 const Operand *Dest = this->getSrc(1); | |
2341 const Operand *Src = this->getSrc(0); | |
2342 Type DestTy = Dest->getType(); | |
2343 if (isScalarFloatingType(DestTy)) { | |
2344 // Src must be a register, since Dest is a Mem operand of some kind. | |
2345 const auto SrcVar = llvm::cast<Variable>(Src); | |
2346 assert(SrcVar->hasReg()); | |
2347 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = | |
2348 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2349 SrcVar->getRegNum()); | |
2350 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2351 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2352 if (const auto DestVar = llvm::dyn_cast<Variable>(Dest)) { | |
2353 assert(!DestVar->hasReg()); | |
2354 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
2355 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
2356 Func->getTarget()) | |
2357 ->stackVarToAsmOperand(DestVar)); | |
2358 Asm->movss(DestTy, StackAddr, SrcReg); | |
2359 } else { | |
2360 const auto DestMem = | |
2361 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
2362 Dest); | |
2363 assert(DestMem->getSegmentRegister() == | |
2364 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
2365 Asm->movss(DestTy, DestMem->toAsmAddress(Asm), SrcReg); | |
2366 } | |
2367 return; | |
2368 } else { | |
2369 assert(isScalarIntegerType(DestTy)); | |
2370 static const typename InstX86Base< | |
2371 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { | |
2372 &InstX86Base<Machine>::Traits::Assembler::mov, | |
2373 &InstX86Base<Machine>::Traits::Assembler::mov}; | |
2374 emitIASAsAddrOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRAddrEmitter); | |
2375 } | |
2376 } | |
2377 | |
2378 template <class Machine> | |
2379 void InstX86BaseStore<Machine>::dump(const Cfg *Func) const { | |
2380 if (!BuildDefs::dump()) | |
2381 return; | |
2382 Ostream &Str = Func->getContext()->getStrDump(); | |
2383 Str << "mov." << this->getSrc(0)->getType() << " "; | |
2384 this->getSrc(1)->dump(Func); | |
2385 Str << ", "; | |
2386 this->getSrc(0)->dump(Func); | |
2387 } | |
2388 | |
2389 template <class Machine> | |
2390 void InstX86BaseStoreP<Machine>::emit(const Cfg *Func) const { | |
2391 if (!BuildDefs::dump()) | |
2392 return; | |
2393 Ostream &Str = Func->getContext()->getStrEmit(); | |
2394 assert(this->getSrcSize() == 2); | |
2395 Str << "\tmovups\t"; | |
2396 this->getSrc(0)->emit(Func); | |
2397 Str << ", "; | |
2398 this->getSrc(1)->emit(Func); | |
2399 } | |
2400 | |
2401 template <class Machine> | |
2402 void InstX86BaseStoreP<Machine>::emitIAS(const Cfg *Func) const { | |
2403 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2404 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2405 assert(this->getSrcSize() == 2); | |
2406 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); | |
2407 const auto DestMem = | |
2408 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
2409 this->getSrc(1)); | |
2410 assert(DestMem->getSegmentRegister() == | |
2411 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
2412 assert(SrcVar->hasReg()); | |
2413 Asm->movups(DestMem->toAsmAddress(Asm), | |
2414 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2415 SrcVar->getRegNum())); | |
2416 } | |
2417 | |
2418 template <class Machine> | |
2419 void InstX86BaseStoreP<Machine>::dump(const Cfg *Func) const { | |
2420 if (!BuildDefs::dump()) | |
2421 return; | |
2422 Ostream &Str = Func->getContext()->getStrDump(); | |
2423 Str << "storep." << this->getSrc(0)->getType() << " "; | |
2424 this->getSrc(1)->dump(Func); | |
2425 Str << ", "; | |
2426 this->getSrc(0)->dump(Func); | |
2427 } | |
2428 | |
2429 template <class Machine> | |
2430 void InstX86BaseStoreQ<Machine>::emit(const Cfg *Func) const { | |
2431 if (!BuildDefs::dump()) | |
2432 return; | |
2433 Ostream &Str = Func->getContext()->getStrEmit(); | |
2434 assert(this->getSrcSize() == 2); | |
2435 assert(this->getSrc(1)->getType() == IceType_i64 || | |
2436 this->getSrc(1)->getType() == IceType_f64); | |
2437 Str << "\tmovq\t"; | |
2438 this->getSrc(0)->emit(Func); | |
2439 Str << ", "; | |
2440 this->getSrc(1)->emit(Func); | |
2441 } | |
2442 | |
2443 template <class Machine> | |
2444 void InstX86BaseStoreQ<Machine>::emitIAS(const Cfg *Func) const { | |
2445 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2446 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2447 assert(this->getSrcSize() == 2); | |
2448 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); | |
2449 const auto DestMem = | |
2450 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
2451 this->getSrc(1)); | |
2452 assert(DestMem->getSegmentRegister() == | |
2453 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
2454 assert(SrcVar->hasReg()); | |
2455 Asm->movq(DestMem->toAsmAddress(Asm), | |
2456 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2457 SrcVar->getRegNum())); | |
2458 } | |
2459 | |
2460 template <class Machine> | |
2461 void InstX86BaseStoreQ<Machine>::dump(const Cfg *Func) const { | |
2462 if (!BuildDefs::dump()) | |
2463 return; | |
2464 Ostream &Str = Func->getContext()->getStrDump(); | |
2465 Str << "storeq." << this->getSrc(0)->getType() << " "; | |
2466 this->getSrc(1)->dump(Func); | |
2467 Str << ", "; | |
2468 this->getSrc(0)->dump(Func); | |
2469 } | |
2470 | |
2471 template <class Machine> | |
2472 void InstX86BaseLea<Machine>::emit(const Cfg *Func) const { | |
2473 if (!BuildDefs::dump()) | |
2474 return; | |
2475 Ostream &Str = Func->getContext()->getStrEmit(); | |
2476 assert(this->getSrcSize() == 1); | |
2477 assert(this->getDest()->hasReg()); | |
2478 Str << "\tleal\t"; | |
2479 Operand *Src0 = this->getSrc(0); | |
2480 if (const auto Src0Var = llvm::dyn_cast<Variable>(Src0)) { | |
2481 Type Ty = Src0Var->getType(); | |
2482 // lea on x86-32 doesn't accept mem128 operands, so cast VSrc0 to an | |
2483 // acceptable type. | |
2484 Src0Var->asType(isVectorType(Ty) ? IceType_i32 : Ty)->emit(Func); | |
2485 } else { | |
2486 Src0->emit(Func); | |
2487 } | |
2488 Str << ", "; | |
2489 this->getDest()->emit(Func); | |
2490 } | |
2491 | |
2492 template <class Machine> | |
2493 void InstX86BaseMov<Machine>::emit(const Cfg *Func) const { | |
2494 if (!BuildDefs::dump()) | |
2495 return; | |
2496 Ostream &Str = Func->getContext()->getStrEmit(); | |
2497 assert(this->getSrcSize() == 1); | |
2498 Operand *Src = this->getSrc(0); | |
2499 Type SrcTy = Src->getType(); | |
2500 Type DestTy = this->getDest()->getType(); | |
2501 Str << "\tmov" | |
2502 << (!isScalarFloatingType(DestTy) | |
2503 ? this->getWidthString(SrcTy) | |
2504 : InstX86Base<Machine>::Traits::TypeAttributes[DestTy].SdSsString) | |
2505 << "\t"; | |
2506 // For an integer truncation operation, src is wider than dest. | |
2507 // Ideally, we use a mov instruction whose data width matches the | |
2508 // narrower dest. This is a problem if e.g. src is a register like | |
2509 // esi or si where there is no 8-bit version of the register. To be | |
2510 // safe, we instead widen the dest to match src. This works even | |
2511 // for stack-allocated dest variables because typeWidthOnStack() | |
2512 // pads to a 4-byte boundary even if only a lower portion is used. | |
2513 // TODO: This assert disallows usages such as copying a floating point | |
2514 // value between a vector and a scalar (which movss is used for). | |
2515 // Clean this up. | |
2516 assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) == | |
2517 Func->getTarget()->typeWidthInBytesOnStack(SrcTy)); | |
2518 Src->emit(Func); | |
2519 Str << ", "; | |
2520 this->getDest()->asType(SrcTy)->emit(Func); | |
2521 } | |
2522 | |
2523 template <class Machine> | |
2524 void InstX86BaseMov<Machine>::emitIAS(const Cfg *Func) const { | |
2525 assert(this->getSrcSize() == 1); | |
2526 const Variable *Dest = this->getDest(); | |
2527 const Operand *Src = this->getSrc(0); | |
2528 Type DestTy = Dest->getType(); | |
2529 Type SrcTy = Src->getType(); | |
2530 // Mov can be used for GPRs or XMM registers. Also, the type does not | |
2531 // necessarily match (Mov can be used for bitcasts). However, when | |
2532 // the type does not match, one of the operands must be a register. | |
2533 // Thus, the strategy is to find out if Src or Dest are a register, | |
2534 // then use that register's type to decide on which emitter set to use. | |
2535 // The emitter set will include reg-reg movs, but that case should | |
2536 // be unused when the types don't match. | |
2537 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | |
2538 XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss, | |
2539 &InstX86Base<Machine>::Traits::Assembler::movss}; | |
2540 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp | |
2541 GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov, | |
2542 &InstX86Base<Machine>::Traits::Assembler::mov, | |
2543 &InstX86Base<Machine>::Traits::Assembler::mov}; | |
2544 static const typename InstX86Base< | |
2545 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { | |
2546 &InstX86Base<Machine>::Traits::Assembler::mov, | |
2547 &InstX86Base<Machine>::Traits::Assembler::mov}; | |
2548 // For an integer truncation operation, src is wider than dest. | |
2549 // Ideally, we use a mov instruction whose data width matches the | |
2550 // narrower dest. This is a problem if e.g. src is a register like | |
2551 // esi or si where there is no 8-bit version of the register. To be | |
2552 // safe, we instead widen the dest to match src. This works even | |
2553 // for stack-allocated dest variables because typeWidthOnStack() | |
2554 // pads to a 4-byte boundary even if only a lower portion is used. | |
2555 // TODO: This assert disallows usages such as copying a floating point | |
2556 // value between a vector and a scalar (which movss is used for). | |
2557 // Clean this up. | |
2558 assert( | |
2559 Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) == | |
2560 Func->getTarget()->typeWidthInBytesOnStack(Src->getType())); | |
2561 if (Dest->hasReg()) { | |
2562 if (isScalarFloatingType(DestTy)) { | |
2563 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter); | |
2564 return; | |
2565 } else { | |
2566 assert(isScalarIntegerType(DestTy)); | |
2567 // Widen DestTy for truncation (see above note). We should only do this | |
2568 // when both Src and Dest are integer types. | |
2569 if (isScalarIntegerType(SrcTy)) { | |
2570 DestTy = SrcTy; | |
2571 } | |
2572 emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter); | |
2573 return; | |
2574 } | |
2575 } else { | |
2576 // Dest must be Stack and Src *could* be a register. Use Src's type | |
2577 // to decide on the emitters. | |
2578 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
2579 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
2580 Func->getTarget()) | |
2581 ->stackVarToAsmOperand(Dest)); | |
2582 if (isScalarFloatingType(SrcTy)) { | |
2583 // Src must be a register. | |
2584 const auto SrcVar = llvm::cast<Variable>(Src); | |
2585 assert(SrcVar->hasReg()); | |
2586 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2587 Func->getAssembler< | |
2588 typename InstX86Base<Machine>::Traits::Assembler>(); | |
2589 Asm->movss(SrcTy, StackAddr, | |
2590 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2591 SrcVar->getRegNum())); | |
2592 return; | |
2593 } else { | |
2594 // Src can be a register or immediate. | |
2595 assert(isScalarIntegerType(SrcTy)); | |
2596 emitIASAddrOpTyGPR<Machine>(Func, SrcTy, StackAddr, Src, GPRAddrEmitter); | |
2597 return; | |
2598 } | |
2599 return; | |
2600 } | |
2601 } | |
2602 | |
2603 template <class Machine> | |
2604 void InstX86BaseMovd<Machine>::emitIAS(const Cfg *Func) const { | |
2605 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2606 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2607 assert(this->getSrcSize() == 1); | |
2608 const Variable *Dest = this->getDest(); | |
2609 const auto SrcVar = llvm::cast<Variable>(this->getSrc(0)); | |
2610 // For insert/extract element (one of Src/Dest is an Xmm vector and | |
2611 // the other is an int type). | |
2612 if (SrcVar->getType() == IceType_i32) { | |
2613 assert(isVectorType(Dest->getType())); | |
2614 assert(Dest->hasReg()); | |
2615 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg = | |
2616 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2617 Dest->getRegNum()); | |
2618 if (SrcVar->hasReg()) { | |
2619 Asm->movd(DestReg, | |
2620 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
2621 SrcVar->getRegNum())); | |
2622 } else { | |
2623 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
2624 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
2625 Func->getTarget()) | |
2626 ->stackVarToAsmOperand(SrcVar)); | |
2627 Asm->movd(DestReg, StackAddr); | |
2628 } | |
2629 } else { | |
2630 assert(isVectorType(SrcVar->getType())); | |
2631 assert(SrcVar->hasReg()); | |
2632 assert(Dest->getType() == IceType_i32); | |
2633 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg = | |
2634 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2635 SrcVar->getRegNum()); | |
2636 if (Dest->hasReg()) { | |
2637 Asm->movd(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
2638 Dest->getRegNum()), | |
2639 SrcReg); | |
2640 } else { | |
2641 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
2642 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
2643 Func->getTarget()) | |
2644 ->stackVarToAsmOperand(Dest)); | |
2645 Asm->movd(StackAddr, SrcReg); | |
2646 } | |
2647 } | |
2648 } | |
2649 | |
2650 template <class Machine> | |
2651 void InstX86BaseMovp<Machine>::emit(const Cfg *Func) const { | |
2652 if (!BuildDefs::dump()) | |
2653 return; | |
2654 // TODO(wala,stichnot): movups works with all vector operands, but | |
2655 // there exist other instructions (movaps, movdqa, movdqu) that may | |
2656 // perform better, depending on the data type and alignment of the | |
2657 // operands. | |
2658 Ostream &Str = Func->getContext()->getStrEmit(); | |
2659 assert(this->getSrcSize() == 1); | |
2660 Str << "\tmovups\t"; | |
2661 this->getSrc(0)->emit(Func); | |
2662 Str << ", "; | |
2663 this->getDest()->emit(Func); | |
2664 } | |
2665 | |
2666 template <class Machine> | |
2667 void InstX86BaseMovp<Machine>::emitIAS(const Cfg *Func) const { | |
2668 assert(this->getSrcSize() == 1); | |
2669 assert(isVectorType(this->getDest()->getType())); | |
2670 const Variable *Dest = this->getDest(); | |
2671 const Operand *Src = this->getSrc(0); | |
2672 static const typename InstX86Base< | |
2673 Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = { | |
2674 &InstX86Base<Machine>::Traits::Assembler::movups, | |
2675 &InstX86Base<Machine>::Traits::Assembler::movups, | |
2676 &InstX86Base<Machine>::Traits::Assembler::movups}; | |
2677 emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter); | |
2678 } | |
2679 | |
2680 template <class Machine> | |
2681 void InstX86BaseMovq<Machine>::emit(const Cfg *Func) const { | |
2682 if (!BuildDefs::dump()) | |
2683 return; | |
2684 Ostream &Str = Func->getContext()->getStrEmit(); | |
2685 assert(this->getSrcSize() == 1); | |
2686 assert(this->getDest()->getType() == IceType_i64 || | |
2687 this->getDest()->getType() == IceType_f64); | |
2688 Str << "\tmovq\t"; | |
2689 this->getSrc(0)->emit(Func); | |
2690 Str << ", "; | |
2691 this->getDest()->emit(Func); | |
2692 } | |
2693 | |
2694 template <class Machine> | |
2695 void InstX86BaseMovq<Machine>::emitIAS(const Cfg *Func) const { | |
2696 assert(this->getSrcSize() == 1); | |
2697 assert(this->getDest()->getType() == IceType_i64 || | |
2698 this->getDest()->getType() == IceType_f64); | |
2699 const Variable *Dest = this->getDest(); | |
2700 const Operand *Src = this->getSrc(0); | |
2701 static const typename InstX86Base< | |
2702 Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = { | |
2703 &InstX86Base<Machine>::Traits::Assembler::movq, | |
2704 &InstX86Base<Machine>::Traits::Assembler::movq, | |
2705 &InstX86Base<Machine>::Traits::Assembler::movq}; | |
2706 emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter); | |
2707 } | |
2708 | |
2709 template <class Machine> | |
2710 void InstX86BaseMovssRegs<Machine>::emitIAS(const Cfg *Func) const { | |
2711 // This is Binop variant is only intended to be used for reg-reg moves | |
2712 // where part of the Dest register is untouched. | |
2713 assert(this->getSrcSize() == 2); | |
2714 const Variable *Dest = this->getDest(); | |
2715 assert(Dest == this->getSrc(0)); | |
2716 const auto SrcVar = llvm::cast<Variable>(this->getSrc(1)); | |
2717 assert(Dest->hasReg() && SrcVar->hasReg()); | |
2718 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2719 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2720 Asm->movss(IceType_f32, | |
2721 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2722 Dest->getRegNum()), | |
2723 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2724 SrcVar->getRegNum())); | |
2725 } | |
2726 | |
2727 template <class Machine> | |
2728 void InstX86BaseMovsx<Machine>::emitIAS(const Cfg *Func) const { | |
2729 assert(this->getSrcSize() == 1); | |
2730 const Variable *Dest = this->getDest(); | |
2731 const Operand *Src = this->getSrc(0); | |
2732 // Dest must be a > 8-bit register, but Src can be 8-bit. In practice | |
2733 // we just use the full register for Dest to avoid having an | |
2734 // OperandSizeOverride prefix. It also allows us to only dispatch on SrcTy. | |
2735 Type SrcTy = Src->getType(); | |
2736 assert(typeWidthInBytes(Dest->getType()) > 1); | |
2737 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); | |
2738 emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src, | |
2739 this->Emitter); | |
2740 } | |
2741 | |
2742 template <class Machine> | |
2743 void InstX86BaseMovzx<Machine>::emitIAS(const Cfg *Func) const { | |
2744 assert(this->getSrcSize() == 1); | |
2745 const Variable *Dest = this->getDest(); | |
2746 const Operand *Src = this->getSrc(0); | |
2747 Type SrcTy = Src->getType(); | |
2748 assert(typeWidthInBytes(Dest->getType()) > 1); | |
2749 assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy)); | |
2750 emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src, | |
2751 this->Emitter); | |
2752 } | |
2753 | |
2754 template <class Machine> | |
2755 void InstX86BaseNop<Machine>::emit(const Cfg *Func) const { | |
2756 if (!BuildDefs::dump()) | |
2757 return; | |
2758 Ostream &Str = Func->getContext()->getStrEmit(); | |
2759 // TODO: Emit the right code for each variant. | |
2760 Str << "\tnop\t# variant = " << Variant; | |
2761 } | |
2762 | |
2763 template <class Machine> | |
2764 void InstX86BaseNop<Machine>::emitIAS(const Cfg *Func) const { | |
2765 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2766 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2767 // TODO: Emit the right code for the variant. | |
2768 Asm->nop(); | |
2769 } | |
2770 | |
2771 template <class Machine> | |
2772 void InstX86BaseNop<Machine>::dump(const Cfg *Func) const { | |
2773 if (!BuildDefs::dump()) | |
2774 return; | |
2775 Ostream &Str = Func->getContext()->getStrDump(); | |
2776 Str << "nop (variant = " << Variant << ")"; | |
2777 } | |
2778 | |
2779 template <class Machine> | |
2780 void InstX86BaseFld<Machine>::emit(const Cfg *Func) const { | |
2781 if (!BuildDefs::dump()) | |
2782 return; | |
2783 Ostream &Str = Func->getContext()->getStrEmit(); | |
2784 assert(this->getSrcSize() == 1); | |
2785 Type Ty = this->getSrc(0)->getType(); | |
2786 SizeT Width = typeWidthInBytes(Ty); | |
2787 const auto Var = llvm::dyn_cast<Variable>(this->getSrc(0)); | |
2788 if (Var && Var->hasReg()) { | |
2789 // This is a physical xmm register, so we need to spill it to a | |
2790 // temporary stack slot. | |
2791 Str << "\tsubl\t$" << Width << ", %esp" | |
2792 << "\n"; | |
2793 Str << "\tmov" | |
2794 << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t"; | |
2795 Var->emit(Func); | |
2796 Str << ", (%esp)\n"; | |
2797 Str << "\tfld" << this->getFldString(Ty) << "\t" | |
2798 << "(%esp)\n"; | |
2799 Str << "\taddl\t$" << Width << ", %esp"; | |
2800 return; | |
2801 } | |
2802 Str << "\tfld" << this->getFldString(Ty) << "\t"; | |
2803 this->getSrc(0)->emit(Func); | |
2804 } | |
2805 | |
2806 template <class Machine> | |
2807 void InstX86BaseFld<Machine>::emitIAS(const Cfg *Func) const { | |
2808 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2809 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2810 assert(this->getSrcSize() == 1); | |
2811 const Operand *Src = this->getSrc(0); | |
2812 Type Ty = Src->getType(); | |
2813 if (const auto Var = llvm::dyn_cast<Variable>(Src)) { | |
2814 if (Var->hasReg()) { | |
2815 // This is a physical xmm register, so we need to spill it to a | |
2816 // temporary stack slot. | |
2817 Immediate Width(typeWidthInBytes(Ty)); | |
2818 Asm->sub(IceType_i32, | |
2819 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, | |
2820 Width); | |
2821 typename InstX86Base<Machine>::Traits::Address StackSlot = | |
2822 typename InstX86Base<Machine>::Traits::Address( | |
2823 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); | |
2824 Asm->movss(Ty, StackSlot, | |
2825 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2826 Var->getRegNum())); | |
2827 Asm->fld(Ty, StackSlot); | |
2828 Asm->add(IceType_i32, | |
2829 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, | |
2830 Width); | |
2831 } else { | |
2832 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
2833 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
2834 Func->getTarget()) | |
2835 ->stackVarToAsmOperand(Var)); | |
2836 Asm->fld(Ty, StackAddr); | |
2837 } | |
2838 } else if (const auto Mem = llvm::dyn_cast< | |
2839 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) { | |
2840 assert(Mem->getSegmentRegister() == | |
2841 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
2842 Asm->fld(Ty, Mem->toAsmAddress(Asm)); | |
2843 } else if (const auto Imm = llvm::dyn_cast<Constant>(Src)) { | |
2844 Asm->fld(Ty, InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm)); | |
2845 } else { | |
2846 llvm_unreachable("Unexpected operand type"); | |
2847 } | |
2848 } | |
2849 | |
2850 template <class Machine> | |
2851 void InstX86BaseFld<Machine>::dump(const Cfg *Func) const { | |
2852 if (!BuildDefs::dump()) | |
2853 return; | |
2854 Ostream &Str = Func->getContext()->getStrDump(); | |
2855 Str << "fld." << this->getSrc(0)->getType() << " "; | |
2856 this->dumpSources(Func); | |
2857 } | |
2858 | |
2859 template <class Machine> | |
2860 void InstX86BaseFstp<Machine>::emit(const Cfg *Func) const { | |
2861 if (!BuildDefs::dump()) | |
2862 return; | |
2863 Ostream &Str = Func->getContext()->getStrEmit(); | |
2864 assert(this->getSrcSize() == 0); | |
2865 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to | |
2866 // "partially" delete the fstp if the Dest is unused. | |
2867 // Even if Dest is unused, the fstp should be kept for the SideEffects | |
2868 // of popping the stack. | |
2869 if (!this->getDest()) { | |
2870 Str << "\tfstp\tst(0)"; | |
2871 return; | |
2872 } | |
2873 Type Ty = this->getDest()->getType(); | |
2874 size_t Width = typeWidthInBytes(Ty); | |
2875 if (!this->getDest()->hasReg()) { | |
2876 Str << "\tfstp" << this->getFldString(Ty) << "\t"; | |
2877 this->getDest()->emit(Func); | |
2878 return; | |
2879 } | |
2880 // Dest is a physical (xmm) register, so st(0) needs to go through | |
2881 // memory. Hack this by creating a temporary stack slot, spilling | |
2882 // st(0) there, loading it into the xmm register, and deallocating | |
2883 // the stack slot. | |
2884 Str << "\tsubl\t$" << Width << ", %esp\n"; | |
2885 Str << "\tfstp" << this->getFldString(Ty) << "\t" | |
2886 << "(%esp)\n"; | |
2887 Str << "\tmov" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString | |
2888 << "\t" | |
2889 << "(%esp), "; | |
2890 this->getDest()->emit(Func); | |
2891 Str << "\n"; | |
2892 Str << "\taddl\t$" << Width << ", %esp"; | |
2893 } | |
2894 | |
2895 template <class Machine> | |
2896 void InstX86BaseFstp<Machine>::emitIAS(const Cfg *Func) const { | |
2897 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
2898 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
2899 assert(this->getSrcSize() == 0); | |
2900 const Variable *Dest = this->getDest(); | |
2901 // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to | |
2902 // "partially" delete the fstp if the Dest is unused. | |
2903 // Even if Dest is unused, the fstp should be kept for the SideEffects | |
2904 // of popping the stack. | |
2905 if (!Dest) { | |
2906 Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0)); | |
2907 return; | |
2908 } | |
2909 Type Ty = Dest->getType(); | |
2910 if (!Dest->hasReg()) { | |
2911 typename InstX86Base<Machine>::Traits::Address StackAddr( | |
2912 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
2913 Func->getTarget()) | |
2914 ->stackVarToAsmOperand(Dest)); | |
2915 Asm->fstp(Ty, StackAddr); | |
2916 } else { | |
2917 // Dest is a physical (xmm) register, so st(0) needs to go through | |
2918 // memory. Hack this by creating a temporary stack slot, spilling | |
2919 // st(0) there, loading it into the xmm register, and deallocating | |
2920 // the stack slot. | |
2921 Immediate Width(typeWidthInBytes(Ty)); | |
2922 Asm->sub(IceType_i32, | |
2923 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width); | |
2924 typename InstX86Base<Machine>::Traits::Address StackSlot = | |
2925 typename InstX86Base<Machine>::Traits::Address( | |
2926 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0); | |
2927 Asm->fstp(Ty, StackSlot); | |
2928 Asm->movss(Ty, InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm( | |
2929 Dest->getRegNum()), | |
2930 StackSlot); | |
2931 Asm->add(IceType_i32, | |
2932 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, Width); | |
2933 } | |
2934 } | |
2935 | |
2936 template <class Machine> | |
2937 void InstX86BaseFstp<Machine>::dump(const Cfg *Func) const { | |
2938 if (!BuildDefs::dump()) | |
2939 return; | |
2940 Ostream &Str = Func->getContext()->getStrDump(); | |
2941 this->dumpDest(Func); | |
2942 Str << " = fstp." << this->getDest()->getType() << ", st(0)"; | |
2943 } | |
2944 | |
2945 template <class Machine> | |
2946 void InstX86BasePcmpeq<Machine>::emit(const Cfg *Func) const { | |
2947 if (!BuildDefs::dump()) | |
2948 return; | |
2949 char buf[30]; | |
2950 snprintf( | |
2951 buf, llvm::array_lengthof(buf), "pcmpeq%s", | |
2952 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
2953 .PackString); | |
2954 this->emitTwoAddress(buf, this, Func); | |
2955 } | |
2956 | |
2957 template <class Machine> | |
2958 void InstX86BasePcmpgt<Machine>::emit(const Cfg *Func) const { | |
2959 if (!BuildDefs::dump()) | |
2960 return; | |
2961 char buf[30]; | |
2962 snprintf( | |
2963 buf, llvm::array_lengthof(buf), "pcmpgt%s", | |
2964 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
2965 .PackString); | |
2966 this->emitTwoAddress(buf, this, Func); | |
2967 } | |
2968 | |
2969 template <class Machine> | |
2970 void InstX86BasePextr<Machine>::emit(const Cfg *Func) const { | |
2971 if (!BuildDefs::dump()) | |
2972 return; | |
2973 Ostream &Str = Func->getContext()->getStrEmit(); | |
2974 assert(this->getSrcSize() == 2); | |
2975 // pextrb and pextrd are SSE4.1 instructions. | |
2976 assert(this->getSrc(0)->getType() == IceType_v8i16 || | |
2977 this->getSrc(0)->getType() == IceType_v8i1 || | |
2978 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
2979 Func->getTarget()) | |
2980 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
2981 Str << "\t" << this->Opcode | |
2982 << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0) | |
2983 ->getType()] | |
2984 .PackString << "\t"; | |
2985 this->getSrc(1)->emit(Func); | |
2986 Str << ", "; | |
2987 this->getSrc(0)->emit(Func); | |
2988 Str << ", "; | |
2989 Variable *Dest = this->getDest(); | |
2990 // pextrw must take a register dest. There is an SSE4.1 version that takes | |
2991 // a memory dest, but we aren't using it. For uniformity, just restrict | |
2992 // them all to have a register dest for now. | |
2993 assert(Dest->hasReg()); | |
2994 Dest->asType(IceType_i32)->emit(Func); | |
2995 } | |
2996 | |
2997 template <class Machine> | |
2998 void InstX86BasePextr<Machine>::emitIAS(const Cfg *Func) const { | |
2999 assert(this->getSrcSize() == 2); | |
3000 // pextrb and pextrd are SSE4.1 instructions. | |
3001 const Variable *Dest = this->getDest(); | |
3002 Type DispatchTy = Dest->getType(); | |
3003 assert(DispatchTy == IceType_i16 || | |
3004 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
3005 Func->getTarget()) | |
3006 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
3007 // pextrw must take a register dest. There is an SSE4.1 version that takes | |
3008 // a memory dest, but we aren't using it. For uniformity, just restrict | |
3009 // them all to have a register dest for now. | |
3010 assert(Dest->hasReg()); | |
3011 // pextrw's Src(0) must be a register (both SSE4.1 and SSE2). | |
3012 assert(llvm::cast<Variable>(this->getSrc(0))->hasReg()); | |
3013 static const typename InstX86Base<Machine>::Traits::Assembler:: | |
3014 template ThreeOpImmEmitter< | |
3015 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | |
3016 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> | |
3017 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pextr, nullptr}; | |
3018 emitIASThreeOpImmOps< | |
3019 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | |
3020 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3021 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR, | |
3022 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( | |
3023 Func, DispatchTy, Dest, this->getSrc(0), this->getSrc(1), Emitter); | |
3024 } | |
3025 | |
3026 template <class Machine> | |
3027 void InstX86BasePinsr<Machine>::emit(const Cfg *Func) const { | |
3028 if (!BuildDefs::dump()) | |
3029 return; | |
3030 Ostream &Str = Func->getContext()->getStrEmit(); | |
3031 assert(this->getSrcSize() == 3); | |
3032 // pinsrb and pinsrd are SSE4.1 instructions. | |
3033 assert(this->getDest()->getType() == IceType_v8i16 || | |
3034 this->getDest()->getType() == IceType_v8i1 || | |
3035 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
3036 Func->getTarget()) | |
3037 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
3038 Str << "\t" << this->Opcode | |
3039 << InstX86Base< | |
3040 Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
3041 .PackString << "\t"; | |
3042 this->getSrc(2)->emit(Func); | |
3043 Str << ", "; | |
3044 Operand *Src1 = this->getSrc(1); | |
3045 if (const auto Src1Var = llvm::dyn_cast<Variable>(Src1)) { | |
3046 // If src1 is a register, it should always be r32. | |
3047 if (Src1Var->hasReg()) { | |
3048 Src1Var->asType(IceType_i32)->emit(Func); | |
3049 } else { | |
3050 Src1Var->emit(Func); | |
3051 } | |
3052 } else { | |
3053 Src1->emit(Func); | |
3054 } | |
3055 Str << ", "; | |
3056 this->getDest()->emit(Func); | |
3057 } | |
3058 | |
3059 template <class Machine> | |
3060 void InstX86BasePinsr<Machine>::emitIAS(const Cfg *Func) const { | |
3061 assert(this->getSrcSize() == 3); | |
3062 assert(this->getDest() == this->getSrc(0)); | |
3063 // pinsrb and pinsrd are SSE4.1 instructions. | |
3064 const Operand *Src0 = this->getSrc(1); | |
3065 Type DispatchTy = Src0->getType(); | |
3066 assert(DispatchTy == IceType_i16 || | |
3067 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
3068 Func->getTarget()) | |
3069 ->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1); | |
3070 // If src1 is a register, it should always be r32 (this should fall out | |
3071 // from the encodings for ByteRegs overlapping the encodings for r32), | |
3072 // but we have to trust the regalloc to not choose "ah", where it | |
3073 // doesn't overlap. | |
3074 static const typename InstX86Base<Machine>::Traits::Assembler:: | |
3075 template ThreeOpImmEmitter< | |
3076 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3077 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister> | |
3078 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pinsr, | |
3079 &InstX86Base<Machine>::Traits::Assembler::pinsr}; | |
3080 emitIASThreeOpImmOps< | |
3081 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3082 typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister, | |
3083 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, | |
3084 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR>( | |
3085 Func, DispatchTy, this->getDest(), Src0, this->getSrc(2), Emitter); | |
3086 } | |
3087 | |
3088 template <class Machine> | |
3089 void InstX86BasePshufd<Machine>::emitIAS(const Cfg *Func) const { | |
3090 assert(this->getSrcSize() == 2); | |
3091 const Variable *Dest = this->getDest(); | |
3092 Type Ty = Dest->getType(); | |
3093 static const typename InstX86Base<Machine>::Traits::Assembler:: | |
3094 template ThreeOpImmEmitter< | |
3095 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3096 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> | |
3097 Emitter = {&InstX86Base<Machine>::Traits::Assembler::pshufd, | |
3098 &InstX86Base<Machine>::Traits::Assembler::pshufd}; | |
3099 emitIASThreeOpImmOps< | |
3100 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3101 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3102 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, | |
3103 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( | |
3104 Func, Ty, Dest, this->getSrc(0), this->getSrc(1), Emitter); | |
3105 } | |
3106 | |
3107 template <class Machine> | |
3108 void InstX86BaseShufps<Machine>::emitIAS(const Cfg *Func) const { | |
3109 assert(this->getSrcSize() == 3); | |
3110 const Variable *Dest = this->getDest(); | |
3111 assert(Dest == this->getSrc(0)); | |
3112 Type Ty = Dest->getType(); | |
3113 static const typename InstX86Base<Machine>::Traits::Assembler:: | |
3114 template ThreeOpImmEmitter< | |
3115 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3116 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister> | |
3117 Emitter = {&InstX86Base<Machine>::Traits::Assembler::shufps, | |
3118 &InstX86Base<Machine>::Traits::Assembler::shufps}; | |
3119 emitIASThreeOpImmOps< | |
3120 Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3121 typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister, | |
3122 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm, | |
3123 InstX86Base<Machine>::Traits::RegisterSet::getEncodedXmm>( | |
3124 Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter); | |
3125 } | |
3126 | |
3127 template <class Machine> | |
3128 void InstX86BasePop<Machine>::emit(const Cfg *Func) const { | |
3129 if (!BuildDefs::dump()) | |
3130 return; | |
3131 Ostream &Str = Func->getContext()->getStrEmit(); | |
3132 assert(this->getSrcSize() == 0); | |
3133 Str << "\tpop\t"; | |
3134 this->getDest()->emit(Func); | |
3135 } | |
3136 | |
3137 template <class Machine> | |
3138 void InstX86BasePop<Machine>::emitIAS(const Cfg *Func) const { | |
3139 assert(this->getSrcSize() == 0); | |
3140 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
3141 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
3142 if (this->getDest()->hasReg()) { | |
3143 Asm->popl(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
3144 this->getDest()->getRegNum())); | |
3145 } else { | |
3146 Asm->popl( | |
3147 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
3148 Func->getTarget()) | |
3149 ->stackVarToAsmOperand(this->getDest())); | |
3150 } | |
3151 } | |
3152 | |
3153 template <class Machine> | |
3154 void InstX86BasePop<Machine>::dump(const Cfg *Func) const { | |
3155 if (!BuildDefs::dump()) | |
3156 return; | |
3157 Ostream &Str = Func->getContext()->getStrDump(); | |
3158 this->dumpDest(Func); | |
3159 Str << " = pop." << this->getDest()->getType() << " "; | |
3160 } | |
3161 | |
3162 template <class Machine> | |
3163 void InstX86BaseAdjustStack<Machine>::emit(const Cfg *Func) const { | |
3164 if (!BuildDefs::dump()) | |
3165 return; | |
3166 Ostream &Str = Func->getContext()->getStrEmit(); | |
3167 Str << "\tsubl\t$" << Amount << ", %esp"; | |
3168 Func->getTarget()->updateStackAdjustment(Amount); | |
3169 } | |
3170 | |
3171 template <class Machine> | |
3172 void InstX86BaseAdjustStack<Machine>::emitIAS(const Cfg *Func) const { | |
3173 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
3174 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
3175 Asm->sub(IceType_i32, | |
3176 InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, | |
3177 Immediate(Amount)); | |
3178 Func->getTarget()->updateStackAdjustment(Amount); | |
3179 } | |
3180 | |
3181 template <class Machine> | |
3182 void InstX86BaseAdjustStack<Machine>::dump(const Cfg *Func) const { | |
3183 if (!BuildDefs::dump()) | |
3184 return; | |
3185 Ostream &Str = Func->getContext()->getStrDump(); | |
3186 Str << "esp = sub.i32 esp, " << Amount; | |
3187 } | |
3188 | |
3189 template <class Machine> | |
3190 void InstX86BasePush<Machine>::emit(const Cfg *Func) const { | |
3191 if (!BuildDefs::dump()) | |
3192 return; | |
3193 Ostream &Str = Func->getContext()->getStrEmit(); | |
3194 assert(this->getSrcSize() == 1); | |
3195 // Push is currently only used for saving GPRs. | |
3196 const auto Var = llvm::cast<Variable>(this->getSrc(0)); | |
3197 assert(Var->hasReg()); | |
3198 Str << "\tpush\t"; | |
3199 Var->emit(Func); | |
3200 } | |
3201 | |
3202 template <class Machine> | |
3203 void InstX86BasePush<Machine>::emitIAS(const Cfg *Func) const { | |
3204 assert(this->getSrcSize() == 1); | |
3205 // Push is currently only used for saving GPRs. | |
3206 const auto Var = llvm::cast<Variable>(this->getSrc(0)); | |
3207 assert(Var->hasReg()); | |
3208 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
3209 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
3210 Asm->pushl(InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
3211 Var->getRegNum())); | |
3212 } | |
3213 | |
3214 template <class Machine> | |
3215 void InstX86BasePush<Machine>::dump(const Cfg *Func) const { | |
3216 if (!BuildDefs::dump()) | |
3217 return; | |
3218 Ostream &Str = Func->getContext()->getStrDump(); | |
3219 Str << "push." << this->getSrc(0)->getType() << " "; | |
3220 this->dumpSources(Func); | |
3221 } | |
3222 | |
3223 template <class Machine> | |
3224 void InstX86BasePsll<Machine>::emit(const Cfg *Func) const { | |
3225 if (!BuildDefs::dump()) | |
3226 return; | |
3227 assert(this->getDest()->getType() == IceType_v8i16 || | |
3228 this->getDest()->getType() == IceType_v8i1 || | |
3229 this->getDest()->getType() == IceType_v4i32 || | |
3230 this->getDest()->getType() == IceType_v4i1); | |
3231 char buf[30]; | |
3232 snprintf( | |
3233 buf, llvm::array_lengthof(buf), "psll%s", | |
3234 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
3235 .PackString); | |
3236 this->emitTwoAddress(buf, this, Func); | |
3237 } | |
3238 | |
3239 template <class Machine> | |
3240 void InstX86BasePsra<Machine>::emit(const Cfg *Func) const { | |
3241 if (!BuildDefs::dump()) | |
3242 return; | |
3243 assert(this->getDest()->getType() == IceType_v8i16 || | |
3244 this->getDest()->getType() == IceType_v8i1 || | |
3245 this->getDest()->getType() == IceType_v4i32 || | |
3246 this->getDest()->getType() == IceType_v4i1); | |
3247 char buf[30]; | |
3248 snprintf( | |
3249 buf, llvm::array_lengthof(buf), "psra%s", | |
3250 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
3251 .PackString); | |
3252 this->emitTwoAddress(buf, this, Func); | |
3253 } | |
3254 | |
3255 template <class Machine> | |
3256 void InstX86BasePsrl<Machine>::emit(const Cfg *Func) const { | |
3257 if (!BuildDefs::dump()) | |
3258 return; | |
3259 char buf[30]; | |
3260 snprintf( | |
3261 buf, llvm::array_lengthof(buf), "psrl%s", | |
3262 InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()] | |
3263 .PackString); | |
3264 this->emitTwoAddress(buf, this, Func); | |
3265 } | |
3266 | |
3267 template <class Machine> | |
3268 void InstX86BaseRet<Machine>::emit(const Cfg *Func) const { | |
3269 if (!BuildDefs::dump()) | |
3270 return; | |
3271 Ostream &Str = Func->getContext()->getStrEmit(); | |
3272 Str << "\tret"; | |
3273 } | |
3274 | |
3275 template <class Machine> | |
3276 void InstX86BaseRet<Machine>::emitIAS(const Cfg *Func) const { | |
3277 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
3278 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
3279 Asm->ret(); | |
3280 } | |
3281 | |
3282 template <class Machine> | |
3283 void InstX86BaseRet<Machine>::dump(const Cfg *Func) const { | |
3284 if (!BuildDefs::dump()) | |
3285 return; | |
3286 Ostream &Str = Func->getContext()->getStrDump(); | |
3287 Type Ty = | |
3288 (this->getSrcSize() == 0 ? IceType_void : this->getSrc(0)->getType()); | |
3289 Str << "ret." << Ty << " "; | |
3290 this->dumpSources(Func); | |
3291 } | |
3292 | |
3293 template <class Machine> | |
3294 void InstX86BaseSetcc<Machine>::emit(const Cfg *Func) const { | |
3295 if (!BuildDefs::dump()) | |
3296 return; | |
3297 Ostream &Str = Func->getContext()->getStrEmit(); | |
3298 Str << "\tset" | |
3299 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString | |
3300 << "\t"; | |
3301 this->Dest->emit(Func); | |
3302 } | |
3303 | |
3304 template <class Machine> | |
3305 void InstX86BaseSetcc<Machine>::emitIAS(const Cfg *Func) const { | |
3306 assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None); | |
3307 assert(this->getDest()->getType() == IceType_i1); | |
3308 assert(this->getSrcSize() == 0); | |
3309 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
3310 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
3311 if (this->getDest()->hasReg()) | |
3312 Asm->setcc(Condition, | |
3313 InstX86Base<Machine>::Traits::RegisterSet::getEncodedByteReg( | |
3314 this->getDest()->getRegNum())); | |
3315 else | |
3316 Asm->setcc( | |
3317 Condition, | |
3318 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | |
3319 Func->getTarget()) | |
3320 ->stackVarToAsmOperand(this->getDest())); | |
3321 return; | |
3322 } | |
3323 | |
3324 template <class Machine> | |
3325 void InstX86BaseSetcc<Machine>::dump(const Cfg *Func) const { | |
3326 if (!BuildDefs::dump()) | |
3327 return; | |
3328 Ostream &Str = Func->getContext()->getStrDump(); | |
3329 Str << "setcc." | |
3330 << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString | |
3331 << " "; | |
3332 this->dumpDest(Func); | |
3333 } | |
3334 | |
3335 template <class Machine> | |
3336 void InstX86BaseXadd<Machine>::emit(const Cfg *Func) const { | |
3337 if (!BuildDefs::dump()) | |
3338 return; | |
3339 Ostream &Str = Func->getContext()->getStrEmit(); | |
3340 if (this->Locked) { | |
3341 Str << "\tlock"; | |
3342 } | |
3343 Str << "\txadd" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; | |
3344 this->getSrc(1)->emit(Func); | |
3345 Str << ", "; | |
3346 this->getSrc(0)->emit(Func); | |
3347 } | |
3348 | |
3349 template <class Machine> | |
3350 void InstX86BaseXadd<Machine>::emitIAS(const Cfg *Func) const { | |
3351 assert(this->getSrcSize() == 2); | |
3352 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
3353 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
3354 Type Ty = this->getSrc(0)->getType(); | |
3355 const auto Mem = | |
3356 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
3357 this->getSrc(0)); | |
3358 assert(Mem->getSegmentRegister() == | |
3359 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
3360 const typename InstX86Base<Machine>::Traits::Address Addr = | |
3361 Mem->toAsmAddress(Asm); | |
3362 const auto VarReg = llvm::cast<Variable>(this->getSrc(1)); | |
3363 assert(VarReg->hasReg()); | |
3364 const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = | |
3365 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
3366 VarReg->getRegNum()); | |
3367 Asm->xadd(Ty, Addr, Reg, this->Locked); | |
3368 } | |
3369 | |
3370 template <class Machine> | |
3371 void InstX86BaseXadd<Machine>::dump(const Cfg *Func) const { | |
3372 if (!BuildDefs::dump()) | |
3373 return; | |
3374 Ostream &Str = Func->getContext()->getStrDump(); | |
3375 if (this->Locked) { | |
3376 Str << "lock "; | |
3377 } | |
3378 Type Ty = this->getSrc(0)->getType(); | |
3379 Str << "xadd." << Ty << " "; | |
3380 this->dumpSources(Func); | |
3381 } | |
3382 | |
3383 template <class Machine> | |
3384 void InstX86BaseXchg<Machine>::emit(const Cfg *Func) const { | |
3385 if (!BuildDefs::dump()) | |
3386 return; | |
3387 Ostream &Str = Func->getContext()->getStrEmit(); | |
3388 Str << "\txchg" << this->getWidthString(this->getSrc(0)->getType()) << "\t"; | |
3389 this->getSrc(1)->emit(Func); | |
3390 Str << ", "; | |
3391 this->getSrc(0)->emit(Func); | |
3392 } | |
3393 | |
3394 template <class Machine> | |
3395 void InstX86BaseXchg<Machine>::emitIAS(const Cfg *Func) const { | |
3396 assert(this->getSrcSize() == 2); | |
3397 typename InstX86Base<Machine>::Traits::Assembler *Asm = | |
3398 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | |
3399 Type Ty = this->getSrc(0)->getType(); | |
3400 const auto Mem = | |
3401 llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>( | |
3402 this->getSrc(0)); | |
3403 assert(Mem->getSegmentRegister() == | |
3404 InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment); | |
3405 const typename InstX86Base<Machine>::Traits::Address Addr = | |
3406 Mem->toAsmAddress(Asm); | |
3407 const auto VarReg = llvm::cast<Variable>(this->getSrc(1)); | |
3408 assert(VarReg->hasReg()); | |
3409 const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg = | |
3410 InstX86Base<Machine>::Traits::RegisterSet::getEncodedGPR( | |
3411 VarReg->getRegNum()); | |
3412 Asm->xchg(Ty, Addr, Reg); | |
3413 } | |
3414 | |
3415 template <class Machine> | |
3416 void InstX86BaseXchg<Machine>::dump(const Cfg *Func) const { | |
3417 if (!BuildDefs::dump()) | |
3418 return; | |
3419 Ostream &Str = Func->getContext()->getStrDump(); | |
3420 Type Ty = this->getSrc(0)->getType(); | |
3421 Str << "xchg." << Ty << " "; | |
3422 this->dumpSources(Func); | |
3423 } | |
3424 | |
3425 } // end of namespace X86Internal | |
3426 | |
3427 } // end of namespace Ice | |
3428 | |
3429 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H | |
OLD | NEW |