OLD | NEW |
---|---|
1 //===- subzero/src/IceTargetLoweringX8664.cpp - lowering for x86-64 -------===// | 1 //===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 lowering -----------===// |
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 /// \file | 10 /// \file |
11 /// Implements the Target Lowering for x86-64. | 11 /// This file implements the TargetLoweringX8664 class, which |
12 /// consists almost entirely of the lowering sequence for each | |
13 /// high-level instruction. | |
12 /// | 14 /// |
13 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
14 | 16 |
15 #include "IceDefs.h" | |
16 #include "IceTargetLoweringX8664.h" | 17 #include "IceTargetLoweringX8664.h" |
17 | 18 |
19 #include "IceTargetLoweringX8664Traits.h" | |
20 #include "IceTargetLoweringX86Base.h" | |
21 | |
18 namespace Ice { | 22 namespace Ice { |
19 | 23 |
20 TargetX8664 *TargetX8664::create(Cfg *) { | 24 namespace X86Internal { |
21 llvm::report_fatal_error("Not yet implemented"); | 25 const MachineTraits<TargetX8664>::TableFcmpType |
26 MachineTraits<TargetX8664>::TableFcmp[] = { | |
27 #define X(val, dflt, swapS, C1, C2, swapV, pred) \ | |
28 { \ | |
29 dflt, swapS, X8664::Traits::Cond::C1, X8664::Traits::Cond::C2, swapV, \ | |
30 X8664::Traits::Cond::pred \ | |
31 } \ | |
32 , | |
33 FCMPX8664_TABLE | |
34 #undef X | |
35 }; | |
36 | |
37 const size_t MachineTraits<TargetX8664>::TableFcmpSize = | |
38 llvm::array_lengthof(TableFcmp); | |
39 | |
40 const MachineTraits<TargetX8664>::TableIcmp32Type | |
41 MachineTraits<TargetX8664>::TableIcmp32[] = { | |
42 #define X(val, C_32, C1_64, C2_64, C3_64) \ | |
43 { X8664::Traits::Cond::C_32 } \ | |
44 , | |
45 ICMPX8664_TABLE | |
46 #undef X | |
47 }; | |
48 | |
49 const size_t MachineTraits<TargetX8664>::TableIcmp32Size = | |
50 llvm::array_lengthof(TableIcmp32); | |
51 | |
52 const MachineTraits<TargetX8664>::TableIcmp64Type | |
Jim Stichnoth
2015/07/30 19:11:08
Presumably this is just cargo-culting that will la
John
2015/07/31 21:05:54
Correct. As the CL description states I did not im
| |
53 MachineTraits<TargetX8664>::TableIcmp64[] = { | |
54 #define X(val, C_32, C1_64, C2_64, C3_64) \ | |
55 { \ | |
56 X8664::Traits::Cond::C1_64, X8664::Traits::Cond::C2_64, \ | |
57 X8664::Traits::Cond::C3_64 \ | |
58 } \ | |
59 , | |
60 ICMPX8664_TABLE | |
61 #undef X | |
62 }; | |
63 | |
64 const size_t MachineTraits<TargetX8664>::TableIcmp64Size = | |
65 llvm::array_lengthof(TableIcmp64); | |
66 | |
67 const MachineTraits<TargetX8664>::TableTypeX8664AttributesType | |
68 MachineTraits<TargetX8664>::TableTypeX8664Attributes[] = { | |
69 #define X(tag, elementty, cvt, sdss, pack, width, fld) \ | |
70 { elementty } \ | |
71 , | |
72 ICETYPEX8664_TABLE | |
73 #undef X | |
74 }; | |
75 | |
76 const size_t MachineTraits<TargetX8664>::TableTypeX8664AttributesSize = | |
77 llvm::array_lengthof(TableTypeX8664Attributes); | |
78 | |
79 const uint32_t MachineTraits<TargetX8664>::X86_STACK_ALIGNMENT_BYTES = 16; | |
Jim Stichnoth
2015/07/30 19:11:08
Can/should this be constexpr?
John
2015/07/31 21:05:54
No, it can not. having this as a constexpr causes
| |
80 const char *MachineTraits<TargetX8664>::TargetName = "X8664"; | |
81 | |
82 } // end of namespace X86Internal | |
83 | |
84 namespace { | |
85 template <typename T> struct PoolTypeConverter {}; | |
86 | |
87 template <> struct PoolTypeConverter<float> { | |
88 typedef uint32_t PrimitiveIntType; | |
89 typedef ConstantFloat IceType; | |
90 static const Type Ty = IceType_f32; | |
91 static const char *TypeName; | |
92 static const char *AsmTag; | |
93 static const char *PrintfString; | |
94 }; | |
95 const char *PoolTypeConverter<float>::TypeName = "float"; | |
96 const char *PoolTypeConverter<float>::AsmTag = ".long"; | |
97 const char *PoolTypeConverter<float>::PrintfString = "0x%x"; | |
98 | |
99 template <> struct PoolTypeConverter<double> { | |
100 typedef uint64_t PrimitiveIntType; | |
101 typedef ConstantDouble IceType; | |
102 static const Type Ty = IceType_f64; | |
103 static const char *TypeName; | |
104 static const char *AsmTag; | |
105 static const char *PrintfString; | |
106 }; | |
107 const char *PoolTypeConverter<double>::TypeName = "double"; | |
108 const char *PoolTypeConverter<double>::AsmTag = ".quad"; | |
109 const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; | |
110 | |
111 // Add converter for int type constant pooling | |
112 template <> struct PoolTypeConverter<uint32_t> { | |
113 typedef uint32_t PrimitiveIntType; | |
114 typedef ConstantInteger32 IceType; | |
115 static const Type Ty = IceType_i32; | |
116 static const char *TypeName; | |
117 static const char *AsmTag; | |
118 static const char *PrintfString; | |
119 }; | |
120 const char *PoolTypeConverter<uint32_t>::TypeName = "i32"; | |
121 const char *PoolTypeConverter<uint32_t>::AsmTag = ".long"; | |
122 const char *PoolTypeConverter<uint32_t>::PrintfString = "0x%x"; | |
123 | |
124 // Add converter for int type constant pooling | |
125 template <> struct PoolTypeConverter<uint16_t> { | |
126 typedef uint32_t PrimitiveIntType; | |
127 typedef ConstantInteger32 IceType; | |
128 static const Type Ty = IceType_i16; | |
129 static const char *TypeName; | |
130 static const char *AsmTag; | |
131 static const char *PrintfString; | |
132 }; | |
133 const char *PoolTypeConverter<uint16_t>::TypeName = "i16"; | |
134 const char *PoolTypeConverter<uint16_t>::AsmTag = ".short"; | |
135 const char *PoolTypeConverter<uint16_t>::PrintfString = "0x%x"; | |
136 | |
137 // Add converter for int type constant pooling | |
138 template <> struct PoolTypeConverter<uint8_t> { | |
139 typedef uint32_t PrimitiveIntType; | |
140 typedef ConstantInteger32 IceType; | |
141 static const Type Ty = IceType_i8; | |
142 static const char *TypeName; | |
143 static const char *AsmTag; | |
144 static const char *PrintfString; | |
145 }; | |
146 const char *PoolTypeConverter<uint8_t>::TypeName = "i8"; | |
147 const char *PoolTypeConverter<uint8_t>::AsmTag = ".byte"; | |
148 const char *PoolTypeConverter<uint8_t>::PrintfString = "0x%x"; | |
149 } // end of anonymous namespace | |
150 | |
151 template <typename T> | |
152 void TargetDataX8664::emitConstantPool(GlobalContext *Ctx) { | |
153 if (!BuildDefs::dump()) | |
154 return; | |
155 Ostream &Str = Ctx->getStrEmit(); | |
156 Type Ty = T::Ty; | |
157 SizeT Align = typeAlignInBytes(Ty); | |
158 ConstantList Pool = Ctx->getConstantPool(Ty); | |
159 | |
160 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align | |
161 << "\n"; | |
162 Str << "\t.align\t" << Align << "\n"; | |
163 | |
164 // If reorder-pooled-constants option is set to true, we need to shuffle the | |
165 // constant pool before emitting it. | |
166 if (Ctx->getFlags().shouldReorderPooledConstants()) | |
167 RandomShuffle(Pool.begin(), Pool.end(), [Ctx](uint64_t N) { | |
168 return (uint32_t)Ctx->getRNG().next(N); | |
169 }); | |
170 | |
171 for (Constant *C : Pool) { | |
172 if (!C->getShouldBePooled()) | |
173 continue; | |
174 typename T::IceType *Const = llvm::cast<typename T::IceType>(C); | |
175 typename T::IceType::PrimType Value = Const->getValue(); | |
176 // Use memcpy() to copy bits from Value into RawValue in a way | |
177 // that avoids breaking strict-aliasing rules. | |
178 typename T::PrimitiveIntType RawValue; | |
179 memcpy(&RawValue, &Value, sizeof(Value)); | |
180 char buf[30]; | |
181 int CharsPrinted = | |
182 snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); | |
183 assert(CharsPrinted >= 0 && | |
184 (size_t)CharsPrinted < llvm::array_lengthof(buf)); | |
185 (void)CharsPrinted; // avoid warnings if asserts are disabled | |
186 Const->emitPoolLabel(Str); | |
187 Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " " | |
188 << Value << "\n"; | |
189 } | |
22 } | 190 } |
23 void TargetDataX8664::lowerGlobals(const VariableDeclarationList &, | 191 |
24 const IceString &) { | 192 void TargetDataX8664::lowerConstants() { |
25 llvm::report_fatal_error("Not yet implemented"); | 193 if (Ctx->getFlags().getDisableTranslation()) |
194 return; | |
195 // No need to emit constants from the int pool since (for x86) they | |
196 // are embedded as immediates in the instructions, just emit float/double. | |
197 switch (Ctx->getFlags().getOutFileType()) { | |
198 case FT_Elf: { | |
199 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
200 | |
201 Writer->writeConstantPool<ConstantInteger32>(IceType_i8); | |
202 Writer->writeConstantPool<ConstantInteger32>(IceType_i16); | |
203 Writer->writeConstantPool<ConstantInteger32>(IceType_i32); | |
204 | |
205 Writer->writeConstantPool<ConstantFloat>(IceType_f32); | |
206 Writer->writeConstantPool<ConstantDouble>(IceType_f64); | |
207 } break; | |
208 case FT_Asm: | |
209 case FT_Iasm: { | |
210 OstreamLocker L(Ctx); | |
211 | |
212 emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx); | |
213 emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx); | |
214 emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx); | |
215 | |
216 emitConstantPool<PoolTypeConverter<float>>(Ctx); | |
217 emitConstantPool<PoolTypeConverter<double>>(Ctx); | |
218 } break; | |
219 } | |
26 } | 220 } |
27 | 221 |
28 void TargetDataX8664::lowerConstants() { | 222 void TargetDataX8664::lowerGlobals(const VariableDeclarationList &Vars, |
29 llvm::report_fatal_error("Not yet implemented"); | 223 const IceString &SectionSuffix) { |
224 switch (Ctx->getFlags().getOutFileType()) { | |
225 case FT_Elf: { | |
226 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
227 Writer->writeDataSection(Vars, llvm::ELF::R_386_32, SectionSuffix); | |
jvoung (off chromium)
2015/07/30 21:16:22
TODO(jpp) to change this reloc to be not 386.
John
2015/07/31 21:05:54
Done.
| |
228 } break; | |
229 case FT_Asm: | |
230 case FT_Iasm: { | |
231 const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); | |
232 OstreamLocker L(Ctx); | |
233 for (const VariableDeclaration *Var : Vars) { | |
234 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { | |
235 emitGlobal(*Var, SectionSuffix); | |
236 } | |
237 } | |
238 } break; | |
239 } | |
30 } | 240 } |
31 | 241 |
242 // In some cases, there are x-macros tables for both high-level and | |
243 // low-level instructions/operands that use the same enum key value. | |
244 // The tables are kept separate to maintain a proper separation | |
245 // between abstraction layers. There is a risk that the tables could | |
246 // get out of sync if enum values are reordered or if entries are | |
247 // added or deleted. The following dummy namespaces use | |
248 // static_asserts to ensure everything is kept in sync. | |
249 | |
250 namespace { | |
251 // Validate the enum values in FCMPX8664_TABLE. | |
252 namespace dummy1 { | |
253 // Define a temporary set of enum values based on low-level table | |
254 // entries. | |
255 enum _tmp_enum { | |
256 #define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val, | |
257 FCMPX8664_TABLE | |
258 #undef X | |
259 _num | |
260 }; | |
261 // Define a set of constants based on high-level table entries. | |
262 #define X(tag, str) static const int _table1_##tag = InstFcmp::tag; | |
263 ICEINSTFCMP_TABLE | |
264 #undef X | |
265 // Define a set of constants based on low-level table entries, and | |
266 // ensure the table entry keys are consistent. | |
267 #define X(val, dflt, swapS, C1, C2, swapV, pred) \ | |
268 static const int _table2_##val = _tmp_##val; \ | |
269 static_assert( \ | |
270 _table1_##val == _table2_##val, \ | |
271 "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); | |
272 FCMPX8664_TABLE | |
273 #undef X | |
274 // Repeat the static asserts with respect to the high-level table | |
275 // entries in case the high-level table has extra entries. | |
276 #define X(tag, str) \ | |
277 static_assert( \ | |
278 _table1_##tag == _table2_##tag, \ | |
279 "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); | |
280 ICEINSTFCMP_TABLE | |
281 #undef X | |
282 } // end of namespace dummy1 | |
283 | |
284 // Validate the enum values in ICMPX8664_TABLE. | |
285 namespace dummy2 { | |
286 // Define a temporary set of enum values based on low-level table | |
287 // entries. | |
288 enum _tmp_enum { | |
289 #define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val, | |
290 ICMPX8664_TABLE | |
291 #undef X | |
292 _num | |
293 }; | |
294 // Define a set of constants based on high-level table entries. | |
295 #define X(tag, str) static const int _table1_##tag = InstIcmp::tag; | |
296 ICEINSTICMP_TABLE | |
297 #undef X | |
298 // Define a set of constants based on low-level table entries, and | |
299 // ensure the table entry keys are consistent. | |
300 #define X(val, C_32, C1_64, C2_64, C3_64) \ | |
301 static const int _table2_##val = _tmp_##val; \ | |
302 static_assert( \ | |
303 _table1_##val == _table2_##val, \ | |
304 "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); | |
305 ICMPX8664_TABLE | |
306 #undef X | |
307 // Repeat the static asserts with respect to the high-level table | |
308 // entries in case the high-level table has extra entries. | |
309 #define X(tag, str) \ | |
310 static_assert( \ | |
311 _table1_##tag == _table2_##tag, \ | |
312 "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); | |
313 ICEINSTICMP_TABLE | |
314 #undef X | |
315 } // end of namespace dummy2 | |
316 | |
317 // Validate the enum values in ICETYPEX8664_TABLE. | |
318 namespace dummy3 { | |
319 // Define a temporary set of enum values based on low-level table | |
320 // entries. | |
321 enum _tmp_enum { | |
322 #define X(tag, elementty, cvt, sdss, pack, width, fld) _tmp_##tag, | |
323 ICETYPEX8664_TABLE | |
324 #undef X | |
325 _num | |
326 }; | |
327 // Define a set of constants based on high-level table entries. | |
328 #define X(tag, sizeLog2, align, elts, elty, str) \ | |
329 static const int _table1_##tag = tag; | |
330 ICETYPE_TABLE | |
331 #undef X | |
332 // Define a set of constants based on low-level table entries, and | |
333 // ensure the table entry keys are consistent. | |
334 #define X(tag, elementty, cvt, sdss, pack, width, fld) \ | |
335 static const int _table2_##tag = _tmp_##tag; \ | |
336 static_assert(_table1_##tag == _table2_##tag, \ | |
337 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); | |
338 ICETYPEX8664_TABLE | |
339 #undef X | |
340 // Repeat the static asserts with respect to the high-level table | |
341 // entries in case the high-level table has extra entries. | |
342 #define X(tag, sizeLog2, align, elts, elty, str) \ | |
343 static_assert(_table1_##tag == _table2_##tag, \ | |
344 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); | |
345 ICETYPE_TABLE | |
346 #undef X | |
347 } // end of namespace dummy3 | |
348 } // end of anonymous namespace | |
349 | |
32 } // end of namespace Ice | 350 } // end of namespace Ice |
OLD | NEW |