OLD | NEW |
---|---|
1 //===- subzero/src/IceTargetLoweringX8632Traits.h - x86-32 traits -*- C++ -*-=// | 1 //===- subzero/src/IceTargetLoweringX8632Traits.h - x86-32 traits -*- C++ -*-=// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 /// |
10 // This file defines the X8632 Target Lowering Traits. | 10 /// \file |
11 // | 11 /// This file declares the X8632 Target Lowering Traits. |
12 /// | |
12 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
13 | 14 |
14 #ifndef SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H | 15 #ifndef SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H |
15 #define SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H | 16 #define SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H |
16 | 17 |
17 #include "IceAssembler.h" | 18 #include "IceAssembler.h" |
18 #include "IceConditionCodesX8632.h" | 19 #include "IceConditionCodesX8632.h" |
19 #include "IceDefs.h" | 20 #include "IceDefs.h" |
20 #include "IceInst.h" | 21 #include "IceInst.h" |
21 #include "IceInstX8632.def" | 22 #include "IceInstX8632.def" |
23 #include "IceOperand.h" | |
22 #include "IceRegistersX8632.h" | 24 #include "IceRegistersX8632.h" |
23 #include "IceTargetLoweringX8632.def" | 25 #include "IceTargetLoweringX8632.def" |
26 #include "IceTargetLowering.h" | |
24 | 27 |
25 namespace Ice { | 28 namespace Ice { |
26 | 29 |
27 class TargetX8632; | 30 class TargetX8632; |
28 | 31 |
32 namespace X8632 { | |
33 class AssemblerX8632; | |
34 } // end of namespace X8632 | |
35 | |
29 namespace X86Internal { | 36 namespace X86Internal { |
30 | 37 |
38 template <class Machine> struct Insts; | |
31 template <class Machine> struct MachineTraits; | 39 template <class Machine> struct MachineTraits; |
32 | 40 |
33 template <> struct MachineTraits<TargetX8632> { | 41 template <> struct MachineTraits<TargetX8632> { |
34 //---------------------------------------------------------------------------- | 42 //---------------------------------------------------------------------------- |
35 // ______ ______ __ __ | 43 // ______ ______ __ __ |
36 // /\ __ \/\ ___\/\ "-./ \ | 44 // /\ __ \/\ ___\/\ "-./ \ |
37 // \ \ __ \ \___ \ \ \-./\ \ | 45 // \ \ __ \ \___ \ \ \-./\ \ |
38 // \ \_\ \_\/\_____\ \_\ \ \_\ | 46 // \ \_\ \_\/\_____\ \_\ \ \_\ |
39 // \/_/\/_/\/_____/\/_/ \/_/ | 47 // \/_/\/_/\/_____/\/_/ \/_/ |
40 // | 48 // |
41 //---------------------------------------------------------------------------- | 49 //---------------------------------------------------------------------------- |
42 enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 }; | 50 enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 }; |
43 | 51 |
44 using GPRRegister = ::Ice::RegX8632::GPRRegister; | 52 using GPRRegister = ::Ice::RegX8632::GPRRegister; |
45 using XmmRegister = ::Ice::RegX8632::XmmRegister; | 53 using XmmRegister = ::Ice::RegX8632::XmmRegister; |
46 using ByteRegister = ::Ice::RegX8632::ByteRegister; | 54 using ByteRegister = ::Ice::RegX8632::ByteRegister; |
47 using X87STRegister = ::Ice::RegX8632::X87STRegister; | 55 using X87STRegister = ::Ice::RegX8632::X87STRegister; |
48 | 56 |
49 using Cond = ::Ice::CondX86; | 57 using Cond = ::Ice::CondX86; |
50 | 58 |
51 using RegisterSet = ::Ice::RegX8632; | 59 using RegisterSet = ::Ice::RegX8632; |
52 static const GPRRegister Encoded_Reg_Accumulator = RegX8632::Encoded_Reg_eax; | 60 static const GPRRegister Encoded_Reg_Accumulator = RegX8632::Encoded_Reg_eax; |
53 static const GPRRegister Encoded_Reg_Counter = RegX8632::Encoded_Reg_ecx; | 61 static const GPRRegister Encoded_Reg_Counter = RegX8632::Encoded_Reg_ecx; |
54 static const FixupKind PcRelFixup = llvm::ELF::R_386_PC32; | 62 static const FixupKind PcRelFixup = llvm::ELF::R_386_PC32; |
55 | 63 |
56 class Operand { | 64 class Operand { |
57 public: | 65 public: |
58 Operand(const Operand &other) | 66 Operand(const Operand &other) |
59 : length_(other.length_), fixup_(other.fixup_) { | 67 : fixup_(other.fixup_), length_(other.length_) { |
60 memmove(&encoding_[0], &other.encoding_[0], other.length_); | 68 memmove(&encoding_[0], &other.encoding_[0], other.length_); |
61 } | 69 } |
62 | 70 |
63 Operand &operator=(const Operand &other) { | 71 Operand &operator=(const Operand &other) { |
64 length_ = other.length_; | 72 length_ = other.length_; |
65 fixup_ = other.fixup_; | 73 fixup_ = other.fixup_; |
66 memmove(&encoding_[0], &other.encoding_[0], other.length_); | 74 memmove(&encoding_[0], &other.encoding_[0], other.length_); |
67 return *this; | 75 return *this; |
68 } | 76 } |
69 | 77 |
(...skipping 21 matching lines...) Expand all Loading... | |
91 } | 99 } |
92 | 100 |
93 int32_t disp32() const { | 101 int32_t disp32() const { |
94 assert(length_ >= 5); | 102 assert(length_ >= 5); |
95 return bit_copy<int32_t>(encoding_[length_ - 4]); | 103 return bit_copy<int32_t>(encoding_[length_ - 4]); |
96 } | 104 } |
97 | 105 |
98 AssemblerFixup *fixup() const { return fixup_; } | 106 AssemblerFixup *fixup() const { return fixup_; } |
99 | 107 |
100 protected: | 108 protected: |
101 Operand() : length_(0), fixup_(nullptr) {} // Needed by subclass Address. | 109 Operand() : fixup_(nullptr), length_(0) {} // Needed by subclass Address. |
102 | 110 |
103 void SetModRM(int mod, GPRRegister rm) { | 111 void SetModRM(int mod, GPRRegister rm) { |
104 assert((mod & ~3) == 0); | 112 assert((mod & ~3) == 0); |
105 encoding_[0] = (mod << 6) | rm; | 113 encoding_[0] = (mod << 6) | rm; |
106 length_ = 1; | 114 length_ = 1; |
107 } | 115 } |
108 | 116 |
109 void SetSIB(ScaleFactor scale, GPRRegister index, GPRRegister base) { | 117 void SetSIB(ScaleFactor scale, GPRRegister index, GPRRegister base) { |
110 assert(length_ == 1); | 118 assert(length_ == 1); |
111 assert((scale & ~3) == 0); | 119 assert((scale & ~3) == 0); |
112 encoding_[1] = (scale << 6) | (index << 3) | base; | 120 encoding_[1] = (scale << 6) | (index << 3) | base; |
113 length_ = 2; | 121 length_ = 2; |
114 } | 122 } |
115 | 123 |
116 void SetDisp8(int8_t disp) { | 124 void SetDisp8(int8_t disp) { |
117 assert(length_ == 1 || length_ == 2); | 125 assert(length_ == 1 || length_ == 2); |
118 encoding_[length_++] = static_cast<uint8_t>(disp); | 126 encoding_[length_++] = static_cast<uint8_t>(disp); |
119 } | 127 } |
120 | 128 |
121 void SetDisp32(int32_t disp) { | 129 void SetDisp32(int32_t disp) { |
122 assert(length_ == 1 || length_ == 2); | 130 assert(length_ == 1 || length_ == 2); |
123 intptr_t disp_size = sizeof(disp); | 131 intptr_t disp_size = sizeof(disp); |
124 memmove(&encoding_[length_], &disp, disp_size); | 132 memmove(&encoding_[length_], &disp, disp_size); |
125 length_ += disp_size; | 133 length_ += disp_size; |
126 } | 134 } |
127 | 135 |
128 void SetFixup(AssemblerFixup *fixup) { fixup_ = fixup; } | 136 void SetFixup(AssemblerFixup *fixup) { fixup_ = fixup; } |
129 | 137 |
130 private: | 138 private: |
139 AssemblerFixup *fixup_; | |
140 uint8_t encoding_[6]; | |
131 uint8_t length_; | 141 uint8_t length_; |
132 uint8_t encoding_[6]; | |
133 AssemblerFixup *fixup_; | |
134 | 142 |
135 explicit Operand(GPRRegister reg) : fixup_(nullptr) { SetModRM(3, reg); } | 143 explicit Operand(GPRRegister reg) : fixup_(nullptr) { SetModRM(3, reg); } |
136 | 144 |
137 // Get the operand encoding byte at the given index. | 145 /// Get the operand encoding byte at the given index. |
138 uint8_t encoding_at(intptr_t index) const { | 146 uint8_t encoding_at(intptr_t index) const { |
139 assert(index >= 0 && index < length_); | 147 assert(index >= 0 && index < length_); |
140 return encoding_[index]; | 148 return encoding_[index]; |
141 } | 149 } |
142 | 150 |
143 // Returns whether or not this operand is really the given register in | 151 /// Returns whether or not this operand is really the given register in |
144 // disguise. Used from the assembler to generate better encodings. | 152 /// disguise. Used from the assembler to generate better encodings. |
145 bool IsRegister(GPRRegister reg) const { | 153 bool IsRegister(GPRRegister reg) const { |
146 return ((encoding_[0] & 0xF8) == | 154 return ((encoding_[0] & 0xF8) == |
147 0xC0) // Addressing mode is register only. | 155 0xC0) // Addressing mode is register only. |
148 && | 156 && |
149 ((encoding_[0] & 0x07) == reg); // Register codes match. | 157 ((encoding_[0] & 0x07) == reg); // Register codes match. |
150 } | 158 } |
151 | 159 |
152 template <class> friend class AssemblerX86Base; | 160 template <class> friend class AssemblerX86Base; |
153 }; | 161 }; |
154 | 162 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 SetModRM(1, RegX8632::Encoded_Reg_esp); | 206 SetModRM(1, RegX8632::Encoded_Reg_esp); |
199 SetSIB(scale, index, base); | 207 SetSIB(scale, index, base); |
200 SetDisp8(disp); | 208 SetDisp8(disp); |
201 } else { | 209 } else { |
202 SetModRM(2, RegX8632::Encoded_Reg_esp); | 210 SetModRM(2, RegX8632::Encoded_Reg_esp); |
203 SetSIB(scale, index, base); | 211 SetSIB(scale, index, base); |
204 SetDisp32(disp); | 212 SetDisp32(disp); |
205 } | 213 } |
206 } | 214 } |
207 | 215 |
208 // AbsoluteTag is a special tag used by clients to create an absolute | 216 /// AbsoluteTag is a special tag used by clients to create an absolute |
209 // Address. | 217 /// Address. |
210 enum AbsoluteTag { ABSOLUTE }; | 218 enum AbsoluteTag { ABSOLUTE }; |
211 | 219 |
212 Address(AbsoluteTag, const uintptr_t Addr) { | 220 Address(AbsoluteTag, const uintptr_t Addr) { |
213 SetModRM(0, RegX8632::Encoded_Reg_ebp); | 221 SetModRM(0, RegX8632::Encoded_Reg_ebp); |
214 SetDisp32(Addr); | 222 SetDisp32(Addr); |
215 } | 223 } |
216 | 224 |
217 // TODO(jpp): remove this. | 225 // TODO(jpp): remove this. |
218 static Address Absolute(const uintptr_t Addr) { | 226 static Address Absolute(const uintptr_t Addr) { |
219 return Address(ABSOLUTE, Addr); | 227 return Address(ABSOLUTE, Addr); |
(...skipping 28 matching lines...) Expand all Loading... | |
248 // | 256 // |
249 //---------------------------------------------------------------------------- | 257 //---------------------------------------------------------------------------- |
250 enum InstructionSet { | 258 enum InstructionSet { |
251 Begin, | 259 Begin, |
252 // SSE2 is the PNaCl baseline instruction set. | 260 // SSE2 is the PNaCl baseline instruction set. |
253 SSE2 = Begin, | 261 SSE2 = Begin, |
254 SSE4_1, | 262 SSE4_1, |
255 End | 263 End |
256 }; | 264 }; |
257 | 265 |
258 // The maximum number of arguments to pass in XMM registers | 266 static const char *TargetName; |
267 | |
268 static IceString getRegName(SizeT RegNum, Type Ty) { | |
269 assert(RegNum < RegisterSet::Reg_NUM); | |
270 static const char *RegNames8[] = { | |
271 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ | |
272 frameptr, isI8, isInt, isFP) \ | |
273 name8, | |
274 REGX8632_TABLE | |
275 #undef X | |
276 }; | |
277 | |
278 static const char *RegNames16[] = { | |
279 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ | |
280 frameptr, isI8, isInt, isFP) \ | |
281 name16, | |
282 REGX8632_TABLE | |
283 #undef X | |
284 }; | |
285 | |
286 static const char *RegNames[] = { | |
287 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ | |
288 frameptr, isI8, isInt, isFP) \ | |
289 name, | |
290 REGX8632_TABLE | |
291 #undef X | |
292 }; | |
293 | |
294 switch (Ty) { | |
295 case IceType_i1: | |
296 case IceType_i8: | |
297 return RegNames8[RegNum]; | |
298 case IceType_i16: | |
299 return RegNames16[RegNum]; | |
300 default: | |
301 return RegNames[RegNum]; | |
302 } | |
303 } | |
304 | |
305 static void initRegisterSet(llvm::SmallBitVector *IntegerRegisters, | |
306 llvm::SmallBitVector *IntegerRegistersI8, | |
307 llvm::SmallBitVector *FloatRegisters, | |
308 llvm::SmallBitVector *VectorRegisters, | |
309 llvm::SmallBitVector *ScratchRegs) { | |
310 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ | |
311 frameptr, isI8, isInt, isFP) \ | |
312 (*IntegerRegisters)[RegisterSet::val] = isInt; \ | |
313 (*IntegerRegistersI8)[RegisterSet::val] = isI8; \ | |
314 (*FloatRegisters)[RegisterSet::val] = isFP; \ | |
315 (*VectorRegisters)[RegisterSet::val] = isFP; \ | |
316 (*ScratchRegs)[RegisterSet::val] = scratch; | |
317 REGX8632_TABLE; | |
318 #undef X | |
319 } | |
320 | |
321 static llvm::SmallBitVector | |
322 getRegisterSet(TargetLowering::RegSetMask Include, | |
323 TargetLowering::RegSetMask Exclude) { | |
324 llvm::SmallBitVector Registers(RegisterSet::Reg_NUM); | |
325 | |
326 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ | |
327 frameptr, isI8, isInt, isFP) \ | |
328 if (scratch && (Include & ::Ice::TargetLowering::RegSet_CallerSave)) \ | |
329 Registers[RegisterSet::val] = true; \ | |
330 if (preserved && (Include & ::Ice::TargetLowering::RegSet_CalleeSave)) \ | |
331 Registers[RegisterSet::val] = true; \ | |
332 if (stackptr && (Include & ::Ice::TargetLowering::RegSet_StackPointer)) \ | |
333 Registers[RegisterSet::val] = true; \ | |
334 if (frameptr && (Include & ::Ice::TargetLowering::RegSet_FramePointer)) \ | |
335 Registers[RegisterSet::val] = true; \ | |
336 if (scratch && (Exclude & ::Ice::TargetLowering::RegSet_CallerSave)) \ | |
337 Registers[RegisterSet::val] = false; \ | |
338 if (preserved && (Exclude & ::Ice::TargetLowering::RegSet_CalleeSave)) \ | |
339 Registers[RegisterSet::val] = false; \ | |
340 if (stackptr && (Exclude & ::Ice::TargetLowering::RegSet_StackPointer)) \ | |
341 Registers[RegisterSet::val] = false; \ | |
342 if (frameptr && (Exclude & ::Ice::TargetLowering::RegSet_FramePointer)) \ | |
343 Registers[RegisterSet::val] = false; | |
344 | |
345 REGX8632_TABLE | |
346 | |
347 #undef X | |
348 | |
349 return Registers; | |
350 } | |
351 | |
352 static void | |
353 makeRandomRegisterPermutation(GlobalContext *Ctx, Cfg *Func, | |
354 llvm::SmallVectorImpl<int32_t> &Permutation, | |
355 const llvm::SmallBitVector &ExcludeRegisters) { | |
356 // TODO(stichnot): Declaring Permutation this way loses type/size | |
357 // information. Fix this in conjunction with the caller-side TODO. | |
358 assert(Permutation.size() >= RegisterSet::Reg_NUM); | |
359 // Expected upper bound on the number of registers in a single equivalence | |
360 // class. For x86-32, this would comprise the 8 XMM registers. This is for | |
361 // performance, not correctness. | |
362 static const unsigned MaxEquivalenceClassSize = 8; | |
363 typedef llvm::SmallVector<int32_t, MaxEquivalenceClassSize> RegisterList; | |
364 typedef std::map<uint32_t, RegisterList> EquivalenceClassMap; | |
365 EquivalenceClassMap EquivalenceClasses; | |
366 SizeT NumShuffled = 0, NumPreserved = 0; | |
367 | |
368 // Build up the equivalence classes of registers by looking at the register | |
369 // properties as well as whether the registers should be explicitly excluded | |
370 // from shuffling. | |
371 #define X(val, encode, name, name16, name8, scratch, preserved, stackptr, \ | |
372 frameptr, isI8, isInt, isFP) \ | |
373 if (ExcludeRegisters[RegisterSet::val]) { \ | |
374 /* val stays the same in the resulting permutation. */ \ | |
375 Permutation[RegisterSet::val] = RegisterSet::val; \ | |
376 ++NumPreserved; \ | |
377 } else { \ | |
378 const uint32_t Index = (scratch << 0) | (preserved << 1) | (isI8 << 2) | \ | |
379 (isInt << 3) | (isFP << 4); \ | |
380 /* val is assigned to an equivalence class based on its properties. */ \ | |
381 EquivalenceClasses[Index].push_back(RegisterSet::val); \ | |
382 } | |
383 REGX8632_TABLE | |
384 #undef X | |
385 | |
386 RandomNumberGeneratorWrapper RNG(Ctx->getRNG()); | |
387 | |
388 // Shuffle the resulting equivalence classes. | |
389 for (auto I : EquivalenceClasses) { | |
390 const RegisterList &List = I.second; | |
391 RegisterList Shuffled(List); | |
392 RandomShuffle(Shuffled.begin(), Shuffled.end(), RNG); | |
393 for (size_t SI = 0, SE = Shuffled.size(); SI < SE; ++SI) { | |
394 Permutation[List[SI]] = Shuffled[SI]; | |
395 ++NumShuffled; | |
396 } | |
397 } | |
398 | |
399 assert(NumShuffled + NumPreserved == RegisterSet::Reg_NUM); | |
400 | |
401 if (Func->isVerbose(IceV_Random)) { | |
402 OstreamLocker L(Func->getContext()); | |
403 Ostream &Str = Func->getContext()->getStrDump(); | |
404 Str << "Register equivalence classes:\n"; | |
405 for (auto I : EquivalenceClasses) { | |
406 Str << "{"; | |
407 const RegisterList &List = I.second; | |
408 bool First = true; | |
409 for (int32_t Register : List) { | |
410 if (!First) | |
411 Str << " "; | |
412 First = false; | |
413 Str << getRegName(Register, IceType_i32); | |
414 } | |
415 Str << "}\n"; | |
416 } | |
417 } | |
418 } | |
419 | |
420 /// The maximum number of arguments to pass in XMM registers | |
259 static const uint32_t X86_MAX_XMM_ARGS = 4; | 421 static const uint32_t X86_MAX_XMM_ARGS = 4; |
260 // The number of bits in a byte | 422 /// The number of bits in a byte |
261 static const uint32_t X86_CHAR_BIT = 8; | 423 static const uint32_t X86_CHAR_BIT = 8; |
262 // Stack alignment. This is defined in IceTargetLoweringX8632.cpp because it | 424 /// Stack alignment. This is defined in IceTargetLoweringX8632.cpp because it |
263 // is used as an argument to std::max(), and the default std::less<T> has an | 425 /// is used as an argument to std::max(), and the default std::less<T> has an |
264 // operator(T const&, T const&) which requires this member to have an address. | 426 /// operator(T const&, T const&) which requires this member to have an |
427 /// address. | |
265 static const uint32_t X86_STACK_ALIGNMENT_BYTES; | 428 static const uint32_t X86_STACK_ALIGNMENT_BYTES; |
266 // Size of the return address on the stack | 429 /// Size of the return address on the stack |
267 static const uint32_t X86_RET_IP_SIZE_BYTES = 4; | 430 static const uint32_t X86_RET_IP_SIZE_BYTES = 4; |
268 // The number of different NOP instructions | 431 /// The number of different NOP instructions |
269 static const uint32_t X86_NUM_NOP_VARIANTS = 5; | 432 static const uint32_t X86_NUM_NOP_VARIANTS = 5; |
270 | 433 |
271 // Value is in bytes. Return Value adjusted to the next highest multiple | 434 /// Value is in bytes. Return Value adjusted to the next highest multiple |
272 // of the stack alignment. | 435 /// of the stack alignment. |
273 static uint32_t applyStackAlignment(uint32_t Value) { | 436 static uint32_t applyStackAlignment(uint32_t Value) { |
274 return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES); | 437 return Utils::applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES); |
275 } | 438 } |
276 | 439 |
277 // Return the type which the elements of the vector have in the X86 | 440 /// Return the type which the elements of the vector have in the X86 |
278 // representation of the vector. | 441 /// representation of the vector. |
279 static Type getInVectorElementType(Type Ty) { | 442 static Type getInVectorElementType(Type Ty) { |
280 assert(isVectorType(Ty)); | 443 assert(isVectorType(Ty)); |
281 size_t Index = static_cast<size_t>(Ty); | 444 size_t Index = static_cast<size_t>(Ty); |
282 (void)Index; | 445 (void)Index; |
283 assert(Index < TableTypeX8632AttributesSize); | 446 assert(Index < TableTypeX8632AttributesSize); |
284 return TableTypeX8632Attributes[Ty].InVectorElementType; | 447 return TableTypeX8632Attributes[Ty].InVectorElementType; |
285 } | 448 } |
286 | 449 |
287 // Note: The following data structures are defined in | 450 // Note: The following data structures are defined in |
288 // IceTargetLoweringX8632.cpp. | 451 // IceTargetLoweringX8632.cpp. |
289 | 452 |
290 // The following table summarizes the logic for lowering the fcmp | 453 /// The following table summarizes the logic for lowering the fcmp |
291 // instruction. There is one table entry for each of the 16 conditions. | 454 /// instruction. There is one table entry for each of the 16 conditions. |
292 // | 455 /// |
293 // The first four columns describe the case when the operands are | 456 /// The first four columns describe the case when the operands are floating |
294 // floating point scalar values. A comment in lowerFcmp() describes the | 457 /// point scalar values. A comment in lowerFcmp() describes the lowering |
295 // lowering template. In the most general case, there is a compare | 458 /// template. In the most general case, there is a compare followed by two |
296 // followed by two conditional branches, because some fcmp conditions | 459 /// conditional branches, because some fcmp conditions don't map to a single |
297 // don't map to a single x86 conditional branch. However, in many cases | 460 /// x86 conditional branch. However, in many cases it is possible to swap the |
298 // it is possible to swap the operands in the comparison and have a | 461 /// operands in the comparison and have a single conditional branch. Since |
299 // single conditional branch. Since it's quite tedious to validate the | 462 /// it's quite tedious to validate the table by hand, good execution tests are |
300 // table by hand, good execution tests are helpful. | 463 /// helpful. |
301 // | 464 /// |
302 // The last two columns describe the case when the operands are vectors | 465 /// The last two columns describe the case when the operands are vectors of |
303 // of floating point values. For most fcmp conditions, there is a clear | 466 /// floating point values. For most fcmp conditions, there is a clear mapping |
304 // mapping to a single x86 cmpps instruction variant. Some fcmp | 467 /// to a single x86 cmpps instruction variant. Some fcmp conditions require |
305 // conditions require special code to handle and these are marked in the | 468 /// special code to handle and these are marked in the table with a |
306 // table with a Cmpps_Invalid predicate. | 469 /// Cmpps_Invalid predicate. |
470 /// {@ | |
307 static const struct TableFcmpType { | 471 static const struct TableFcmpType { |
308 uint32_t Default; | 472 uint32_t Default; |
309 bool SwapScalarOperands; | 473 bool SwapScalarOperands; |
310 CondX86::BrCond C1, C2; | 474 Cond::BrCond C1, C2; |
311 bool SwapVectorOperands; | 475 bool SwapVectorOperands; |
312 CondX86::CmppsCond Predicate; | 476 Cond::CmppsCond Predicate; |
313 } TableFcmp[]; | 477 } TableFcmp[]; |
314 static const size_t TableFcmpSize; | 478 static const size_t TableFcmpSize; |
479 /// @} | |
315 | 480 |
316 // The following table summarizes the logic for lowering the icmp instruction | 481 /// The following table summarizes the logic for lowering the icmp instruction |
317 // for i32 and narrower types. Each icmp condition has a clear mapping to an | 482 /// for i32 and narrower types. Each icmp condition has a clear mapping to an |
318 // x86 conditional branch instruction. | 483 /// x86 conditional branch instruction. |
484 /// {@ | |
485 static const struct TableIcmp32Type { Cond::BrCond Mapping; } TableIcmp32[]; | |
486 static const size_t TableIcmp32Size; | |
487 /// @} | |
319 | 488 |
320 static const struct TableIcmp32Type { | 489 /// The following table summarizes the logic for lowering the icmp instruction |
321 CondX86::BrCond Mapping; | 490 /// for the i64 type. For Eq and Ne, two separate 32-bit comparisons and |
322 } TableIcmp32[]; | 491 /// conditional branches are needed. For the other conditions, three separate |
323 static const size_t TableIcmp32Size; | 492 /// conditional branches are needed. |
324 | 493 /// {@ |
325 // The following table summarizes the logic for lowering the icmp instruction | |
326 // for the i64 type. For Eq and Ne, two separate 32-bit comparisons and | |
327 // conditional branches are needed. For the other conditions, three separate | |
328 // conditional branches are needed. | |
329 static const struct TableIcmp64Type { | 494 static const struct TableIcmp64Type { |
330 CondX86::BrCond C1, C2, C3; | 495 Cond::BrCond C1, C2, C3; |
331 } TableIcmp64[]; | 496 } TableIcmp64[]; |
332 static const size_t TableIcmp64Size; | 497 static const size_t TableIcmp64Size; |
498 /// @} | |
333 | 499 |
334 static CondX86::BrCond getIcmp32Mapping(InstIcmp::ICond Cond) { | 500 static Cond::BrCond getIcmp32Mapping(InstIcmp::ICond Cond) { |
335 size_t Index = static_cast<size_t>(Cond); | 501 size_t Index = static_cast<size_t>(Cond); |
336 assert(Index < TableIcmp32Size); | 502 assert(Index < TableIcmp32Size); |
337 return TableIcmp32[Index].Mapping; | 503 return TableIcmp32[Index].Mapping; |
338 } | 504 } |
339 | 505 |
340 static const struct TableTypeX8632AttributesType { | 506 static const struct TableTypeX8632AttributesType { |
341 Type InVectorElementType; | 507 Type InVectorElementType; |
342 } TableTypeX8632Attributes[]; | 508 } TableTypeX8632Attributes[]; |
343 static const size_t TableTypeX8632AttributesSize; | 509 static const size_t TableTypeX8632AttributesSize; |
510 | |
511 //---------------------------------------------------------------------------- | |
512 // __ __ __ ______ ______ | |
513 // /\ \/\ "-.\ \/\ ___\/\__ _\ | |
514 // \ \ \ \ \-. \ \___ \/_/\ \/ | |
515 // \ \_\ \_\\"\_\/\_____\ \ \_\ | |
516 // \/_/\/_/ \/_/\/_____/ \/_/ | |
517 // | |
518 //---------------------------------------------------------------------------- | |
519 using Insts = ::Ice::X86Internal::Insts<TargetX8632>; | |
520 | |
521 using TargetLowering = TargetX8632; | |
522 using Assembler = X8632::AssemblerX8632; | |
523 | |
524 /// X86Operand extends the Operand hierarchy. Its subclasses are | |
525 /// X86OperandMem and VariableSplit. | |
526 class X86Operand : public ::Ice::Operand { | |
527 X86Operand() = delete; | |
528 X86Operand(const X86Operand &) = delete; | |
529 X86Operand &operator=(const X86Operand &) = delete; | |
530 | |
531 public: | |
532 enum OperandKindX8632 { k__Start = ::Ice::Operand::kTarget, kMem, kSplit }; | |
533 using ::Ice::Operand::dump; | |
534 | |
535 void dump(const Cfg *, Ostream &Str) const override; | |
536 | |
537 protected: | |
538 X86Operand(OperandKindX8632 Kind, Type Ty) | |
539 : Operand(static_cast<::Ice::Operand::OperandKind>(Kind), Ty) {} | |
540 }; | |
541 | |
542 /// X86OperandMem represents the m32 addressing mode, with optional base and | |
543 /// index registers, a constant offset, and a fixed shift value for the index | |
544 /// register. | |
545 class X86OperandMem : public X86Operand { | |
546 X86OperandMem() = delete; | |
547 X86OperandMem(const X86OperandMem &) = delete; | |
548 X86OperandMem &operator=(const X86OperandMem &) = delete; | |
549 | |
550 public: | |
551 enum SegmentRegisters { | |
552 DefaultSegment = -1, | |
553 #define X(val, name, prefix) val, | |
554 SEG_REGX8632_TABLE | |
555 #undef X | |
556 SegReg_NUM | |
557 }; | |
558 static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base, | |
559 Constant *Offset, Variable *Index = nullptr, | |
560 uint16_t Shift = 0, | |
561 SegmentRegisters SegmentReg = DefaultSegment) { | |
562 return new (Func->allocate<X86OperandMem>()) | |
563 X86OperandMem(Func, Ty, Base, Offset, Index, Shift, SegmentReg); | |
564 } | |
565 Variable *getBase() const { return Base; } | |
566 Constant *getOffset() const { return Offset; } | |
567 Variable *getIndex() const { return Index; } | |
568 uint16_t getShift() const { return Shift; } | |
569 SegmentRegisters getSegmentRegister() const { return SegmentReg; } | |
570 void emitSegmentOverride(Assembler *Asm) const; | |
571 Address toAsmAddress(Assembler *Asm) const; | |
572 | |
573 void emit(const Cfg *Func) const override; | |
574 using X86Operand::dump; | |
575 void dump(const Cfg *Func, Ostream &Str) const override; | |
576 | |
577 static bool classof(const Operand *Operand) { | |
578 return Operand->getKind() == static_cast<OperandKind>(kMem); | |
579 } | |
580 | |
581 void setRandomized(bool R) { Randomized = R; } | |
582 | |
583 bool getRandomized() const { return Randomized; } | |
584 | |
585 private: | |
586 X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset, | |
587 Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg); | |
588 | |
589 Variable *Base; | |
590 Constant *Offset; | |
591 Variable *Index; | |
592 uint16_t Shift; | |
593 SegmentRegisters SegmentReg : 16; | |
594 /// A flag to show if this memory operand is a randomized one. Randomized | |
595 /// memory operands are generated in | |
596 /// TargetX86Base::randomizeOrPoolImmediate() | |
597 bool Randomized; | |
598 }; | |
599 | |
600 /// VariableSplit is a way to treat an f64 memory location as a pair of i32 | |
601 /// locations (Low and High). This is needed for some cases of the Bitcast | |
602 /// instruction. Since it's not possible for integer registers to access the | |
603 /// XMM registers and vice versa, the lowering forces the f64 to be spilled to | |
604 /// the stack and then accesses through the VariableSplit. | |
605 // TODO(jpp): remove references to SplitVariable from IceInstX86Base as 64bit | |
jvoung (off chromium)
2015/07/07 17:23:00
SplitVariable -> VariableSplit
John
2015/07/07 18:23:17
Done.
| |
606 // targets can natively handle these. | |
607 class VariableSplit : public X86Operand { | |
608 VariableSplit() = delete; | |
609 VariableSplit(const VariableSplit &) = delete; | |
610 VariableSplit &operator=(const VariableSplit &) = delete; | |
611 | |
612 public: | |
613 enum Portion { Low, High }; | |
614 static VariableSplit *create(Cfg *Func, Variable *Var, Portion Part) { | |
615 return new (Func->allocate<VariableSplit>()) | |
616 VariableSplit(Func, Var, Part); | |
617 } | |
618 int32_t getOffset() const { return Part == High ? 4 : 0; } | |
619 | |
620 Address toAsmAddress(const Cfg *Func) const; | |
621 void emit(const Cfg *Func) const override; | |
622 using X86Operand::dump; | |
623 void dump(const Cfg *Func, Ostream &Str) const override; | |
624 | |
625 static bool classof(const Operand *Operand) { | |
626 return Operand->getKind() == static_cast<OperandKind>(kSplit); | |
627 } | |
628 | |
629 private: | |
630 VariableSplit(Cfg *Func, Variable *Var, Portion Part) | |
631 : X86Operand(kSplit, IceType_i32), Var(Var), Part(Part) { | |
632 assert(Var->getType() == IceType_f64); | |
633 Vars = Func->allocateArrayOf<Variable *>(1); | |
634 Vars[0] = Var; | |
635 NumVars = 1; | |
636 } | |
637 | |
638 Variable *Var; | |
639 Portion Part; | |
640 }; | |
641 | |
642 /// SpillVariable decorates a Variable by linking it to another Variable. | |
643 /// When stack frame offsets are computed, the SpillVariable is given a | |
644 /// distinct stack slot only if its linked Variable has a register. If the | |
645 /// linked Variable has a stack slot, then the Variable and SpillVariable | |
646 /// share that slot. | |
647 class SpillVariable : public Variable { | |
648 SpillVariable() = delete; | |
649 SpillVariable(const SpillVariable &) = delete; | |
650 SpillVariable &operator=(const SpillVariable &) = delete; | |
651 | |
652 public: | |
653 static SpillVariable *create(Cfg *Func, Type Ty, SizeT Index) { | |
654 return new (Func->allocate<SpillVariable>()) SpillVariable(Ty, Index); | |
655 } | |
656 const static OperandKind SpillVariableKind = | |
657 static_cast<OperandKind>(kVariable_Target); | |
658 static bool classof(const Operand *Operand) { | |
659 return Operand->getKind() == SpillVariableKind; | |
660 } | |
661 void setLinkedTo(Variable *Var) { LinkedTo = Var; } | |
662 Variable *getLinkedTo() const { return LinkedTo; } | |
663 // Inherit dump() and emit() from Variable. | |
664 | |
665 private: | |
666 SpillVariable(Type Ty, SizeT Index) | |
667 : Variable(SpillVariableKind, Ty, Index), LinkedTo(nullptr) {} | |
668 Variable *LinkedTo; | |
669 }; | |
670 | |
671 // Note: The following data structures are defined in IceInstX8632.cpp. | |
672 | |
673 static const struct InstBrAttributesType { | |
674 Cond::BrCond Opposite; | |
675 const char *DisplayString; | |
676 const char *EmitString; | |
677 } InstBrAttributes[]; | |
678 | |
679 static const struct InstCmppsAttributesType { | |
680 const char *EmitString; | |
681 } InstCmppsAttributes[]; | |
682 | |
683 static const struct TypeAttributesType { | |
684 const char *CvtString; // i (integer), s (single FP), d (double FP) | |
685 const char *SdSsString; // ss, sd, or <blank> | |
686 const char *PackString; // b, w, d, or <blank> | |
687 const char *WidthString; // b, w, l, q, or <blank> | |
688 const char *FldString; // s, l, or <blank> | |
689 } TypeAttributes[]; | |
690 | |
691 static const char *InstSegmentRegNames[]; | |
692 | |
693 static uint8_t InstSegmentPrefixes[]; | |
344 }; | 694 }; |
345 | 695 |
346 } // end of namespace X86Internal | 696 } // end of namespace X86Internal |
347 | 697 |
348 namespace X8632 { | 698 namespace X8632 { |
349 using Traits = ::Ice::X86Internal::MachineTraits<TargetX8632>; | 699 using Traits = ::Ice::X86Internal::MachineTraits<TargetX8632>; |
350 } // end of namespace X8632 | 700 } // end of namespace X8632 |
351 | 701 |
352 } // end of namespace Ice | 702 } // end of namespace Ice |
353 | 703 |
354 #endif // SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H | 704 #endif // SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H |
OLD | NEW |