| OLD | NEW |
| 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// | 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 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 // This file implements the TargetLoweringARM32 class, which consists almost | 10 // This file implements the TargetLoweringARM32 class, which consists almost |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 // Repeat the static asserts with respect to the high-level table | 113 // Repeat the static asserts with respect to the high-level table |
| 114 // entries in case the high-level table has extra entries. | 114 // entries in case the high-level table has extra entries. |
| 115 #define X(tag, str) \ | 115 #define X(tag, str) \ |
| 116 static_assert( \ | 116 static_assert( \ |
| 117 _table1_##tag == _table2_##tag, \ | 117 _table1_##tag == _table2_##tag, \ |
| 118 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE"); | 118 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE"); |
| 119 ICEINSTICMP_TABLE | 119 ICEINSTICMP_TABLE |
| 120 #undef X | 120 #undef X |
| 121 } // end of namespace dummy1 | 121 } // end of namespace dummy1 |
| 122 | 122 |
| 123 // The maximum number of arguments to pass in GPR registers. | |
| 124 const uint32_t ARM32_MAX_GPR_ARG = 4; | |
| 125 | |
| 126 // Stack alignment | 123 // Stack alignment |
| 127 const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16; | 124 const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16; |
| 128 | 125 |
| 129 // Value is in bytes. Return Value adjusted to the next highest multiple | 126 // Value is in bytes. Return Value adjusted to the next highest multiple |
| 130 // of the stack alignment. | 127 // of the stack alignment. |
| 131 uint32_t applyStackAlignment(uint32_t Value) { | 128 uint32_t applyStackAlignment(uint32_t Value) { |
| 132 return Utils::applyAlignment(Value, ARM32_STACK_ALIGNMENT_BYTES); | 129 return Utils::applyAlignment(Value, ARM32_STACK_ALIGNMENT_BYTES); |
| 133 } | 130 } |
| 134 | 131 |
| 132 // Value is in bytes. Return Value adjusted to the next highest multiple |
| 133 // of the stack alignment required for the given type. |
| 134 uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) { |
| 135 // Use natural alignment, except that normally (non-NaCl) ARM only |
| 136 // aligns vectors to 8 bytes. |
| 137 // TODO(jvoung): Check this ... |
| 138 size_t typeAlignInBytes = typeWidthInBytes(Ty); |
| 139 if (isVectorType(Ty)) |
| 140 typeAlignInBytes = 8; |
| 141 return Utils::applyAlignment(Value, typeAlignInBytes); |
| 142 } |
| 143 |
| 135 } // end of anonymous namespace | 144 } // end of anonymous namespace |
| 136 | 145 |
| 137 TargetARM32::TargetARM32(Cfg *Func) | 146 TargetARM32::TargetARM32(Cfg *Func) |
| 138 : TargetLowering(Func), InstructionSet(ARM32InstructionSet::Begin), | 147 : TargetLowering(Func), InstructionSet(ARM32InstructionSet::Begin), |
| 139 UsesFramePointer(false), NeedsStackAlignment(false), MaybeLeafFunc(true), | 148 UsesFramePointer(false), NeedsStackAlignment(false), MaybeLeafFunc(true), |
| 140 SpillAreaSizeBytes(0) { | 149 SpillAreaSizeBytes(0) { |
| 141 static_assert( | 150 static_assert( |
| 142 (ARM32InstructionSet::End - ARM32InstructionSet::Begin) == | 151 (ARM32InstructionSet::End - ARM32InstructionSet::Begin) == |
| 143 (TargetInstructionSet::ARM32InstructionSet_End - | 152 (TargetInstructionSet::ARM32InstructionSet_End - |
| 144 TargetInstructionSet::ARM32InstructionSet_Begin), | 153 TargetInstructionSet::ARM32InstructionSet_Begin), |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 } | 379 } |
| 371 if (Var->getWeight().isInf()) { | 380 if (Var->getWeight().isInf()) { |
| 372 llvm::report_fatal_error( | 381 llvm::report_fatal_error( |
| 373 "Infinite-weight Variable has no register assigned"); | 382 "Infinite-weight Variable has no register assigned"); |
| 374 } | 383 } |
| 375 int32_t Offset = Var->getStackOffset(); | 384 int32_t Offset = Var->getStackOffset(); |
| 376 if (!hasFramePointer()) | 385 if (!hasFramePointer()) |
| 377 Offset += getStackAdjustment(); | 386 Offset += getStackAdjustment(); |
| 378 // TODO(jvoung): Handle out of range. Perhaps we need a scratch register | 387 // TODO(jvoung): Handle out of range. Perhaps we need a scratch register |
| 379 // to materialize a larger offset. | 388 // to materialize a larger offset. |
| 380 const bool SignExt = false; | 389 constexpr bool SignExt = false; |
| 381 if (!OperandARM32Mem::canHoldOffset(Var->getType(), SignExt, Offset)) { | 390 if (!OperandARM32Mem::canHoldOffset(Var->getType(), SignExt, Offset)) { |
| 382 llvm::report_fatal_error("Illegal stack offset"); | 391 llvm::report_fatal_error("Illegal stack offset"); |
| 383 } | 392 } |
| 384 const Type FrameSPTy = IceType_i32; | 393 const Type FrameSPTy = IceType_i32; |
| 385 Str << "[" << getRegName(getFrameOrStackReg(), FrameSPTy); | 394 Str << "[" << getRegName(getFrameOrStackReg(), FrameSPTy); |
| 386 if (Offset != 0) { | 395 if (Offset != 0) { |
| 387 Str << ", " << getConstantPrefix() << Offset; | 396 Str << ", " << getConstantPrefix() << Offset; |
| 388 } | 397 } |
| 389 Str << "]"; | 398 Str << "]"; |
| 390 } | 399 } |
| 391 | 400 |
| 401 bool TargetARM32::CallingConv::I64InRegs(std::pair<int32_t, int32_t> *Regs) { |
| 402 if (NumGPRRegsUsed >= ARM32_MAX_GPR_ARG) |
| 403 return false; |
| 404 int32_t RegLo, RegHi; |
| 405 // Always start i64 registers at an even register, so this may end |
| 406 // up padding away a register. |
| 407 if (NumGPRRegsUsed % 2 != 0) { |
| 408 ++NumGPRRegsUsed; |
| 409 } |
| 410 RegLo = RegARM32::Reg_r0 + NumGPRRegsUsed; |
| 411 ++NumGPRRegsUsed; |
| 412 RegHi = RegARM32::Reg_r0 + NumGPRRegsUsed; |
| 413 ++NumGPRRegsUsed; |
| 414 // If this bumps us past the boundary, don't allocate to a register |
| 415 // and leave any previously speculatively consumed registers as consumed. |
| 416 if (NumGPRRegsUsed > ARM32_MAX_GPR_ARG) |
| 417 return false; |
| 418 Regs->first = RegLo; |
| 419 Regs->second = RegHi; |
| 420 return true; |
| 421 } |
| 422 |
| 423 bool TargetARM32::CallingConv::I32InReg(int32_t *Reg) { |
| 424 if (NumGPRRegsUsed >= ARM32_MAX_GPR_ARG) |
| 425 return false; |
| 426 *Reg = RegARM32::Reg_r0 + NumGPRRegsUsed; |
| 427 ++NumGPRRegsUsed; |
| 428 return true; |
| 429 } |
| 430 |
| 392 void TargetARM32::lowerArguments() { | 431 void TargetARM32::lowerArguments() { |
| 393 VarList &Args = Func->getArgs(); | 432 VarList &Args = Func->getArgs(); |
| 394 // The first few integer type parameters can use r0-r3, regardless of their | 433 TargetARM32::CallingConv CC; |
| 395 // position relative to the floating-point/vector arguments in the argument | |
| 396 // list. Floating-point and vector arguments can use q0-q3 (aka d0-d7, | |
| 397 // s0-s15). | |
| 398 unsigned NumGPRRegsUsed = 0; | |
| 399 | 434 |
| 400 // For each register argument, replace Arg in the argument list with the | 435 // For each register argument, replace Arg in the argument list with the |
| 401 // home register. Then generate an instruction in the prolog to copy the | 436 // home register. Then generate an instruction in the prolog to copy the |
| 402 // home register to the assigned location of Arg. | 437 // home register to the assigned location of Arg. |
| 403 Context.init(Func->getEntryNode()); | 438 Context.init(Func->getEntryNode()); |
| 404 Context.setInsertPoint(Context.getCur()); | 439 Context.setInsertPoint(Context.getCur()); |
| 405 | 440 |
| 406 for (SizeT I = 0, E = Args.size(); I < E; ++I) { | 441 for (SizeT I = 0, E = Args.size(); I < E; ++I) { |
| 407 Variable *Arg = Args[I]; | 442 Variable *Arg = Args[I]; |
| 408 Type Ty = Arg->getType(); | 443 Type Ty = Arg->getType(); |
| 409 // TODO(jvoung): handle float/vector types. | 444 // TODO(jvoung): handle float/vector types. |
| 410 if (isVectorType(Ty)) { | 445 if (isVectorType(Ty)) { |
| 411 UnimplementedError(Func->getContext()->getFlags()); | 446 UnimplementedError(Func->getContext()->getFlags()); |
| 412 continue; | 447 continue; |
| 413 } else if (isFloatingType(Ty)) { | 448 } else if (isFloatingType(Ty)) { |
| 414 UnimplementedError(Func->getContext()->getFlags()); | 449 UnimplementedError(Func->getContext()->getFlags()); |
| 415 continue; | 450 continue; |
| 416 } else if (Ty == IceType_i64) { | 451 } else if (Ty == IceType_i64) { |
| 417 if (NumGPRRegsUsed >= ARM32_MAX_GPR_ARG) | 452 std::pair<int32_t, int32_t> RegPair; |
| 418 continue; | 453 if (!CC.I64InRegs(&RegPair)) |
| 419 int32_t RegLo; | |
| 420 int32_t RegHi; | |
| 421 // Always start i64 registers at an even register, so this may end | |
| 422 // up padding away a register. | |
| 423 if (NumGPRRegsUsed % 2 != 0) { | |
| 424 ++NumGPRRegsUsed; | |
| 425 } | |
| 426 RegLo = RegARM32::Reg_r0 + NumGPRRegsUsed; | |
| 427 ++NumGPRRegsUsed; | |
| 428 RegHi = RegARM32::Reg_r0 + NumGPRRegsUsed; | |
| 429 ++NumGPRRegsUsed; | |
| 430 // If this bumps us past the boundary, don't allocate to a register | |
| 431 // and leave any previously speculatively consumed registers as consumed. | |
| 432 if (NumGPRRegsUsed > ARM32_MAX_GPR_ARG) | |
| 433 continue; | 454 continue; |
| 434 Variable *RegisterArg = Func->makeVariable(Ty); | 455 Variable *RegisterArg = Func->makeVariable(Ty); |
| 435 Variable *RegisterLo = Func->makeVariable(IceType_i32); | 456 Variable *RegisterLo = Func->makeVariable(IceType_i32); |
| 436 Variable *RegisterHi = Func->makeVariable(IceType_i32); | 457 Variable *RegisterHi = Func->makeVariable(IceType_i32); |
| 437 if (ALLOW_DUMP) { | 458 if (ALLOW_DUMP) { |
| 438 RegisterArg->setName(Func, "home_reg:" + Arg->getName(Func)); | 459 RegisterArg->setName(Func, "home_reg:" + Arg->getName(Func)); |
| 439 RegisterLo->setName(Func, "home_reg_lo:" + Arg->getName(Func)); | 460 RegisterLo->setName(Func, "home_reg_lo:" + Arg->getName(Func)); |
| 440 RegisterHi->setName(Func, "home_reg_hi:" + Arg->getName(Func)); | 461 RegisterHi->setName(Func, "home_reg_hi:" + Arg->getName(Func)); |
| 441 } | 462 } |
| 442 RegisterLo->setRegNum(RegLo); | 463 RegisterLo->setRegNum(RegPair.first); |
| 443 RegisterLo->setIsArg(); | 464 RegisterLo->setIsArg(); |
| 444 RegisterHi->setRegNum(RegHi); | 465 RegisterHi->setRegNum(RegPair.second); |
| 445 RegisterHi->setIsArg(); | 466 RegisterHi->setIsArg(); |
| 446 RegisterArg->setLoHi(RegisterLo, RegisterHi); | 467 RegisterArg->setLoHi(RegisterLo, RegisterHi); |
| 447 RegisterArg->setIsArg(); | 468 RegisterArg->setIsArg(); |
| 448 Arg->setIsArg(false); | 469 Arg->setIsArg(false); |
| 449 | 470 |
| 450 Args[I] = RegisterArg; | 471 Args[I] = RegisterArg; |
| 451 Context.insert(InstAssign::create(Func, Arg, RegisterArg)); | 472 Context.insert(InstAssign::create(Func, Arg, RegisterArg)); |
| 452 continue; | 473 continue; |
| 453 } else { | 474 } else { |
| 454 assert(Ty == IceType_i32); | 475 assert(Ty == IceType_i32); |
| 455 if (NumGPRRegsUsed >= ARM32_MAX_GPR_ARG) | 476 int32_t RegNum; |
| 477 if (!CC.I32InReg(&RegNum)) |
| 456 continue; | 478 continue; |
| 457 int32_t RegNum = RegARM32::Reg_r0 + NumGPRRegsUsed; | |
| 458 ++NumGPRRegsUsed; | |
| 459 Variable *RegisterArg = Func->makeVariable(Ty); | 479 Variable *RegisterArg = Func->makeVariable(Ty); |
| 460 if (ALLOW_DUMP) { | 480 if (ALLOW_DUMP) { |
| 461 RegisterArg->setName(Func, "home_reg:" + Arg->getName(Func)); | 481 RegisterArg->setName(Func, "home_reg:" + Arg->getName(Func)); |
| 462 } | 482 } |
| 463 RegisterArg->setRegNum(RegNum); | 483 RegisterArg->setRegNum(RegNum); |
| 464 RegisterArg->setIsArg(); | 484 RegisterArg->setIsArg(); |
| 465 Arg->setIsArg(false); | 485 Arg->setIsArg(false); |
| 466 | 486 |
| 467 Args[I] = RegisterArg; | 487 Args[I] = RegisterArg; |
| 468 Context.insert(InstAssign::create(Func, Arg, RegisterArg)); | 488 Context.insert(InstAssign::create(Func, Arg, RegisterArg)); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 485 Variable *Lo = Arg->getLo(); | 505 Variable *Lo = Arg->getLo(); |
| 486 Variable *Hi = Arg->getHi(); | 506 Variable *Hi = Arg->getHi(); |
| 487 Type Ty = Arg->getType(); | 507 Type Ty = Arg->getType(); |
| 488 if (Lo && Hi && Ty == IceType_i64) { | 508 if (Lo && Hi && Ty == IceType_i64) { |
| 489 assert(Lo->getType() != IceType_i64); // don't want infinite recursion | 509 assert(Lo->getType() != IceType_i64); // don't want infinite recursion |
| 490 assert(Hi->getType() != IceType_i64); // don't want infinite recursion | 510 assert(Hi->getType() != IceType_i64); // don't want infinite recursion |
| 491 finishArgumentLowering(Lo, FramePtr, BasicFrameOffset, InArgsSizeBytes); | 511 finishArgumentLowering(Lo, FramePtr, BasicFrameOffset, InArgsSizeBytes); |
| 492 finishArgumentLowering(Hi, FramePtr, BasicFrameOffset, InArgsSizeBytes); | 512 finishArgumentLowering(Hi, FramePtr, BasicFrameOffset, InArgsSizeBytes); |
| 493 return; | 513 return; |
| 494 } | 514 } |
| 495 if (isVectorType(Ty)) { | 515 InArgsSizeBytes = applyStackAlignmentTy(InArgsSizeBytes, Ty); |
| 496 InArgsSizeBytes = applyStackAlignment(InArgsSizeBytes); | |
| 497 } | |
| 498 Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes); | 516 Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes); |
| 499 InArgsSizeBytes += typeWidthInBytesOnStack(Ty); | 517 InArgsSizeBytes += typeWidthInBytesOnStack(Ty); |
| 500 // If the argument variable has been assigned a register, we need to load | 518 // If the argument variable has been assigned a register, we need to load |
| 501 // the value from the stack slot. | 519 // the value from the stack slot. |
| 502 if (Arg->hasReg()) { | 520 if (Arg->hasReg()) { |
| 503 assert(Ty != IceType_i64); | 521 assert(Ty != IceType_i64); |
| 504 OperandARM32Mem *Mem = OperandARM32Mem::create( | 522 OperandARM32Mem *Mem = OperandARM32Mem::create( |
| 505 Func, Ty, FramePtr, llvm::cast<ConstantInteger32>( | 523 Func, Ty, FramePtr, llvm::cast<ConstantInteger32>( |
| 506 Ctx->getConstantInt32(Arg->getStackOffset()))); | 524 Ctx->getConstantInt32(Arg->getStackOffset()))); |
| 507 if (isVectorType(Arg->getType())) { | 525 if (isVectorType(Arg->getType())) { |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 // Fill in stack offsets for stack args, and copy args into registers | 683 // Fill in stack offsets for stack args, and copy args into registers |
| 666 // for those that were register-allocated. Args are pushed right to | 684 // for those that were register-allocated. Args are pushed right to |
| 667 // left, so Arg[0] is closest to the stack/frame pointer. | 685 // left, so Arg[0] is closest to the stack/frame pointer. |
| 668 Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg()); | 686 Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg()); |
| 669 size_t BasicFrameOffset = PreservedRegsSizeBytes; | 687 size_t BasicFrameOffset = PreservedRegsSizeBytes; |
| 670 if (!UsesFramePointer) | 688 if (!UsesFramePointer) |
| 671 BasicFrameOffset += SpillAreaSizeBytes; | 689 BasicFrameOffset += SpillAreaSizeBytes; |
| 672 | 690 |
| 673 const VarList &Args = Func->getArgs(); | 691 const VarList &Args = Func->getArgs(); |
| 674 size_t InArgsSizeBytes = 0; | 692 size_t InArgsSizeBytes = 0; |
| 675 unsigned NumGPRArgs = 0; | 693 TargetARM32::CallingConv CC; |
| 676 for (Variable *Arg : Args) { | 694 for (Variable *Arg : Args) { |
| 677 Type Ty = Arg->getType(); | 695 Type Ty = Arg->getType(); |
| 696 bool InRegs = false; |
| 678 // Skip arguments passed in registers. | 697 // Skip arguments passed in registers. |
| 679 if (isVectorType(Ty)) { | 698 if (isVectorType(Ty)) { |
| 680 UnimplementedError(Func->getContext()->getFlags()); | 699 UnimplementedError(Func->getContext()->getFlags()); |
| 681 continue; | 700 continue; |
| 682 } else if (isFloatingType(Ty)) { | 701 } else if (isFloatingType(Ty)) { |
| 683 UnimplementedError(Func->getContext()->getFlags()); | 702 UnimplementedError(Func->getContext()->getFlags()); |
| 684 continue; | 703 continue; |
| 685 } else if (Ty == IceType_i64 && NumGPRArgs < ARM32_MAX_GPR_ARG) { | 704 } else if (Ty == IceType_i64) { |
| 686 // Start at an even register. | 705 std::pair<int32_t, int32_t> DummyRegs; |
| 687 if (NumGPRArgs % 2 == 1) { | 706 InRegs = CC.I64InRegs(&DummyRegs); |
| 688 ++NumGPRArgs; | 707 } else { |
| 689 } | 708 assert(Ty == IceType_i32); |
| 690 NumGPRArgs += 2; | 709 int32_t DummyReg; |
| 691 if (NumGPRArgs <= ARM32_MAX_GPR_ARG) | 710 InRegs = CC.I32InReg(&DummyReg); |
| 692 continue; | |
| 693 } else if (NumGPRArgs < ARM32_MAX_GPR_ARG) { | |
| 694 ++NumGPRArgs; | |
| 695 continue; | |
| 696 } | 711 } |
| 697 finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, InArgsSizeBytes); | 712 if (!InRegs) |
| 713 finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, InArgsSizeBytes); |
| 698 } | 714 } |
| 699 | 715 |
| 700 // Fill in stack offsets for locals. | 716 // Fill in stack offsets for locals. |
| 701 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes, | 717 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes, |
| 702 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize, | 718 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize, |
| 703 UsesFramePointer); | 719 UsesFramePointer); |
| 704 this->HasComputedFrame = true; | 720 this->HasComputedFrame = true; |
| 705 | 721 |
| 706 if (ALLOW_DUMP && Func->isVerbose(IceV_Frame)) { | 722 if (ALLOW_DUMP && Func->isVerbose(IceV_Frame)) { |
| 707 OstreamLocker L(Func->getContext()); | 723 OstreamLocker L(Func->getContext()); |
| (...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1307 // TODO(jvoung): Handle folding opportunities. | 1323 // TODO(jvoung): Handle folding opportunities. |
| 1308 | 1324 |
| 1309 Variable *Src0R = legalizeToVar(Cond); | 1325 Variable *Src0R = legalizeToVar(Cond); |
| 1310 Constant *Zero = Ctx->getConstantZero(IceType_i32); | 1326 Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| 1311 _cmp(Src0R, Zero); | 1327 _cmp(Src0R, Zero); |
| 1312 _br(CondARM32::NE, Inst->getTargetTrue(), Inst->getTargetFalse()); | 1328 _br(CondARM32::NE, Inst->getTargetTrue(), Inst->getTargetFalse()); |
| 1313 } | 1329 } |
| 1314 | 1330 |
| 1315 void TargetARM32::lowerCall(const InstCall *Instr) { | 1331 void TargetARM32::lowerCall(const InstCall *Instr) { |
| 1316 MaybeLeafFunc = false; | 1332 MaybeLeafFunc = false; |
| 1333 NeedsStackAlignment = true; |
| 1317 | 1334 |
| 1318 // TODO(jvoung): assign arguments to registers and stack. Also reserve stack. | 1335 // Assign arguments to registers and stack. Also reserve stack. |
| 1319 if (Instr->getNumArgs()) { | 1336 TargetARM32::CallingConv CC; |
| 1320 UnimplementedError(Func->getContext()->getFlags()); | 1337 // Pair of Arg Operand -> GPR number assignments. |
| 1338 llvm::SmallVector<std::pair<Operand *, int32_t>, |
| 1339 TargetARM32::CallingConv::ARM32_MAX_GPR_ARG> GPRArgs; |
| 1340 // Pair of Arg Operand -> stack offset. |
| 1341 llvm::SmallVector<std::pair<Operand *, int32_t>, 8> StackArgs; |
| 1342 int32_t ParameterAreaSizeBytes = 0; |
| 1343 |
| 1344 // Classify each argument operand according to the location where the |
| 1345 // argument is passed. |
| 1346 for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) { |
| 1347 Operand *Arg = Instr->getArg(i); |
| 1348 Type Ty = Arg->getType(); |
| 1349 bool InRegs = false; |
| 1350 if (isVectorType(Ty)) { |
| 1351 UnimplementedError(Func->getContext()->getFlags()); |
| 1352 } else if (isFloatingType(Ty)) { |
| 1353 UnimplementedError(Func->getContext()->getFlags()); |
| 1354 } else if (Ty == IceType_i64) { |
| 1355 std::pair<int32_t, int32_t> Regs; |
| 1356 if (CC.I64InRegs(&Regs)) { |
| 1357 InRegs = true; |
| 1358 Operand *Lo = loOperand(Arg); |
| 1359 Operand *Hi = hiOperand(Arg); |
| 1360 GPRArgs.push_back(std::make_pair(Lo, Regs.first)); |
| 1361 GPRArgs.push_back(std::make_pair(Hi, Regs.second)); |
| 1362 } |
| 1363 } else { |
| 1364 assert(Ty == IceType_i32); |
| 1365 int32_t Reg; |
| 1366 if (CC.I32InReg(&Reg)) { |
| 1367 InRegs = true; |
| 1368 GPRArgs.push_back(std::make_pair(Arg, Reg)); |
| 1369 } |
| 1370 } |
| 1371 |
| 1372 if (!InRegs) { |
| 1373 ParameterAreaSizeBytes = |
| 1374 applyStackAlignmentTy(ParameterAreaSizeBytes, Ty); |
| 1375 StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes)); |
| 1376 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType()); |
| 1377 } |
| 1378 } |
| 1379 |
| 1380 // Adjust the parameter area so that the stack is aligned. It is |
| 1381 // assumed that the stack is already aligned at the start of the |
| 1382 // calling sequence. |
| 1383 ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes); |
| 1384 |
| 1385 // Subtract the appropriate amount for the argument area. This also |
| 1386 // takes care of setting the stack adjustment during emission. |
| 1387 // |
| 1388 // TODO: If for some reason the call instruction gets dead-code |
| 1389 // eliminated after lowering, we would need to ensure that the |
| 1390 // pre-call and the post-call esp adjustment get eliminated as well. |
| 1391 if (ParameterAreaSizeBytes) { |
| 1392 Operand *SubAmount = legalize(Ctx->getConstantInt32(ParameterAreaSizeBytes), |
| 1393 Legal_Reg | Legal_Flex); |
| 1394 _adjust_stack(ParameterAreaSizeBytes, SubAmount); |
| 1395 } |
| 1396 |
| 1397 // Copy arguments that are passed on the stack to the appropriate |
| 1398 // stack locations. |
| 1399 Variable *SP = Func->getTarget()->getPhysicalRegister(RegARM32::Reg_sp); |
| 1400 for (auto &StackArg : StackArgs) { |
| 1401 ConstantInteger32 *Loc = |
| 1402 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second)); |
| 1403 Type Ty = StackArg.first->getType(); |
| 1404 OperandARM32Mem *Addr; |
| 1405 constexpr bool SignExt = false; |
| 1406 if (OperandARM32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) { |
| 1407 Addr = OperandARM32Mem::create(Func, Ty, SP, Loc); |
| 1408 } else { |
| 1409 Variable *NewBase = Func->makeVariable(SP->getType()); |
| 1410 lowerArithmetic( |
| 1411 InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc)); |
| 1412 Addr = formMemoryOperand(NewBase, Ty); |
| 1413 } |
| 1414 lowerStore(InstStore::create(Func, StackArg.first, Addr)); |
| 1415 } |
| 1416 |
| 1417 // Copy arguments to be passed in registers to the appropriate registers. |
| 1418 for (auto &GPRArg : GPRArgs) { |
| 1419 Variable *Reg = legalizeToVar(GPRArg.first, GPRArg.second); |
| 1420 // Generate a FakeUse of register arguments so that they do not get |
| 1421 // dead code eliminated as a result of the FakeKill of scratch |
| 1422 // registers after the call. |
| 1423 Context.insert(InstFakeUse::create(Func, Reg)); |
| 1321 } | 1424 } |
| 1322 | 1425 |
| 1323 // Generate the call instruction. Assign its result to a temporary | 1426 // Generate the call instruction. Assign its result to a temporary |
| 1324 // with high register allocation weight. | 1427 // with high register allocation weight. |
| 1325 Variable *Dest = Instr->getDest(); | 1428 Variable *Dest = Instr->getDest(); |
| 1326 // ReturnReg doubles as ReturnRegLo as necessary. | 1429 // ReturnReg doubles as ReturnRegLo as necessary. |
| 1327 Variable *ReturnReg = nullptr; | 1430 Variable *ReturnReg = nullptr; |
| 1328 Variable *ReturnRegHi = nullptr; | 1431 Variable *ReturnRegHi = nullptr; |
| 1329 if (Dest) { | 1432 if (Dest) { |
| 1330 switch (Dest->getType()) { | 1433 switch (Dest->getType()) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1354 case IceType_v16i8: | 1457 case IceType_v16i8: |
| 1355 case IceType_v8i16: | 1458 case IceType_v8i16: |
| 1356 case IceType_v4i32: | 1459 case IceType_v4i32: |
| 1357 case IceType_v4f32: | 1460 case IceType_v4f32: |
| 1358 // Use Q regs. | 1461 // Use Q regs. |
| 1359 UnimplementedError(Func->getContext()->getFlags()); | 1462 UnimplementedError(Func->getContext()->getFlags()); |
| 1360 break; | 1463 break; |
| 1361 } | 1464 } |
| 1362 } | 1465 } |
| 1363 Operand *CallTarget = Instr->getCallTarget(); | 1466 Operand *CallTarget = Instr->getCallTarget(); |
| 1467 // TODO(jvoung): Handle sandboxing. |
| 1468 // const bool NeedSandboxing = Ctx->getFlags().getUseSandboxing(); |
| 1469 |
| 1364 // Allow ConstantRelocatable to be left alone as a direct call, | 1470 // Allow ConstantRelocatable to be left alone as a direct call, |
| 1365 // but force other constants like ConstantInteger32 to be in | 1471 // but force other constants like ConstantInteger32 to be in |
| 1366 // a register and make it an indirect call. | 1472 // a register and make it an indirect call. |
| 1367 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { | 1473 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { |
| 1368 CallTarget = legalize(CallTarget, Legal_Reg); | 1474 CallTarget = legalize(CallTarget, Legal_Reg); |
| 1369 } | 1475 } |
| 1370 Inst *NewCall = InstARM32Call::create(Func, ReturnReg, CallTarget); | 1476 Inst *NewCall = InstARM32Call::create(Func, ReturnReg, CallTarget); |
| 1371 Context.insert(NewCall); | 1477 Context.insert(NewCall); |
| 1372 if (ReturnRegHi) | 1478 if (ReturnRegHi) |
| 1373 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); | 1479 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); |
| 1374 | 1480 |
| 1481 // Add the appropriate offset to SP. The call instruction takes care |
| 1482 // of resetting the stack offset during emission. |
| 1483 if (ParameterAreaSizeBytes) { |
| 1484 Operand *AddAmount = legalize(Ctx->getConstantInt32(ParameterAreaSizeBytes), |
| 1485 Legal_Reg | Legal_Flex); |
| 1486 Variable *SP = Func->getTarget()->getPhysicalRegister(RegARM32::Reg_sp); |
| 1487 _add(SP, SP, AddAmount); |
| 1488 } |
| 1489 |
| 1375 // Insert a register-kill pseudo instruction. | 1490 // Insert a register-kill pseudo instruction. |
| 1376 Context.insert(InstFakeKill::create(Func, NewCall)); | 1491 Context.insert(InstFakeKill::create(Func, NewCall)); |
| 1377 | 1492 |
| 1378 // Generate a FakeUse to keep the call live if necessary. | 1493 // Generate a FakeUse to keep the call live if necessary. |
| 1379 if (Instr->hasSideEffects() && ReturnReg) { | 1494 if (Instr->hasSideEffects() && ReturnReg) { |
| 1380 Inst *FakeUse = InstFakeUse::create(Func, ReturnReg); | 1495 Inst *FakeUse = InstFakeUse::create(Func, ReturnReg); |
| 1381 Context.insert(FakeUse); | 1496 Context.insert(FakeUse); |
| 1382 } | 1497 } |
| 1383 | 1498 |
| 1384 if (!Dest) | 1499 if (!Dest) |
| (...skipping 881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2266 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n" | 2381 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n" |
| 2267 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n" | 2382 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n" |
| 2268 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n" | 2383 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n" |
| 2269 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; | 2384 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; |
| 2270 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 2385 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
| 2271 // However, for compatibility with current NaCl LLVM, don't claim that. | 2386 // However, for compatibility with current NaCl LLVM, don't claim that. |
| 2272 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 2387 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
| 2273 } | 2388 } |
| 2274 | 2389 |
| 2275 } // end of namespace Ice | 2390 } // end of namespace Ice |
| OLD | NEW |