OLD | NEW |
1 //===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 lowering -----------===// | 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 /// This file implements the TargetLoweringX8664 class, which | 11 /// This file implements the TargetLoweringX8664 class, which consists almost |
12 /// consists almost entirely of the lowering sequence for each | 12 /// entirely of the lowering sequence for each high-level instruction. |
13 /// high-level instruction. | |
14 /// | 13 /// |
15 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
16 | 15 |
17 #include "IceTargetLoweringX8664.h" | 16 #include "IceTargetLoweringX8664.h" |
18 | 17 |
19 #include "IceTargetLoweringX8664Traits.h" | 18 #include "IceTargetLoweringX8664Traits.h" |
20 #include "IceTargetLoweringX86Base.h" | 19 #include "IceTargetLoweringX86Base.h" |
21 | 20 |
22 namespace Ice { | 21 namespace Ice { |
23 | 22 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 | 123 |
125 // constexprMax returns a (constexpr) max(S0, S1), and it is used for defining | 124 // constexprMax returns a (constexpr) max(S0, S1), and it is used for defining |
126 // OperandList in lowerCall. std::max() is supposed to work, but it doesn't. | 125 // OperandList in lowerCall. std::max() is supposed to work, but it doesn't. |
127 constexpr SizeT constexprMax(SizeT S0, SizeT S1) { return S0 < S1 ? S1 : S0; } | 126 constexpr SizeT constexprMax(SizeT S0, SizeT S1) { return S0 < S1 ? S1 : S0; } |
128 | 127 |
129 } // end of anonymous namespace | 128 } // end of anonymous namespace |
130 | 129 |
131 void TargetX8664::lowerCall(const InstCall *Instr) { | 130 void TargetX8664::lowerCall(const InstCall *Instr) { |
132 // x86-64 calling convention: | 131 // x86-64 calling convention: |
133 // | 132 // |
134 // * At the point before the call, the stack must be aligned to 16 | 133 // * At the point before the call, the stack must be aligned to 16 bytes. |
135 // bytes. | |
136 // | 134 // |
137 // * The first eight arguments of vector/fp type, regardless of their | 135 // * The first eight arguments of vector/fp type, regardless of their |
138 // position relative to the other arguments in the argument list, are | 136 // position relative to the other arguments in the argument list, are placed |
139 // placed in registers %xmm0 - %xmm7. | 137 // in registers %xmm0 - %xmm7. |
140 // | 138 // |
141 // * The first six arguments of integer types, regardless of their | 139 // * The first six arguments of integer types, regardless of their position |
142 // position relative to the other arguments in the argument list, are | 140 // relative to the other arguments in the argument list, are placed in |
143 // placed in registers %rdi, %rsi, %rdx, %rcx, %r8, and %r9. | 141 // registers %rdi, %rsi, %rdx, %rcx, %r8, and %r9. |
144 // | 142 // |
145 // * Other arguments are pushed onto the stack in right-to-left order, | 143 // * Other arguments are pushed onto the stack in right-to-left order, such |
146 // such that the left-most argument ends up on the top of the stack at | 144 // that the left-most argument ends up on the top of the stack at the lowest |
147 // the lowest memory address. | 145 // memory address. |
148 // | 146 // |
149 // * Stack arguments of vector type are aligned to start at the next | 147 // * Stack arguments of vector type are aligned to start at the next highest |
150 // highest multiple of 16 bytes. Other stack arguments are aligned to | 148 // multiple of 16 bytes. Other stack arguments are aligned to 8 bytes. |
151 // 8 bytes. | |
152 // | 149 // |
153 // This intends to match the section "Function Calling Sequence" of the | 150 // This intends to match the section "Function Calling Sequence" of the |
154 // document "System V Application Binary Interface." | 151 // document "System V Application Binary Interface." |
155 NeedsStackAlignment = true; | 152 NeedsStackAlignment = true; |
156 | 153 |
157 using OperandList = | 154 using OperandList = |
158 llvm::SmallVector<Operand *, constexprMax(Traits::X86_MAX_XMM_ARGS, | 155 llvm::SmallVector<Operand *, constexprMax(Traits::X86_MAX_XMM_ARGS, |
159 Traits::X86_MAX_GPR_ARGS)>; | 156 Traits::X86_MAX_GPR_ARGS)>; |
160 OperandList XmmArgs; | 157 OperandList XmmArgs; |
161 OperandList GprArgs; | 158 OperandList GprArgs; |
(...skipping 22 matching lines...) Expand all Loading... |
184 Traits::applyStackAlignment(ParameterAreaSizeBytes); | 181 Traits::applyStackAlignment(ParameterAreaSizeBytes); |
185 } | 182 } |
186 Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); | 183 Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
187 Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes); | 184 Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes); |
188 StackArgLocations.push_back( | 185 StackArgLocations.push_back( |
189 Traits::X86OperandMem::create(Func, Ty, esp, Loc)); | 186 Traits::X86OperandMem::create(Func, Ty, esp, Loc)); |
190 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType()); | 187 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType()); |
191 } | 188 } |
192 } | 189 } |
193 | 190 |
194 // Adjust the parameter area so that the stack is aligned. It is | 191 // Adjust the parameter area so that the stack is aligned. It is assumed that |
195 // assumed that the stack is already aligned at the start of the | 192 // the stack is already aligned at the start of the calling sequence. |
196 // calling sequence. | |
197 ParameterAreaSizeBytes = Traits::applyStackAlignment(ParameterAreaSizeBytes); | 193 ParameterAreaSizeBytes = Traits::applyStackAlignment(ParameterAreaSizeBytes); |
198 | 194 |
199 // Subtract the appropriate amount for the argument area. This also | 195 // Subtract the appropriate amount for the argument area. This also takes |
200 // takes care of setting the stack adjustment during emission. | 196 // care of setting the stack adjustment during emission. |
201 // | 197 // |
202 // TODO: If for some reason the call instruction gets dead-code | 198 // TODO: If for some reason the call instruction gets dead-code eliminated |
203 // eliminated after lowering, we would need to ensure that the | 199 // after lowering, we would need to ensure that the pre-call and the |
204 // pre-call and the post-call esp adjustment get eliminated as well. | 200 // post-call esp adjustment get eliminated as well. |
205 if (ParameterAreaSizeBytes) { | 201 if (ParameterAreaSizeBytes) { |
206 _adjust_stack(ParameterAreaSizeBytes); | 202 _adjust_stack(ParameterAreaSizeBytes); |
207 } | 203 } |
208 | 204 |
209 // Copy arguments that are passed on the stack to the appropriate | 205 // Copy arguments that are passed on the stack to the appropriate stack |
210 // stack locations. | 206 // locations. |
211 for (SizeT i = 0, e = StackArgs.size(); i < e; ++i) { | 207 for (SizeT i = 0, e = StackArgs.size(); i < e; ++i) { |
212 lowerStore(InstStore::create(Func, StackArgs[i], StackArgLocations[i])); | 208 lowerStore(InstStore::create(Func, StackArgs[i], StackArgLocations[i])); |
213 } | 209 } |
214 | 210 |
215 // Copy arguments to be passed in registers to the appropriate | 211 // Copy arguments to be passed in registers to the appropriate registers. |
216 // registers. | 212 // TODO: Investigate the impact of lowering arguments passed in registers |
217 // TODO: Investigate the impact of lowering arguments passed in | 213 // after lowering stack arguments as opposed to the other way around. |
218 // registers after lowering stack arguments as opposed to the other | 214 // Lowering register arguments after stack arguments may reduce register |
219 // way around. Lowering register arguments after stack arguments may | 215 // pressure. On the other hand, lowering register arguments first (before |
220 // reduce register pressure. On the other hand, lowering register | 216 // stack arguments) may result in more compact code, as the memory operand |
221 // arguments first (before stack arguments) may result in more compact | 217 // displacements may end up being smaller before any stack adjustment is |
222 // code, as the memory operand displacements may end up being smaller | 218 // done. |
223 // before any stack adjustment is done. | |
224 for (SizeT i = 0, NumXmmArgs = XmmArgs.size(); i < NumXmmArgs; ++i) { | 219 for (SizeT i = 0, NumXmmArgs = XmmArgs.size(); i < NumXmmArgs; ++i) { |
225 Variable *Reg = legalizeToReg(XmmArgs[i], getRegisterForXmmArgNum(i)); | 220 Variable *Reg = legalizeToReg(XmmArgs[i], getRegisterForXmmArgNum(i)); |
226 // Generate a FakeUse of register arguments so that they do not get | 221 // Generate a FakeUse of register arguments so that they do not get dead |
227 // dead code eliminated as a result of the FakeKill of scratch | 222 // code eliminated as a result of the FakeKill of scratch registers after |
228 // registers after the call. | 223 // the call. |
229 Context.insert(InstFakeUse::create(Func, Reg)); | 224 Context.insert(InstFakeUse::create(Func, Reg)); |
230 } | 225 } |
231 | 226 |
232 for (SizeT i = 0, NumGprArgs = GprArgs.size(); i < NumGprArgs; ++i) { | 227 for (SizeT i = 0, NumGprArgs = GprArgs.size(); i < NumGprArgs; ++i) { |
233 Variable *Reg = legalizeToReg(GprArgs[i], getRegisterForGprArgNum(i)); | 228 Variable *Reg = legalizeToReg(GprArgs[i], getRegisterForGprArgNum(i)); |
234 Context.insert(InstFakeUse::create(Func, Reg)); | 229 Context.insert(InstFakeUse::create(Func, Reg)); |
235 } | 230 } |
236 | 231 |
237 // Generate the call instruction. Assign its result to a temporary | 232 // Generate the call instruction. Assign its result to a temporary with high |
238 // with high register allocation weight. | 233 // register allocation weight. |
239 Variable *Dest = Instr->getDest(); | 234 Variable *Dest = Instr->getDest(); |
240 // ReturnReg doubles as ReturnRegLo as necessary. | 235 // ReturnReg doubles as ReturnRegLo as necessary. |
241 Variable *ReturnReg = nullptr; | 236 Variable *ReturnReg = nullptr; |
242 if (Dest) { | 237 if (Dest) { |
243 switch (Dest->getType()) { | 238 switch (Dest->getType()) { |
244 case IceType_NUM: | 239 case IceType_NUM: |
245 case IceType_void: | 240 case IceType_void: |
246 llvm::report_fatal_error("Invalid Call dest type"); | 241 llvm::report_fatal_error("Invalid Call dest type"); |
247 break; | 242 break; |
248 case IceType_i1: | 243 case IceType_i1: |
(...skipping 21 matching lines...) Expand all Loading... |
270 const bool NeedSandboxing = Ctx->getFlags().getUseSandboxing(); | 265 const bool NeedSandboxing = Ctx->getFlags().getUseSandboxing(); |
271 if (NeedSandboxing) { | 266 if (NeedSandboxing) { |
272 llvm_unreachable("X86-64 Sandboxing codegen not implemented."); | 267 llvm_unreachable("X86-64 Sandboxing codegen not implemented."); |
273 } | 268 } |
274 Inst *NewCall = Traits::Insts::Call::create(Func, ReturnReg, CallTarget); | 269 Inst *NewCall = Traits::Insts::Call::create(Func, ReturnReg, CallTarget); |
275 Context.insert(NewCall); | 270 Context.insert(NewCall); |
276 if (NeedSandboxing) { | 271 if (NeedSandboxing) { |
277 llvm_unreachable("X86-64 Sandboxing codegen not implemented."); | 272 llvm_unreachable("X86-64 Sandboxing codegen not implemented."); |
278 } | 273 } |
279 | 274 |
280 // Add the appropriate offset to esp. The call instruction takes care | 275 // Add the appropriate offset to esp. The call instruction takes care of |
281 // of resetting the stack offset during emission. | 276 // resetting the stack offset during emission. |
282 if (ParameterAreaSizeBytes) { | 277 if (ParameterAreaSizeBytes) { |
283 Variable *Esp = | 278 Variable *Esp = |
284 Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp); | 279 Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
285 _add(Esp, Ctx->getConstantInt32(ParameterAreaSizeBytes)); | 280 _add(Esp, Ctx->getConstantInt32(ParameterAreaSizeBytes)); |
286 } | 281 } |
287 | 282 |
288 // Insert a register-kill pseudo instruction. | 283 // Insert a register-kill pseudo instruction. |
289 Context.insert(InstFakeKill::create(Func, NewCall)); | 284 Context.insert(InstFakeKill::create(Func, NewCall)); |
290 | 285 |
291 // Generate a FakeUse to keep the call live if necessary. | 286 // Generate a FakeUse to keep the call live if necessary. |
(...skipping 11 matching lines...) Expand all Loading... |
303 _movp(Dest, ReturnReg); | 298 _movp(Dest, ReturnReg); |
304 } else { | 299 } else { |
305 assert(isScalarFloatingType(Dest->getType()) || | 300 assert(isScalarFloatingType(Dest->getType()) || |
306 isScalarIntegerType(Dest->getType())); | 301 isScalarIntegerType(Dest->getType())); |
307 _mov(Dest, ReturnReg); | 302 _mov(Dest, ReturnReg); |
308 } | 303 } |
309 } | 304 } |
310 | 305 |
311 void TargetX8664::lowerArguments() { | 306 void TargetX8664::lowerArguments() { |
312 VarList &Args = Func->getArgs(); | 307 VarList &Args = Func->getArgs(); |
313 // The first eight vetcor typed arguments (as well as fp arguments) are passed | 308 // The first eight vetcor typed arguments (as well as fp arguments) are |
314 // in %xmm0 through %xmm7 regardless of their position in the argument list. | 309 // passed in %xmm0 through %xmm7 regardless of their position in the argument |
| 310 // list. |
315 unsigned NumXmmArgs = 0; | 311 unsigned NumXmmArgs = 0; |
316 // The first six integer typed arguments are passed in %rdi, %rsi, %rdx, %rcx, | 312 // The first six integer typed arguments are passed in %rdi, %rsi, %rdx, |
317 // %r8, and %r9 regardless of their position in the argument list. | 313 // %rcx, %r8, and %r9 regardless of their position in the argument list. |
318 unsigned NumGprArgs = 0; | 314 unsigned NumGprArgs = 0; |
319 | 315 |
320 Context.init(Func->getEntryNode()); | 316 Context.init(Func->getEntryNode()); |
321 Context.setInsertPoint(Context.getCur()); | 317 Context.setInsertPoint(Context.getCur()); |
322 | 318 |
323 for (SizeT i = 0, End = Args.size(); | 319 for (SizeT i = 0, End = Args.size(); |
324 i < End && (NumXmmArgs < Traits::X86_MAX_XMM_ARGS || | 320 i < End && (NumXmmArgs < Traits::X86_MAX_XMM_ARGS || |
325 NumGprArgs < Traits::X86_MAX_XMM_ARGS); | 321 NumGprArgs < Traits::X86_MAX_XMM_ARGS); |
326 ++i) { | 322 ++i) { |
327 Variable *Arg = Args[i]; | 323 Variable *Arg = Args[i]; |
(...skipping 10 matching lines...) Expand all Loading... |
338 } else if (isScalarIntegerType(Ty)) { | 334 } else if (isScalarIntegerType(Ty)) { |
339 if (NumGprArgs >= Traits::X86_MAX_GPR_ARGS) { | 335 if (NumGprArgs >= Traits::X86_MAX_GPR_ARGS) { |
340 continue; | 336 continue; |
341 } | 337 } |
342 RegNum = getRegisterForGprArgNum(NumGprArgs); | 338 RegNum = getRegisterForGprArgNum(NumGprArgs); |
343 ++NumGprArgs; | 339 ++NumGprArgs; |
344 RegisterArg = Func->makeVariable(Ty); | 340 RegisterArg = Func->makeVariable(Ty); |
345 } | 341 } |
346 assert(RegNum != Variable::NoRegister); | 342 assert(RegNum != Variable::NoRegister); |
347 assert(RegisterArg != nullptr); | 343 assert(RegisterArg != nullptr); |
348 // Replace Arg in the argument list with the home register. Then | 344 // Replace Arg in the argument list with the home register. Then generate |
349 // generate an instruction in the prolog to copy the home register | 345 // an instruction in the prolog to copy the home register to the assigned |
350 // to the assigned location of Arg. | 346 // location of Arg. |
351 if (BuildDefs::dump()) | 347 if (BuildDefs::dump()) |
352 RegisterArg->setName(Func, "home_reg:" + Arg->getName(Func)); | 348 RegisterArg->setName(Func, "home_reg:" + Arg->getName(Func)); |
353 RegisterArg->setRegNum(RegNum); | 349 RegisterArg->setRegNum(RegNum); |
354 RegisterArg->setIsArg(); | 350 RegisterArg->setIsArg(); |
355 Arg->setIsArg(false); | 351 Arg->setIsArg(false); |
356 | 352 |
357 Args[i] = RegisterArg; | 353 Args[i] = RegisterArg; |
358 Context.insert(InstAssign::create(Func, Arg, RegisterArg)); | 354 Context.insert(InstAssign::create(Func, Arg, RegisterArg)); |
359 } | 355 } |
360 } | 356 } |
361 | 357 |
362 void TargetX8664::lowerRet(const InstRet *Inst) { | 358 void TargetX8664::lowerRet(const InstRet *Inst) { |
363 Variable *Reg = nullptr; | 359 Variable *Reg = nullptr; |
364 if (Inst->hasRetValue()) { | 360 if (Inst->hasRetValue()) { |
365 Operand *Src0 = legalize(Inst->getRetValue()); | 361 Operand *Src0 = legalize(Inst->getRetValue()); |
366 if (isVectorType(Src0->getType()) || | 362 if (isVectorType(Src0->getType()) || |
367 isScalarFloatingType(Src0->getType())) { | 363 isScalarFloatingType(Src0->getType())) { |
368 Reg = legalizeToReg(Src0, Traits::RegisterSet::Reg_xmm0); | 364 Reg = legalizeToReg(Src0, Traits::RegisterSet::Reg_xmm0); |
369 } else { | 365 } else { |
370 assert(isScalarIntegerType(Src0->getType())); | 366 assert(isScalarIntegerType(Src0->getType())); |
371 _mov(Reg, Src0, Traits::RegisterSet::Reg_eax); | 367 _mov(Reg, Src0, Traits::RegisterSet::Reg_eax); |
372 } | 368 } |
373 } | 369 } |
374 // Add a ret instruction even if sandboxing is enabled, because | 370 // Add a ret instruction even if sandboxing is enabled, because addEpilog |
375 // addEpilog explicitly looks for a ret instruction as a marker for | 371 // explicitly looks for a ret instruction as a marker for where to insert the |
376 // where to insert the frame removal instructions. | 372 // frame removal instructions. |
377 _ret(Reg); | 373 _ret(Reg); |
378 // Add a fake use of esp to make sure esp stays alive for the entire | 374 // Add a fake use of esp to make sure esp stays alive for the entire |
379 // function. Otherwise post-call esp adjustments get dead-code | 375 // function. Otherwise post-call esp adjustments get dead-code eliminated. |
380 // eliminated. TODO: Are there more places where the fake use | 376 // TODO: Are there more places where the fake use should be inserted? E.g. |
381 // should be inserted? E.g. "void f(int n){while(1) g(n);}" may not | 377 // "void f(int n){while(1) g(n);}" may not have a ret instruction. |
382 // have a ret instruction. | |
383 Variable *esp = | 378 Variable *esp = |
384 Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp); | 379 Func->getTarget()->getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
385 Context.insert(InstFakeUse::create(Func, esp)); | 380 Context.insert(InstFakeUse::create(Func, esp)); |
386 } | 381 } |
387 | 382 |
388 void TargetX8664::addProlog(CfgNode *Node) { | 383 void TargetX8664::addProlog(CfgNode *Node) { |
389 // Stack frame layout: | 384 // Stack frame layout: |
390 // | 385 // |
391 // +------------------------+ | 386 // +------------------------+ |
392 // | 1. return address | | 387 // | 1. return address | |
(...skipping 15 matching lines...) Expand all Loading... |
408 // | 403 // |
409 // The following variables record the size in bytes of the given areas: | 404 // The following variables record the size in bytes of the given areas: |
410 // * X86_RET_IP_SIZE_BYTES: area 1 | 405 // * X86_RET_IP_SIZE_BYTES: area 1 |
411 // * PreservedRegsSizeBytes: area 2 | 406 // * PreservedRegsSizeBytes: area 2 |
412 // * SpillAreaPaddingBytes: area 3 | 407 // * SpillAreaPaddingBytes: area 3 |
413 // * GlobalsSize: area 4 | 408 // * GlobalsSize: area 4 |
414 // * GlobalsAndSubsequentPaddingSize: areas 4 - 5 | 409 // * GlobalsAndSubsequentPaddingSize: areas 4 - 5 |
415 // * LocalsSpillAreaSize: area 6 | 410 // * LocalsSpillAreaSize: area 6 |
416 // * SpillAreaSizeBytes: areas 3 - 7 | 411 // * SpillAreaSizeBytes: areas 3 - 7 |
417 | 412 |
418 // Determine stack frame offsets for each Variable without a | 413 // Determine stack frame offsets for each Variable without a register |
419 // register assignment. This can be done as one variable per stack | 414 // assignment. This can be done as one variable per stack slot. Or, do |
420 // slot. Or, do coalescing by running the register allocator again | 415 // coalescing by running the register allocator again with an infinite set of |
421 // with an infinite set of registers (as a side effect, this gives | 416 // registers (as a side effect, this gives variables a second chance at |
422 // variables a second chance at physical register assignment). | 417 // physical register assignment). |
423 // | 418 // |
424 // A middle ground approach is to leverage sparsity and allocate one | 419 // A middle ground approach is to leverage sparsity and allocate one block of |
425 // block of space on the frame for globals (variables with | 420 // space on the frame for globals (variables with multi-block lifetime), and |
426 // multi-block lifetime), and one block to share for locals | 421 // one block to share for locals (single-block lifetime). |
427 // (single-block lifetime). | |
428 | 422 |
429 Context.init(Node); | 423 Context.init(Node); |
430 Context.setInsertPoint(Context.getCur()); | 424 Context.setInsertPoint(Context.getCur()); |
431 | 425 |
432 llvm::SmallBitVector CalleeSaves = | 426 llvm::SmallBitVector CalleeSaves = |
433 getRegisterSet(RegSet_CalleeSave, RegSet_None); | 427 getRegisterSet(RegSet_CalleeSave, RegSet_None); |
434 RegsUsed = llvm::SmallBitVector(CalleeSaves.size()); | 428 RegsUsed = llvm::SmallBitVector(CalleeSaves.size()); |
435 VarList SortedSpilledVariables, VariablesLinkedToSpillSlots; | 429 VarList SortedSpilledVariables, VariablesLinkedToSpillSlots; |
436 size_t GlobalsSize = 0; | 430 size_t GlobalsSize = 0; |
437 // If there is a separate locals area, this represents that area. | 431 // If there is a separate locals area, this represents that area. Otherwise |
438 // Otherwise it counts any variable not counted by GlobalsSize. | 432 // it counts any variable not counted by GlobalsSize. |
439 SpillAreaSizeBytes = 0; | 433 SpillAreaSizeBytes = 0; |
440 // If there is a separate locals area, this specifies the alignment | 434 // If there is a separate locals area, this specifies the alignment for it. |
441 // for it. | |
442 uint32_t LocalsSlotsAlignmentBytes = 0; | 435 uint32_t LocalsSlotsAlignmentBytes = 0; |
443 // The entire spill locations area gets aligned to largest natural | 436 // The entire spill locations area gets aligned to largest natural alignment |
444 // alignment of the variables that have a spill slot. | 437 // of the variables that have a spill slot. |
445 uint32_t SpillAreaAlignmentBytes = 0; | 438 uint32_t SpillAreaAlignmentBytes = 0; |
446 // A spill slot linked to a variable with a stack slot should reuse | 439 // A spill slot linked to a variable with a stack slot should reuse that |
447 // that stack slot. | 440 // stack slot. |
448 std::function<bool(Variable *)> TargetVarHook = | 441 std::function<bool(Variable *)> TargetVarHook = |
449 [&VariablesLinkedToSpillSlots](Variable *Var) { | 442 [&VariablesLinkedToSpillSlots](Variable *Var) { |
450 if (auto *SpillVar = | 443 if (auto *SpillVar = |
451 llvm::dyn_cast<typename Traits::SpillVariable>(Var)) { | 444 llvm::dyn_cast<typename Traits::SpillVariable>(Var)) { |
452 assert(Var->mustNotHaveReg()); | 445 assert(Var->mustNotHaveReg()); |
453 if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) { | 446 if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) { |
454 VariablesLinkedToSpillSlots.push_back(Var); | 447 VariablesLinkedToSpillSlots.push_back(Var); |
455 return true; | 448 return true; |
456 } | 449 } |
457 } | 450 } |
(...skipping 21 matching lines...) Expand all Loading... |
479 | 472 |
480 // Generate "push ebp; mov ebp, esp" | 473 // Generate "push ebp; mov ebp, esp" |
481 if (IsEbpBasedFrame) { | 474 if (IsEbpBasedFrame) { |
482 assert((RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None)) | 475 assert((RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None)) |
483 .count() == 0); | 476 .count() == 0); |
484 PreservedRegsSizeBytes += typeWidthInBytes(IceType_i64); | 477 PreservedRegsSizeBytes += typeWidthInBytes(IceType_i64); |
485 Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp); | 478 Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp); |
486 Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); | 479 Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
487 _push(ebp); | 480 _push(ebp); |
488 _mov(ebp, esp); | 481 _mov(ebp, esp); |
489 // Keep ebp live for late-stage liveness analysis | 482 // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode). |
490 // (e.g. asm-verbose mode). | |
491 Context.insert(InstFakeUse::create(Func, ebp)); | 483 Context.insert(InstFakeUse::create(Func, ebp)); |
492 } | 484 } |
493 | 485 |
494 // Align the variables area. SpillAreaPaddingBytes is the size of | 486 // Align the variables area. SpillAreaPaddingBytes is the size of the region |
495 // the region after the preserved registers and before the spill areas. | 487 // after the preserved registers and before the spill areas. |
496 // LocalsSlotsPaddingBytes is the amount of padding between the globals | 488 // LocalsSlotsPaddingBytes is the amount of padding between the globals and |
497 // and locals area if they are separate. | 489 // locals area if they are separate. |
498 assert(SpillAreaAlignmentBytes <= Traits::X86_STACK_ALIGNMENT_BYTES); | 490 assert(SpillAreaAlignmentBytes <= Traits::X86_STACK_ALIGNMENT_BYTES); |
499 assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes); | 491 assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes); |
500 uint32_t SpillAreaPaddingBytes = 0; | 492 uint32_t SpillAreaPaddingBytes = 0; |
501 uint32_t LocalsSlotsPaddingBytes = 0; | 493 uint32_t LocalsSlotsPaddingBytes = 0; |
502 alignStackSpillAreas(Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes, | 494 alignStackSpillAreas(Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes, |
503 SpillAreaAlignmentBytes, GlobalsSize, | 495 SpillAreaAlignmentBytes, GlobalsSize, |
504 LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes, | 496 LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes, |
505 &LocalsSlotsPaddingBytes); | 497 &LocalsSlotsPaddingBytes); |
506 SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes; | 498 SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes; |
507 uint32_t GlobalsAndSubsequentPaddingSize = | 499 uint32_t GlobalsAndSubsequentPaddingSize = |
508 GlobalsSize + LocalsSlotsPaddingBytes; | 500 GlobalsSize + LocalsSlotsPaddingBytes; |
509 | 501 |
510 // Align esp if necessary. | 502 // Align esp if necessary. |
511 if (NeedsStackAlignment) { | 503 if (NeedsStackAlignment) { |
512 uint32_t StackOffset = | 504 uint32_t StackOffset = |
513 Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes; | 505 Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes; |
514 uint32_t StackSize = | 506 uint32_t StackSize = |
515 Traits::applyStackAlignment(StackOffset + SpillAreaSizeBytes); | 507 Traits::applyStackAlignment(StackOffset + SpillAreaSizeBytes); |
516 SpillAreaSizeBytes = StackSize - StackOffset; | 508 SpillAreaSizeBytes = StackSize - StackOffset; |
517 } | 509 } |
518 | 510 |
519 // Generate "sub esp, SpillAreaSizeBytes" | 511 // Generate "sub esp, SpillAreaSizeBytes" |
520 if (SpillAreaSizeBytes) | 512 if (SpillAreaSizeBytes) |
521 _sub(getPhysicalRegister(Traits::RegisterSet::Reg_esp), | 513 _sub(getPhysicalRegister(Traits::RegisterSet::Reg_esp), |
522 Ctx->getConstantInt32(SpillAreaSizeBytes)); | 514 Ctx->getConstantInt32(SpillAreaSizeBytes)); |
523 Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes); | 515 Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes); |
524 | 516 |
525 resetStackAdjustment(); | 517 resetStackAdjustment(); |
526 | 518 |
527 // Fill in stack offsets for stack args, and copy args into registers | 519 // Fill in stack offsets for stack args, and copy args into registers for |
528 // for those that were register-allocated. Args are pushed right to | 520 // those that were register-allocated. Args are pushed right to left, so |
529 // left, so Arg[0] is closest to the stack/frame pointer. | 521 // Arg[0] is closest to the stack/frame pointer. |
530 Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg()); | 522 Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg()); |
531 size_t BasicFrameOffset = | 523 size_t BasicFrameOffset = |
532 PreservedRegsSizeBytes + Traits::X86_RET_IP_SIZE_BYTES; | 524 PreservedRegsSizeBytes + Traits::X86_RET_IP_SIZE_BYTES; |
533 if (!IsEbpBasedFrame) | 525 if (!IsEbpBasedFrame) |
534 BasicFrameOffset += SpillAreaSizeBytes; | 526 BasicFrameOffset += SpillAreaSizeBytes; |
535 | 527 |
536 const VarList &Args = Func->getArgs(); | 528 const VarList &Args = Func->getArgs(); |
537 size_t InArgsSizeBytes = 0; | 529 size_t InArgsSizeBytes = 0; |
538 unsigned NumXmmArgs = 0; | 530 unsigned NumXmmArgs = 0; |
539 unsigned NumGPRArgs = 0; | 531 unsigned NumGPRArgs = 0; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 void TargetX8664::addEpilog(CfgNode *Node) { | 590 void TargetX8664::addEpilog(CfgNode *Node) { |
599 InstList &Insts = Node->getInsts(); | 591 InstList &Insts = Node->getInsts(); |
600 InstList::reverse_iterator RI, E; | 592 InstList::reverse_iterator RI, E; |
601 for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) { | 593 for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) { |
602 if (llvm::isa<typename Traits::Insts::Ret>(*RI)) | 594 if (llvm::isa<typename Traits::Insts::Ret>(*RI)) |
603 break; | 595 break; |
604 } | 596 } |
605 if (RI == E) | 597 if (RI == E) |
606 return; | 598 return; |
607 | 599 |
608 // Convert the reverse_iterator position into its corresponding | 600 // Convert the reverse_iterator position into its corresponding (forward) |
609 // (forward) iterator position. | 601 // iterator position. |
610 InstList::iterator InsertPoint = RI.base(); | 602 InstList::iterator InsertPoint = RI.base(); |
611 --InsertPoint; | 603 --InsertPoint; |
612 Context.init(Node); | 604 Context.init(Node); |
613 Context.setInsertPoint(InsertPoint); | 605 Context.setInsertPoint(InsertPoint); |
614 | 606 |
615 Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); | 607 Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
616 if (IsEbpBasedFrame) { | 608 if (IsEbpBasedFrame) { |
617 Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp); | 609 Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp); |
618 // For late-stage liveness analysis (e.g. asm-verbose mode), | 610 // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake |
619 // adding a fake use of esp before the assignment of esp=ebp keeps | 611 // use of esp before the assignment of esp=ebp keeps previous esp |
620 // previous esp adjustments from being dead-code eliminated. | 612 // adjustments from being dead-code eliminated. |
621 Context.insert(InstFakeUse::create(Func, esp)); | 613 Context.insert(InstFakeUse::create(Func, esp)); |
622 _mov(esp, ebp); | 614 _mov(esp, ebp); |
623 _pop(ebp); | 615 _pop(ebp); |
624 } else { | 616 } else { |
625 // add esp, SpillAreaSizeBytes | 617 // add esp, SpillAreaSizeBytes |
626 if (SpillAreaSizeBytes) | 618 if (SpillAreaSizeBytes) |
627 _add(esp, Ctx->getConstantInt32(SpillAreaSizeBytes)); | 619 _add(esp, Ctx->getConstantInt32(SpillAreaSizeBytes)); |
628 } | 620 } |
629 | 621 |
630 // Add pop instructions for preserved registers. | 622 // Add pop instructions for preserved registers. |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
751 RPE_PooledConstantReordering, K); | 743 RPE_PooledConstantReordering, K); |
752 RandomShuffle(Pool.begin(), Pool.end(), | 744 RandomShuffle(Pool.begin(), Pool.end(), |
753 [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); }); | 745 [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); }); |
754 } | 746 } |
755 | 747 |
756 for (Constant *C : Pool) { | 748 for (Constant *C : Pool) { |
757 if (!C->getShouldBePooled()) | 749 if (!C->getShouldBePooled()) |
758 continue; | 750 continue; |
759 typename T::IceType *Const = llvm::cast<typename T::IceType>(C); | 751 typename T::IceType *Const = llvm::cast<typename T::IceType>(C); |
760 typename T::IceType::PrimType Value = Const->getValue(); | 752 typename T::IceType::PrimType Value = Const->getValue(); |
761 // Use memcpy() to copy bits from Value into RawValue in a way | 753 // Use memcpy() to copy bits from Value into RawValue in a way that avoids |
762 // that avoids breaking strict-aliasing rules. | 754 // breaking strict-aliasing rules. |
763 typename T::PrimitiveIntType RawValue; | 755 typename T::PrimitiveIntType RawValue; |
764 memcpy(&RawValue, &Value, sizeof(Value)); | 756 memcpy(&RawValue, &Value, sizeof(Value)); |
765 char buf[30]; | 757 char buf[30]; |
766 int CharsPrinted = | 758 int CharsPrinted = |
767 snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); | 759 snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); |
768 assert(CharsPrinted >= 0 && | 760 assert(CharsPrinted >= 0 && |
769 (size_t)CharsPrinted < llvm::array_lengthof(buf)); | 761 (size_t)CharsPrinted < llvm::array_lengthof(buf)); |
770 (void)CharsPrinted; // avoid warnings if asserts are disabled | 762 (void)CharsPrinted; // avoid warnings if asserts are disabled |
771 Const->emitPoolLabel(Str); | 763 Const->emitPoolLabel(Str); |
772 Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " " | 764 Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " " |
773 << Value << "\n"; | 765 << Value << "\n"; |
774 } | 766 } |
775 } | 767 } |
776 | 768 |
777 void TargetDataX8664::lowerConstants() { | 769 void TargetDataX8664::lowerConstants() { |
778 if (Ctx->getFlags().getDisableTranslation()) | 770 if (Ctx->getFlags().getDisableTranslation()) |
779 return; | 771 return; |
780 // No need to emit constants from the int pool since (for x86) they | 772 // No need to emit constants from the int pool since (for x86) they are |
781 // are embedded as immediates in the instructions, just emit float/double. | 773 // embedded as immediates in the instructions, just emit float/double. |
782 switch (Ctx->getFlags().getOutFileType()) { | 774 switch (Ctx->getFlags().getOutFileType()) { |
783 case FT_Elf: { | 775 case FT_Elf: { |
784 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | 776 ELFObjectWriter *Writer = Ctx->getObjectWriter(); |
785 | 777 |
786 Writer->writeConstantPool<ConstantInteger32>(IceType_i8); | 778 Writer->writeConstantPool<ConstantInteger32>(IceType_i8); |
787 Writer->writeConstantPool<ConstantInteger32>(IceType_i16); | 779 Writer->writeConstantPool<ConstantInteger32>(IceType_i16); |
788 Writer->writeConstantPool<ConstantInteger32>(IceType_i32); | 780 Writer->writeConstantPool<ConstantInteger32>(IceType_i32); |
789 | 781 |
790 Writer->writeConstantPool<ConstantFloat>(IceType_f32); | 782 Writer->writeConstantPool<ConstantFloat>(IceType_f32); |
791 Writer->writeConstantPool<ConstantDouble>(IceType_f64); | 783 Writer->writeConstantPool<ConstantDouble>(IceType_f64); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
847 OstreamLocker L(Ctx); | 839 OstreamLocker L(Ctx); |
848 for (const VariableDeclaration *Var : Vars) { | 840 for (const VariableDeclaration *Var : Vars) { |
849 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { | 841 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { |
850 emitGlobal(*Var, SectionSuffix); | 842 emitGlobal(*Var, SectionSuffix); |
851 } | 843 } |
852 } | 844 } |
853 } break; | 845 } break; |
854 } | 846 } |
855 } | 847 } |
856 | 848 |
857 // In some cases, there are x-macros tables for both high-level and | 849 // In some cases, there are x-macros tables for both high-level and low-level |
858 // low-level instructions/operands that use the same enum key value. | 850 // instructions/operands that use the same enum key value. The tables are kept |
859 // The tables are kept separate to maintain a proper separation | 851 // separate to maintain a proper separation between abstraction layers. There |
860 // between abstraction layers. There is a risk that the tables could | 852 // is a risk that the tables could get out of sync if enum values are reordered |
861 // get out of sync if enum values are reordered or if entries are | 853 // or if entries are added or deleted. The following dummy namespaces use |
862 // added or deleted. The following dummy namespaces use | |
863 // static_asserts to ensure everything is kept in sync. | 854 // static_asserts to ensure everything is kept in sync. |
864 | 855 |
865 namespace { | 856 namespace { |
866 // Validate the enum values in FCMPX8664_TABLE. | 857 // Validate the enum values in FCMPX8664_TABLE. |
867 namespace dummy1 { | 858 namespace dummy1 { |
868 // Define a temporary set of enum values based on low-level table | 859 // Define a temporary set of enum values based on low-level table entries. |
869 // entries. | |
870 enum _tmp_enum { | 860 enum _tmp_enum { |
871 #define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val, | 861 #define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val, |
872 FCMPX8664_TABLE | 862 FCMPX8664_TABLE |
873 #undef X | 863 #undef X |
874 _num | 864 _num |
875 }; | 865 }; |
876 // Define a set of constants based on high-level table entries. | 866 // Define a set of constants based on high-level table entries. |
877 #define X(tag, str) static const int _table1_##tag = InstFcmp::tag; | 867 #define X(tag, str) static const int _table1_##tag = InstFcmp::tag; |
878 ICEINSTFCMP_TABLE | 868 ICEINSTFCMP_TABLE |
879 #undef X | 869 #undef X |
880 // Define a set of constants based on low-level table entries, and | 870 // Define a set of constants based on low-level table entries, and ensure the |
881 // ensure the table entry keys are consistent. | 871 // table entry keys are consistent. |
882 #define X(val, dflt, swapS, C1, C2, swapV, pred) \ | 872 #define X(val, dflt, swapS, C1, C2, swapV, pred) \ |
883 static const int _table2_##val = _tmp_##val; \ | 873 static const int _table2_##val = _tmp_##val; \ |
884 static_assert( \ | 874 static_assert( \ |
885 _table1_##val == _table2_##val, \ | 875 _table1_##val == _table2_##val, \ |
886 "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); | 876 "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); |
887 FCMPX8664_TABLE | 877 FCMPX8664_TABLE |
888 #undef X | 878 #undef X |
889 // Repeat the static asserts with respect to the high-level table | 879 // Repeat the static asserts with respect to the high-level table entries in |
890 // entries in case the high-level table has extra entries. | 880 // case the high-level table has extra entries. |
891 #define X(tag, str) \ | 881 #define X(tag, str) \ |
892 static_assert( \ | 882 static_assert( \ |
893 _table1_##tag == _table2_##tag, \ | 883 _table1_##tag == _table2_##tag, \ |
894 "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); | 884 "Inconsistency between FCMPX8664_TABLE and ICEINSTFCMP_TABLE"); |
895 ICEINSTFCMP_TABLE | 885 ICEINSTFCMP_TABLE |
896 #undef X | 886 #undef X |
897 } // end of namespace dummy1 | 887 } // end of namespace dummy1 |
898 | 888 |
899 // Validate the enum values in ICMPX8664_TABLE. | 889 // Validate the enum values in ICMPX8664_TABLE. |
900 namespace dummy2 { | 890 namespace dummy2 { |
901 // Define a temporary set of enum values based on low-level table | 891 // Define a temporary set of enum values based on low-level table entries. |
902 // entries. | |
903 enum _tmp_enum { | 892 enum _tmp_enum { |
904 #define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val, | 893 #define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val, |
905 ICMPX8664_TABLE | 894 ICMPX8664_TABLE |
906 #undef X | 895 #undef X |
907 _num | 896 _num |
908 }; | 897 }; |
909 // Define a set of constants based on high-level table entries. | 898 // Define a set of constants based on high-level table entries. |
910 #define X(tag, str) static const int _table1_##tag = InstIcmp::tag; | 899 #define X(tag, str) static const int _table1_##tag = InstIcmp::tag; |
911 ICEINSTICMP_TABLE | 900 ICEINSTICMP_TABLE |
912 #undef X | 901 #undef X |
913 // Define a set of constants based on low-level table entries, and | 902 // Define a set of constants based on low-level table entries, and ensure the |
914 // ensure the table entry keys are consistent. | 903 // table entry keys are consistent. |
915 #define X(val, C_32, C1_64, C2_64, C3_64) \ | 904 #define X(val, C_32, C1_64, C2_64, C3_64) \ |
916 static const int _table2_##val = _tmp_##val; \ | 905 static const int _table2_##val = _tmp_##val; \ |
917 static_assert( \ | 906 static_assert( \ |
918 _table1_##val == _table2_##val, \ | 907 _table1_##val == _table2_##val, \ |
919 "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); | 908 "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); |
920 ICMPX8664_TABLE | 909 ICMPX8664_TABLE |
921 #undef X | 910 #undef X |
922 // Repeat the static asserts with respect to the high-level table | 911 // Repeat the static asserts with respect to the high-level table entries in |
923 // entries in case the high-level table has extra entries. | 912 // case the high-level table has extra entries. |
924 #define X(tag, str) \ | 913 #define X(tag, str) \ |
925 static_assert( \ | 914 static_assert( \ |
926 _table1_##tag == _table2_##tag, \ | 915 _table1_##tag == _table2_##tag, \ |
927 "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); | 916 "Inconsistency between ICMPX8664_TABLE and ICEINSTICMP_TABLE"); |
928 ICEINSTICMP_TABLE | 917 ICEINSTICMP_TABLE |
929 #undef X | 918 #undef X |
930 } // end of namespace dummy2 | 919 } // end of namespace dummy2 |
931 | 920 |
932 // Validate the enum values in ICETYPEX8664_TABLE. | 921 // Validate the enum values in ICETYPEX8664_TABLE. |
933 namespace dummy3 { | 922 namespace dummy3 { |
934 // Define a temporary set of enum values based on low-level table | 923 // Define a temporary set of enum values based on low-level table entries. |
935 // entries. | |
936 enum _tmp_enum { | 924 enum _tmp_enum { |
937 #define X(tag, elementty, cvt, sdss, pack, width, fld) _tmp_##tag, | 925 #define X(tag, elementty, cvt, sdss, pack, width, fld) _tmp_##tag, |
938 ICETYPEX8664_TABLE | 926 ICETYPEX8664_TABLE |
939 #undef X | 927 #undef X |
940 _num | 928 _num |
941 }; | 929 }; |
942 // Define a set of constants based on high-level table entries. | 930 // Define a set of constants based on high-level table entries. |
943 #define X(tag, sizeLog2, align, elts, elty, str) \ | 931 #define X(tag, sizeLog2, align, elts, elty, str) \ |
944 static const int _table1_##tag = tag; | 932 static const int _table1_##tag = tag; |
945 ICETYPE_TABLE | 933 ICETYPE_TABLE |
946 #undef X | 934 #undef X |
947 // Define a set of constants based on low-level table entries, and | 935 // Define a set of constants based on low-level table entries, and ensure the |
948 // ensure the table entry keys are consistent. | 936 // table entry keys are consistent. |
949 #define X(tag, elementty, cvt, sdss, pack, width, fld) \ | 937 #define X(tag, elementty, cvt, sdss, pack, width, fld) \ |
950 static const int _table2_##tag = _tmp_##tag; \ | 938 static const int _table2_##tag = _tmp_##tag; \ |
951 static_assert(_table1_##tag == _table2_##tag, \ | 939 static_assert(_table1_##tag == _table2_##tag, \ |
952 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); | 940 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); |
953 ICETYPEX8664_TABLE | 941 ICETYPEX8664_TABLE |
954 #undef X | 942 #undef X |
955 // Repeat the static asserts with respect to the high-level table | 943 // Repeat the static asserts with respect to the high-level table entries in |
956 // entries in case the high-level table has extra entries. | 944 // case the high-level table has extra entries. |
957 #define X(tag, sizeLog2, align, elts, elty, str) \ | 945 #define X(tag, sizeLog2, align, elts, elty, str) \ |
958 static_assert(_table1_##tag == _table2_##tag, \ | 946 static_assert(_table1_##tag == _table2_##tag, \ |
959 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); | 947 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); |
960 ICETYPE_TABLE | 948 ICETYPE_TABLE |
961 #undef X | 949 #undef X |
962 } // end of namespace dummy3 | 950 } // end of namespace dummy3 |
963 } // end of anonymous namespace | 951 } // end of anonymous namespace |
964 | 952 |
965 } // end of namespace Ice | 953 } // end of namespace Ice |
OLD | NEW |