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