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