| OLD | NEW |
| 1 //===- subzero/src/IceTargetLoweringX8632.cpp - x86-32 lowering -----------===// | 1 //===- subzero/src/IceTargetLoweringX8632.cpp - x86-32 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 /// \brief Implements the TargetLoweringX8632 class, which consists almost | 11 /// \brief Implements the TargetLoweringX8632 class, which consists almost |
| 12 /// entirely of the lowering sequence for each high-level instruction. | 12 /// entirely of the lowering sequence for each high-level instruction. |
| 13 /// | 13 /// |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #include "IceTargetLoweringX8632.h" | 16 #include "IceTargetLoweringX8632.h" |
| 17 | 17 |
| 18 #include "IceTargetLoweringX8632Traits.h" | 18 #include "IceTargetLoweringX8632Traits.h" |
| 19 | 19 |
| 20 namespace X8632 { | 20 namespace X8632 { |
| 21 std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { | 21 std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { |
| 22 return ::Ice::X8632::TargetX8632::create(Func); | 22 return ::Ice::X8632::TargetX8632::create(Func); |
| 23 } | 23 } |
| 24 | 24 |
| 25 std::unique_ptr<::Ice::TargetDataLowering> | 25 std::unique_ptr<::Ice::TargetDataLowering> |
| 26 createTargetDataLowering(::Ice::GlobalContext *Ctx) { | 26 createTargetDataLowering(::Ice::GlobalContext *Ctx) { |
| 27 return ::Ice::X8632::TargetDataX8632::create(Ctx); | 27 return ::Ice::X8632::TargetDataX86<::Ice::X8632::TargetX8632Traits>::create( |
| 28 Ctx); |
| 28 } | 29 } |
| 29 | 30 |
| 30 std::unique_ptr<::Ice::TargetHeaderLowering> | 31 std::unique_ptr<::Ice::TargetHeaderLowering> |
| 31 createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { | 32 createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { |
| 32 return ::Ice::X8632::TargetHeaderX8632::create(Ctx); | 33 return ::Ice::X8632::TargetHeaderX86::create(Ctx); |
| 33 } | 34 } |
| 34 | 35 |
| 35 void staticInit(::Ice::GlobalContext *Ctx) { | 36 void staticInit(::Ice::GlobalContext *Ctx) { |
| 36 ::Ice::X8632::TargetX8632::staticInit(Ctx); | 37 ::Ice::X8632::TargetX8632::staticInit(Ctx); |
| 37 } | 38 } |
| 38 } // end of namespace X8632 | 39 } // end of namespace X8632 |
| 39 | 40 |
| 40 namespace Ice { | 41 namespace Ice { |
| 41 namespace X8632 { | 42 namespace X8632 { |
| 42 | 43 |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 // bundle_lock | 263 // bundle_lock |
| 263 // and t, ~31 | 264 // and t, ~31 |
| 264 // jmp *t | 265 // jmp *t |
| 265 // bundle_unlock | 266 // bundle_unlock |
| 266 // FakeUse <original_ret_operand> | 267 // FakeUse <original_ret_operand> |
| 267 Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx); | 268 Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx); |
| 268 _pop(T_ecx); | 269 _pop(T_ecx); |
| 269 lowerIndirectJump(T_ecx); | 270 lowerIndirectJump(T_ecx); |
| 270 } | 271 } |
| 271 | 272 |
| 272 void TargetX8632::emitJumpTable(const Cfg *Func, | |
| 273 const InstJumpTable *JumpTable) const { | |
| 274 if (!BuildDefs::dump()) | |
| 275 return; | |
| 276 Ostream &Str = Ctx->getStrEmit(); | |
| 277 const bool UseNonsfi = Ctx->getFlags().getUseNonsfi(); | |
| 278 const IceString MangledName = Ctx->mangleName(Func->getFunctionName()); | |
| 279 const IceString Prefix = UseNonsfi ? ".data.rel.ro." : ".rodata."; | |
| 280 Str << "\t.section\t" << Prefix << MangledName | |
| 281 << "$jumptable,\"a\",@progbits\n"; | |
| 282 Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"; | |
| 283 Str << InstJumpTable::makeName(MangledName, JumpTable->getId()) << ":"; | |
| 284 | |
| 285 // On X8632 pointers are 32-bit hence the use of .long | |
| 286 for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I) | |
| 287 Str << "\n\t.long\t" << JumpTable->getTarget(I)->getAsmName(); | |
| 288 Str << "\n"; | |
| 289 } | |
| 290 | |
| 291 TargetDataX8632::TargetDataX8632(GlobalContext *Ctx) | |
| 292 : TargetDataLowering(Ctx) {} | |
| 293 | |
| 294 namespace { | |
| 295 template <typename T> struct PoolTypeConverter {}; | |
| 296 | |
| 297 template <> struct PoolTypeConverter<float> { | |
| 298 using PrimitiveIntType = uint32_t; | |
| 299 using IceType = ConstantFloat; | |
| 300 static const Type Ty = IceType_f32; | |
| 301 static const char *TypeName; | |
| 302 static const char *AsmTag; | |
| 303 static const char *PrintfString; | |
| 304 }; | |
| 305 const char *PoolTypeConverter<float>::TypeName = "float"; | |
| 306 const char *PoolTypeConverter<float>::AsmTag = ".long"; | |
| 307 const char *PoolTypeConverter<float>::PrintfString = "0x%x"; | |
| 308 | |
| 309 template <> struct PoolTypeConverter<double> { | |
| 310 using PrimitiveIntType = uint64_t; | |
| 311 using IceType = ConstantDouble; | |
| 312 static const Type Ty = IceType_f64; | |
| 313 static const char *TypeName; | |
| 314 static const char *AsmTag; | |
| 315 static const char *PrintfString; | |
| 316 }; | |
| 317 const char *PoolTypeConverter<double>::TypeName = "double"; | |
| 318 const char *PoolTypeConverter<double>::AsmTag = ".quad"; | |
| 319 const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; | |
| 320 | |
| 321 // Add converter for int type constant pooling | |
| 322 template <> struct PoolTypeConverter<uint32_t> { | |
| 323 using PrimitiveIntType = uint32_t; | |
| 324 using IceType = ConstantInteger32; | |
| 325 static const Type Ty = IceType_i32; | |
| 326 static const char *TypeName; | |
| 327 static const char *AsmTag; | |
| 328 static const char *PrintfString; | |
| 329 }; | |
| 330 const char *PoolTypeConverter<uint32_t>::TypeName = "i32"; | |
| 331 const char *PoolTypeConverter<uint32_t>::AsmTag = ".long"; | |
| 332 const char *PoolTypeConverter<uint32_t>::PrintfString = "0x%x"; | |
| 333 | |
| 334 // Add converter for int type constant pooling | |
| 335 template <> struct PoolTypeConverter<uint16_t> { | |
| 336 using PrimitiveIntType = uint32_t; | |
| 337 using IceType = ConstantInteger32; | |
| 338 static const Type Ty = IceType_i16; | |
| 339 static const char *TypeName; | |
| 340 static const char *AsmTag; | |
| 341 static const char *PrintfString; | |
| 342 }; | |
| 343 const char *PoolTypeConverter<uint16_t>::TypeName = "i16"; | |
| 344 const char *PoolTypeConverter<uint16_t>::AsmTag = ".short"; | |
| 345 const char *PoolTypeConverter<uint16_t>::PrintfString = "0x%x"; | |
| 346 | |
| 347 // Add converter for int type constant pooling | |
| 348 template <> struct PoolTypeConverter<uint8_t> { | |
| 349 using PrimitiveIntType = uint32_t; | |
| 350 using IceType = ConstantInteger32; | |
| 351 static const Type Ty = IceType_i8; | |
| 352 static const char *TypeName; | |
| 353 static const char *AsmTag; | |
| 354 static const char *PrintfString; | |
| 355 }; | |
| 356 const char *PoolTypeConverter<uint8_t>::TypeName = "i8"; | |
| 357 const char *PoolTypeConverter<uint8_t>::AsmTag = ".byte"; | |
| 358 const char *PoolTypeConverter<uint8_t>::PrintfString = "0x%x"; | |
| 359 } // end of anonymous namespace | |
| 360 | |
| 361 template <typename T> | |
| 362 void TargetDataX8632::emitConstantPool(GlobalContext *Ctx) { | |
| 363 if (!BuildDefs::dump()) | |
| 364 return; | |
| 365 Ostream &Str = Ctx->getStrEmit(); | |
| 366 Type Ty = T::Ty; | |
| 367 SizeT Align = typeAlignInBytes(Ty); | |
| 368 ConstantList Pool = Ctx->getConstantPool(Ty); | |
| 369 | |
| 370 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align | |
| 371 << "\n"; | |
| 372 Str << "\t.align\t" << Align << "\n"; | |
| 373 | |
| 374 // If reorder-pooled-constants option is set to true, we need to shuffle the | |
| 375 // constant pool before emitting it. | |
| 376 if (Ctx->getFlags().shouldReorderPooledConstants() && !Pool.empty()) { | |
| 377 // Use the constant's kind value as the salt for creating random number | |
| 378 // generator. | |
| 379 Operand::OperandKind K = (*Pool.begin())->getKind(); | |
| 380 | |
| 381 RandomNumberGenerator RNG(Ctx->getFlags().getRandomSeed(), | |
| 382 RPE_PooledConstantReordering, K); | |
| 383 RandomShuffle(Pool.begin(), Pool.end(), | |
| 384 [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); }); | |
| 385 } | |
| 386 | |
| 387 for (Constant *C : Pool) { | |
| 388 if (!C->getShouldBePooled()) | |
| 389 continue; | |
| 390 auto *Const = llvm::cast<typename T::IceType>(C); | |
| 391 typename T::IceType::PrimType Value = Const->getValue(); | |
| 392 // Use memcpy() to copy bits from Value into RawValue in a way that avoids | |
| 393 // breaking strict-aliasing rules. | |
| 394 typename T::PrimitiveIntType RawValue; | |
| 395 memcpy(&RawValue, &Value, sizeof(Value)); | |
| 396 char buf[30]; | |
| 397 int CharsPrinted = | |
| 398 snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue); | |
| 399 assert(CharsPrinted >= 0 && | |
| 400 (size_t)CharsPrinted < llvm::array_lengthof(buf)); | |
| 401 (void)CharsPrinted; // avoid warnings if asserts are disabled | |
| 402 Const->emitPoolLabel(Str, Ctx); | |
| 403 Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " " | |
| 404 << Value << " */\n"; | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 void TargetDataX8632::lowerConstants() { | |
| 409 if (Ctx->getFlags().getDisableTranslation()) | |
| 410 return; | |
| 411 // No need to emit constants from the int pool since (for x86) they are | |
| 412 // embedded as immediates in the instructions, just emit float/double. | |
| 413 switch (Ctx->getFlags().getOutFileType()) { | |
| 414 case FT_Elf: { | |
| 415 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
| 416 | |
| 417 Writer->writeConstantPool<ConstantInteger32>(IceType_i8); | |
| 418 Writer->writeConstantPool<ConstantInteger32>(IceType_i16); | |
| 419 Writer->writeConstantPool<ConstantInteger32>(IceType_i32); | |
| 420 | |
| 421 Writer->writeConstantPool<ConstantFloat>(IceType_f32); | |
| 422 Writer->writeConstantPool<ConstantDouble>(IceType_f64); | |
| 423 } break; | |
| 424 case FT_Asm: | |
| 425 case FT_Iasm: { | |
| 426 OstreamLocker L(Ctx); | |
| 427 | |
| 428 emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx); | |
| 429 emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx); | |
| 430 emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx); | |
| 431 | |
| 432 emitConstantPool<PoolTypeConverter<float>>(Ctx); | |
| 433 emitConstantPool<PoolTypeConverter<double>>(Ctx); | |
| 434 } break; | |
| 435 } | |
| 436 } | |
| 437 | |
| 438 void TargetDataX8632::lowerJumpTables() { | |
| 439 const bool IsPIC = Ctx->getFlags().getUseNonsfi(); | |
| 440 switch (Ctx->getFlags().getOutFileType()) { | |
| 441 case FT_Elf: { | |
| 442 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
| 443 for (const JumpTableData &JT : Ctx->getJumpTables()) | |
| 444 Writer->writeJumpTable(JT, TargetX8632::Traits::FK_Abs, IsPIC); | |
| 445 } break; | |
| 446 case FT_Asm: | |
| 447 // Already emitted from Cfg | |
| 448 break; | |
| 449 case FT_Iasm: { | |
| 450 if (!BuildDefs::dump()) | |
| 451 return; | |
| 452 Ostream &Str = Ctx->getStrEmit(); | |
| 453 const IceString Prefix = IsPIC ? ".data.rel.ro." : ".rodata."; | |
| 454 for (const JumpTableData &JT : Ctx->getJumpTables()) { | |
| 455 Str << "\t.section\t" << Prefix << JT.getFunctionName() | |
| 456 << "$jumptable,\"a\",@progbits\n"; | |
| 457 Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"; | |
| 458 Str << InstJumpTable::makeName(JT.getFunctionName(), JT.getId()) << ":"; | |
| 459 | |
| 460 // On X8632 pointers are 32-bit hence the use of .long | |
| 461 for (intptr_t TargetOffset : JT.getTargetOffsets()) | |
| 462 Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset; | |
| 463 Str << "\n"; | |
| 464 } | |
| 465 } break; | |
| 466 } | |
| 467 } | |
| 468 | |
| 469 void TargetDataX8632::lowerGlobals(const VariableDeclarationList &Vars, | |
| 470 const IceString &SectionSuffix) { | |
| 471 const bool IsPIC = Ctx->getFlags().getUseNonsfi(); | |
| 472 switch (Ctx->getFlags().getOutFileType()) { | |
| 473 case FT_Elf: { | |
| 474 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | |
| 475 Writer->writeDataSection(Vars, TargetX8632::Traits::FK_Abs, SectionSuffix, | |
| 476 IsPIC); | |
| 477 } break; | |
| 478 case FT_Asm: | |
| 479 case FT_Iasm: { | |
| 480 const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); | |
| 481 OstreamLocker L(Ctx); | |
| 482 for (const VariableDeclaration *Var : Vars) { | |
| 483 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { | |
| 484 emitGlobal(*Var, SectionSuffix); | |
| 485 } | |
| 486 } | |
| 487 } break; | |
| 488 } | |
| 489 } | |
| 490 | |
| 491 TargetHeaderX8632::TargetHeaderX8632(GlobalContext *Ctx) | |
| 492 : TargetHeaderLowering(Ctx) {} | |
| 493 | |
| 494 // In some cases, there are x-macros tables for both high-level and low-level | 273 // In some cases, there are x-macros tables for both high-level and low-level |
| 495 // instructions/operands that use the same enum key value. The tables are kept | 274 // instructions/operands that use the same enum key value. The tables are kept |
| 496 // separate to maintain a proper separation between abstraction layers. There | 275 // separate to maintain a proper separation between abstraction layers. There |
| 497 // is a risk that the tables could get out of sync if enum values are reordered | 276 // is a risk that the tables could get out of sync if enum values are reordered |
| 498 // or if entries are added or deleted. The following dummy namespaces use | 277 // or if entries are added or deleted. The following dummy namespaces use |
| 499 // static_asserts to ensure everything is kept in sync. | 278 // static_asserts to ensure everything is kept in sync. |
| 500 | 279 |
| 501 namespace { | 280 namespace { |
| 502 // Validate the enum values in FCMPX8632_TABLE. | 281 // Validate the enum values in FCMPX8632_TABLE. |
| 503 namespace dummy1 { | 282 namespace dummy1 { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 #define X(tag, sizeLog2, align, elts, elty, str) \ | 369 #define X(tag, sizeLog2, align, elts, elty, str) \ |
| 591 static_assert(_table1_##tag == _table2_##tag, \ | 370 static_assert(_table1_##tag == _table2_##tag, \ |
| 592 "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE"); | 371 "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE"); |
| 593 ICETYPE_TABLE | 372 ICETYPE_TABLE |
| 594 #undef X | 373 #undef X |
| 595 } // end of namespace dummy3 | 374 } // end of namespace dummy3 |
| 596 } // end of anonymous namespace | 375 } // end of anonymous namespace |
| 597 | 376 |
| 598 } // end of namespace X8632 | 377 } // end of namespace X8632 |
| 599 } // end of namespace Ice | 378 } // end of namespace Ice |
| OLD | NEW |