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 VariableSplit from IceInstX86Base as 64bit |
| 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 |