| 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 |