| OLD | NEW |
| 1 //===- subzero/src/IceTargetLowering.cpp - Basic lowering implementation --===// | 1 //===- subzero/src/IceTargetLowering.cpp - Basic lowering implementation --===// |
| 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 skeleton of the TargetLowering class, | 11 /// This file implements the skeleton of the TargetLowering class, specifically |
| 12 /// specifically invoking the appropriate lowering method for a given | 12 /// invoking the appropriate lowering method for a given instruction kind and |
| 13 /// instruction kind and driving global register allocation. It also | 13 /// driving global register allocation. It also implements the non-deleted |
| 14 /// implements the non-deleted instruction iteration in | 14 /// instruction iteration in LoweringContext. |
| 15 /// LoweringContext. | |
| 16 /// | 15 /// |
| 17 //===----------------------------------------------------------------------===// | 16 //===----------------------------------------------------------------------===// |
| 18 | 17 |
| 19 #include "IceTargetLowering.h" | 18 #include "IceTargetLowering.h" |
| 20 | 19 |
| 21 #include "IceAssemblerARM32.h" | 20 #include "IceAssemblerARM32.h" |
| 22 #include "IceAssemblerMIPS32.h" | 21 #include "IceAssemblerMIPS32.h" |
| 23 #include "IceAssemblerX8632.h" | 22 #include "IceAssemblerX8632.h" |
| 24 #include "IceAssemblerX8664.h" | 23 #include "IceAssemblerX8664.h" |
| 25 #include "IceCfg.h" // setError() | 24 #include "IceCfg.h" // setError() |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 llvm::isa<InstFakeKill>(I) || I->isRedundantAssign() || | 109 llvm::isa<InstFakeKill>(I) || I->isRedundantAssign() || |
| 111 I->isDeleted(); | 110 I->isDeleted(); |
| 112 if (!ShouldSkip) { | 111 if (!ShouldSkip) { |
| 113 int Probability = Ctx->getFlags().getNopProbabilityAsPercentage(); | 112 int Probability = Ctx->getFlags().getNopProbabilityAsPercentage(); |
| 114 for (int I = 0; I < Ctx->getFlags().getMaxNopsPerInstruction(); ++I) { | 113 for (int I = 0; I < Ctx->getFlags().getMaxNopsPerInstruction(); ++I) { |
| 115 randomlyInsertNop(Probability / 100.0, RNG); | 114 randomlyInsertNop(Probability / 100.0, RNG); |
| 116 } | 115 } |
| 117 } | 116 } |
| 118 } | 117 } |
| 119 | 118 |
| 120 // Lowers a single instruction according to the information in | 119 // Lowers a single instruction according to the information in Context, by |
| 121 // Context, by checking the Context.Cur instruction kind and calling | 120 // checking the Context.Cur instruction kind and calling the appropriate |
| 122 // the appropriate lowering method. The lowering method should insert | 121 // lowering method. The lowering method should insert target instructions at |
| 123 // target instructions at the Cur.Next insertion point, and should not | 122 // the Cur.Next insertion point, and should not delete the Context.Cur |
| 124 // delete the Context.Cur instruction or advance Context.Cur. | 123 // instruction or advance Context.Cur. |
| 125 // | 124 // |
| 126 // The lowering method may look ahead in the instruction stream as | 125 // The lowering method may look ahead in the instruction stream as desired, and |
| 127 // desired, and lower additional instructions in conjunction with the | 126 // lower additional instructions in conjunction with the current one, for |
| 128 // current one, for example fusing a compare and branch. If it does, | 127 // example fusing a compare and branch. If it does, it should advance |
| 129 // it should advance Context.Cur to point to the next non-deleted | 128 // Context.Cur to point to the next non-deleted instruction to process, and it |
| 130 // instruction to process, and it should delete any additional | 129 // should delete any additional instructions it consumes. |
| 131 // instructions it consumes. | |
| 132 void TargetLowering::lower() { | 130 void TargetLowering::lower() { |
| 133 assert(!Context.atEnd()); | 131 assert(!Context.atEnd()); |
| 134 Inst *Inst = Context.getCur(); | 132 Inst *Inst = Context.getCur(); |
| 135 Inst->deleteIfDead(); | 133 Inst->deleteIfDead(); |
| 136 if (!Inst->isDeleted() && !llvm::isa<InstFakeDef>(Inst) && | 134 if (!Inst->isDeleted() && !llvm::isa<InstFakeDef>(Inst) && |
| 137 !llvm::isa<InstFakeUse>(Inst)) { | 135 !llvm::isa<InstFakeUse>(Inst)) { |
| 138 // Mark the current instruction as deleted before lowering, | 136 // Mark the current instruction as deleted before lowering, otherwise the |
| 139 // otherwise the Dest variable will likely get marked as non-SSA. | 137 // Dest variable will likely get marked as non-SSA. See |
| 140 // See Variable::setDefinition(). However, just pass-through | 138 // Variable::setDefinition(). However, just pass-through FakeDef and |
| 141 // FakeDef and FakeUse instructions that might have been inserted | 139 // FakeUse instructions that might have been inserted prior to lowering. |
| 142 // prior to lowering. | |
| 143 Inst->setDeleted(); | 140 Inst->setDeleted(); |
| 144 switch (Inst->getKind()) { | 141 switch (Inst->getKind()) { |
| 145 case Inst::Alloca: | 142 case Inst::Alloca: |
| 146 lowerAlloca(llvm::cast<InstAlloca>(Inst)); | 143 lowerAlloca(llvm::cast<InstAlloca>(Inst)); |
| 147 break; | 144 break; |
| 148 case Inst::Arithmetic: | 145 case Inst::Arithmetic: |
| 149 lowerArithmetic(llvm::cast<InstArithmetic>(Inst)); | 146 lowerArithmetic(llvm::cast<InstArithmetic>(Inst)); |
| 150 break; | 147 break; |
| 151 case Inst::Assign: | 148 case Inst::Assign: |
| 152 lowerAssign(llvm::cast<InstAssign>(Inst)); | 149 lowerAssign(llvm::cast<InstAssign>(Inst)); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 assert(&*Next == Instr); | 221 assert(&*Next == Instr); |
| 225 Context.setCur(Next); | 222 Context.setCur(Next); |
| 226 lower(); | 223 lower(); |
| 227 } | 224 } |
| 228 | 225 |
| 229 void TargetLowering::lowerOther(const Inst *Instr) { | 226 void TargetLowering::lowerOther(const Inst *Instr) { |
| 230 (void)Instr; | 227 (void)Instr; |
| 231 Func->setError("Can't lower unsupported instruction type"); | 228 Func->setError("Can't lower unsupported instruction type"); |
| 232 } | 229 } |
| 233 | 230 |
| 234 // Drives register allocation, allowing all physical registers (except | 231 // Drives register allocation, allowing all physical registers (except perhaps |
| 235 // perhaps for the frame pointer) to be allocated. This set of | 232 // for the frame pointer) to be allocated. This set of registers could |
| 236 // registers could potentially be parameterized if we want to restrict | 233 // potentially be parameterized if we want to restrict registers e.g. for |
| 237 // registers e.g. for performance testing. | 234 // performance testing. |
| 238 void TargetLowering::regAlloc(RegAllocKind Kind) { | 235 void TargetLowering::regAlloc(RegAllocKind Kind) { |
| 239 TimerMarker T(TimerStack::TT_regAlloc, Func); | 236 TimerMarker T(TimerStack::TT_regAlloc, Func); |
| 240 LinearScan LinearScan(Func); | 237 LinearScan LinearScan(Func); |
| 241 RegSetMask RegInclude = RegSet_None; | 238 RegSetMask RegInclude = RegSet_None; |
| 242 RegSetMask RegExclude = RegSet_None; | 239 RegSetMask RegExclude = RegSet_None; |
| 243 RegInclude |= RegSet_CallerSave; | 240 RegInclude |= RegSet_CallerSave; |
| 244 RegInclude |= RegSet_CalleeSave; | 241 RegInclude |= RegSet_CalleeSave; |
| 245 if (hasFramePointer()) | 242 if (hasFramePointer()) |
| 246 RegExclude |= RegSet_FramePointer; | 243 RegExclude |= RegSet_FramePointer; |
| 247 LinearScan.init(Kind); | 244 LinearScan.init(Kind); |
| 248 llvm::SmallBitVector RegMask = getRegisterSet(RegInclude, RegExclude); | 245 llvm::SmallBitVector RegMask = getRegisterSet(RegInclude, RegExclude); |
| 249 LinearScan.scan(RegMask, Ctx->getFlags().shouldRandomizeRegAlloc()); | 246 LinearScan.scan(RegMask, Ctx->getFlags().shouldRandomizeRegAlloc()); |
| 250 } | 247 } |
| 251 | 248 |
| 252 void TargetLowering::inferTwoAddress() { | 249 void TargetLowering::inferTwoAddress() { |
| 253 // Find two-address non-SSA instructions where Dest==Src0, and set | 250 // Find two-address non-SSA instructions where Dest==Src0, and set the |
| 254 // the DestNonKillable flag to keep liveness analysis consistent. | 251 // DestNonKillable flag to keep liveness analysis consistent. |
| 255 for (auto Inst = Context.getCur(), E = Context.getNext(); Inst != E; ++Inst) { | 252 for (auto Inst = Context.getCur(), E = Context.getNext(); Inst != E; ++Inst) { |
| 256 if (Inst->isDeleted()) | 253 if (Inst->isDeleted()) |
| 257 continue; | 254 continue; |
| 258 if (Variable *Dest = Inst->getDest()) { | 255 if (Variable *Dest = Inst->getDest()) { |
| 259 // TODO(stichnot): We may need to consider all source | 256 // TODO(stichnot): We may need to consider all source operands, not just |
| 260 // operands, not just the first one, if using 3-address | 257 // the first one, if using 3-address instructions. |
| 261 // instructions. | |
| 262 if (Inst->getSrcSize() > 0 && Inst->getSrc(0) == Dest) | 258 if (Inst->getSrcSize() > 0 && Inst->getSrc(0) == Dest) |
| 263 Inst->setDestNonKillable(); | 259 Inst->setDestNonKillable(); |
| 264 } | 260 } |
| 265 } | 261 } |
| 266 } | 262 } |
| 267 | 263 |
| 268 void TargetLowering::sortVarsByAlignment(VarList &Dest, | 264 void TargetLowering::sortVarsByAlignment(VarList &Dest, |
| 269 const VarList &Source) const { | 265 const VarList &Source) const { |
| 270 Dest = Source; | 266 Dest = Source; |
| 271 // Instead of std::sort, we could do a bucket sort with log2(alignment) | 267 // Instead of std::sort, we could do a bucket sort with log2(alignment) as |
| 272 // as the buckets, if performance is an issue. | 268 // the buckets, if performance is an issue. |
| 273 std::sort(Dest.begin(), Dest.end(), | 269 std::sort(Dest.begin(), Dest.end(), |
| 274 [this](const Variable *V1, const Variable *V2) { | 270 [this](const Variable *V1, const Variable *V2) { |
| 275 return typeWidthInBytesOnStack(V1->getType()) > | 271 return typeWidthInBytesOnStack(V1->getType()) > |
| 276 typeWidthInBytesOnStack(V2->getType()); | 272 typeWidthInBytesOnStack(V2->getType()); |
| 277 }); | 273 }); |
| 278 } | 274 } |
| 279 | 275 |
| 280 void TargetLowering::getVarStackSlotParams( | 276 void TargetLowering::getVarStackSlotParams( |
| 281 VarList &SortedSpilledVariables, llvm::SmallBitVector &RegsUsed, | 277 VarList &SortedSpilledVariables, llvm::SmallBitVector &RegsUsed, |
| 282 size_t *GlobalsSize, size_t *SpillAreaSizeBytes, | 278 size_t *GlobalsSize, size_t *SpillAreaSizeBytes, |
| 283 uint32_t *SpillAreaAlignmentBytes, uint32_t *LocalsSlotsAlignmentBytes, | 279 uint32_t *SpillAreaAlignmentBytes, uint32_t *LocalsSlotsAlignmentBytes, |
| 284 std::function<bool(Variable *)> TargetVarHook) { | 280 std::function<bool(Variable *)> TargetVarHook) { |
| 285 const VariablesMetadata *VMetadata = Func->getVMetadata(); | 281 const VariablesMetadata *VMetadata = Func->getVMetadata(); |
| 286 llvm::BitVector IsVarReferenced(Func->getNumVariables()); | 282 llvm::BitVector IsVarReferenced(Func->getNumVariables()); |
| 287 for (CfgNode *Node : Func->getNodes()) { | 283 for (CfgNode *Node : Func->getNodes()) { |
| 288 for (Inst &Inst : Node->getInsts()) { | 284 for (Inst &Inst : Node->getInsts()) { |
| 289 if (Inst.isDeleted()) | 285 if (Inst.isDeleted()) |
| 290 continue; | 286 continue; |
| 291 if (const Variable *Var = Inst.getDest()) | 287 if (const Variable *Var = Inst.getDest()) |
| 292 IsVarReferenced[Var->getIndex()] = true; | 288 IsVarReferenced[Var->getIndex()] = true; |
| 293 FOREACH_VAR_IN_INST(Var, Inst) { | 289 FOREACH_VAR_IN_INST(Var, Inst) { |
| 294 IsVarReferenced[Var->getIndex()] = true; | 290 IsVarReferenced[Var->getIndex()] = true; |
| 295 } | 291 } |
| 296 } | 292 } |
| 297 } | 293 } |
| 298 | 294 |
| 299 // If SimpleCoalescing is false, each variable without a register | 295 // If SimpleCoalescing is false, each variable without a register gets its |
| 300 // gets its own unique stack slot, which leads to large stack | 296 // own unique stack slot, which leads to large stack frames. If |
| 301 // frames. If SimpleCoalescing is true, then each "global" variable | 297 // SimpleCoalescing is true, then each "global" variable without a register |
| 302 // without a register gets its own slot, but "local" variable slots | 298 // gets its own slot, but "local" variable slots are reused across basic |
| 303 // are reused across basic blocks. E.g., if A and B are local to | 299 // blocks. E.g., if A and B are local to block 1 and C is local to block 2, |
| 304 // block 1 and C is local to block 2, then C may share a slot with A or B. | 300 // then C may share a slot with A or B. |
| 305 // | 301 // |
| 306 // We cannot coalesce stack slots if this function calls a "returns twice" | 302 // We cannot coalesce stack slots if this function calls a "returns twice" |
| 307 // function. In that case, basic blocks may be revisited, and variables | 303 // function. In that case, basic blocks may be revisited, and variables local |
| 308 // local to those basic blocks are actually live until after the | 304 // to those basic blocks are actually live until after the called function |
| 309 // called function returns a second time. | 305 // returns a second time. |
| 310 const bool SimpleCoalescing = !callsReturnsTwice(); | 306 const bool SimpleCoalescing = !callsReturnsTwice(); |
| 311 | 307 |
| 312 std::vector<size_t> LocalsSize(Func->getNumNodes()); | 308 std::vector<size_t> LocalsSize(Func->getNumNodes()); |
| 313 const VarList &Variables = Func->getVariables(); | 309 const VarList &Variables = Func->getVariables(); |
| 314 VarList SpilledVariables; | 310 VarList SpilledVariables; |
| 315 for (Variable *Var : Variables) { | 311 for (Variable *Var : Variables) { |
| 316 if (Var->hasReg()) { | 312 if (Var->hasReg()) { |
| 317 RegsUsed[Var->getRegNum()] = true; | 313 RegsUsed[Var->getRegNum()] = true; |
| 318 continue; | 314 continue; |
| 319 } | 315 } |
| 320 // An argument either does not need a stack slot (if passed in a | 316 // An argument either does not need a stack slot (if passed in a register) |
| 321 // register) or already has one (if passed on the stack). | 317 // or already has one (if passed on the stack). |
| 322 if (Var->getIsArg()) | 318 if (Var->getIsArg()) |
| 323 continue; | 319 continue; |
| 324 // An unreferenced variable doesn't need a stack slot. | 320 // An unreferenced variable doesn't need a stack slot. |
| 325 if (!IsVarReferenced[Var->getIndex()]) | 321 if (!IsVarReferenced[Var->getIndex()]) |
| 326 continue; | 322 continue; |
| 327 // Check a target-specific variable (it may end up sharing stack slots) | 323 // Check a target-specific variable (it may end up sharing stack slots) and |
| 328 // and not need accounting here. | 324 // not need accounting here. |
| 329 if (TargetVarHook(Var)) | 325 if (TargetVarHook(Var)) |
| 330 continue; | 326 continue; |
| 331 SpilledVariables.push_back(Var); | 327 SpilledVariables.push_back(Var); |
| 332 } | 328 } |
| 333 | 329 |
| 334 SortedSpilledVariables.reserve(SpilledVariables.size()); | 330 SortedSpilledVariables.reserve(SpilledVariables.size()); |
| 335 sortVarsByAlignment(SortedSpilledVariables, SpilledVariables); | 331 sortVarsByAlignment(SortedSpilledVariables, SpilledVariables); |
| 336 | 332 |
| 337 for (Variable *Var : SortedSpilledVariables) { | 333 for (Variable *Var : SortedSpilledVariables) { |
| 338 size_t Increment = typeWidthInBytesOnStack(Var->getType()); | 334 size_t Increment = typeWidthInBytesOnStack(Var->getType()); |
| 339 // We have sorted by alignment, so the first variable we encounter that | 335 // We have sorted by alignment, so the first variable we encounter that is |
| 340 // is located in each area determines the max alignment for the area. | 336 // located in each area determines the max alignment for the area. |
| 341 if (!*SpillAreaAlignmentBytes) | 337 if (!*SpillAreaAlignmentBytes) |
| 342 *SpillAreaAlignmentBytes = Increment; | 338 *SpillAreaAlignmentBytes = Increment; |
| 343 if (SimpleCoalescing && VMetadata->isTracked(Var)) { | 339 if (SimpleCoalescing && VMetadata->isTracked(Var)) { |
| 344 if (VMetadata->isMultiBlock(Var)) { | 340 if (VMetadata->isMultiBlock(Var)) { |
| 345 *GlobalsSize += Increment; | 341 *GlobalsSize += Increment; |
| 346 } else { | 342 } else { |
| 347 SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex(); | 343 SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex(); |
| 348 LocalsSize[NodeIndex] += Increment; | 344 LocalsSize[NodeIndex] += Increment; |
| 349 if (LocalsSize[NodeIndex] > *SpillAreaSizeBytes) | 345 if (LocalsSize[NodeIndex] > *SpillAreaSizeBytes) |
| 350 *SpillAreaSizeBytes = LocalsSize[NodeIndex]; | 346 *SpillAreaSizeBytes = LocalsSize[NodeIndex]; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 366 uint32_t LocalsSlotsAlignmentBytes, | 362 uint32_t LocalsSlotsAlignmentBytes, |
| 367 uint32_t *SpillAreaPaddingBytes, | 363 uint32_t *SpillAreaPaddingBytes, |
| 368 uint32_t *LocalsSlotsPaddingBytes) { | 364 uint32_t *LocalsSlotsPaddingBytes) { |
| 369 if (SpillAreaAlignmentBytes) { | 365 if (SpillAreaAlignmentBytes) { |
| 370 uint32_t PaddingStart = SpillAreaStartOffset; | 366 uint32_t PaddingStart = SpillAreaStartOffset; |
| 371 uint32_t SpillAreaStart = | 367 uint32_t SpillAreaStart = |
| 372 Utils::applyAlignment(PaddingStart, SpillAreaAlignmentBytes); | 368 Utils::applyAlignment(PaddingStart, SpillAreaAlignmentBytes); |
| 373 *SpillAreaPaddingBytes = SpillAreaStart - PaddingStart; | 369 *SpillAreaPaddingBytes = SpillAreaStart - PaddingStart; |
| 374 } | 370 } |
| 375 | 371 |
| 376 // If there are separate globals and locals areas, make sure the | 372 // If there are separate globals and locals areas, make sure the locals area |
| 377 // locals area is aligned by padding the end of the globals area. | 373 // is aligned by padding the end of the globals area. |
| 378 if (LocalsSlotsAlignmentBytes) { | 374 if (LocalsSlotsAlignmentBytes) { |
| 379 uint32_t GlobalsAndSubsequentPaddingSize = GlobalsSize; | 375 uint32_t GlobalsAndSubsequentPaddingSize = GlobalsSize; |
| 380 GlobalsAndSubsequentPaddingSize = | 376 GlobalsAndSubsequentPaddingSize = |
| 381 Utils::applyAlignment(GlobalsSize, LocalsSlotsAlignmentBytes); | 377 Utils::applyAlignment(GlobalsSize, LocalsSlotsAlignmentBytes); |
| 382 *LocalsSlotsPaddingBytes = GlobalsAndSubsequentPaddingSize - GlobalsSize; | 378 *LocalsSlotsPaddingBytes = GlobalsAndSubsequentPaddingSize - GlobalsSize; |
| 383 } | 379 } |
| 384 } | 380 } |
| 385 | 381 |
| 386 void TargetLowering::assignVarStackSlots(VarList &SortedSpilledVariables, | 382 void TargetLowering::assignVarStackSlots(VarList &SortedSpilledVariables, |
| 387 size_t SpillAreaPaddingBytes, | 383 size_t SpillAreaPaddingBytes, |
| 388 size_t SpillAreaSizeBytes, | 384 size_t SpillAreaSizeBytes, |
| 389 size_t GlobalsAndSubsequentPaddingSize, | 385 size_t GlobalsAndSubsequentPaddingSize, |
| 390 bool UsesFramePointer) { | 386 bool UsesFramePointer) { |
| 391 const VariablesMetadata *VMetadata = Func->getVMetadata(); | 387 const VariablesMetadata *VMetadata = Func->getVMetadata(); |
| 392 // For testing legalization of large stack offsets on targets with limited | 388 // For testing legalization of large stack offsets on targets with limited |
| 393 // offset bits in instruction encodings, add some padding. This assumes that | 389 // offset bits in instruction encodings, add some padding. This assumes that |
| 394 // SpillAreaSizeBytes has accounted for the extra test padding. | 390 // SpillAreaSizeBytes has accounted for the extra test padding. When |
| 395 // When UseFramePointer is true, the offset depends on the padding, | 391 // UseFramePointer is true, the offset depends on the padding, not just the |
| 396 // not just the SpillAreaSizeBytes. On the other hand, when UseFramePointer | 392 // SpillAreaSizeBytes. On the other hand, when UseFramePointer is false, the |
| 397 // is false, the offsets depend on the gap between SpillAreaSizeBytes | 393 // offsets depend on the gap between SpillAreaSizeBytes and |
| 398 // and SpillAreaPaddingBytes, so we don't increment that. | 394 // SpillAreaPaddingBytes, so we don't increment that. |
| 399 size_t TestPadding = Ctx->getFlags().getTestStackExtra(); | 395 size_t TestPadding = Ctx->getFlags().getTestStackExtra(); |
| 400 if (UsesFramePointer) | 396 if (UsesFramePointer) |
| 401 SpillAreaPaddingBytes += TestPadding; | 397 SpillAreaPaddingBytes += TestPadding; |
| 402 size_t GlobalsSpaceUsed = SpillAreaPaddingBytes; | 398 size_t GlobalsSpaceUsed = SpillAreaPaddingBytes; |
| 403 size_t NextStackOffset = SpillAreaPaddingBytes; | 399 size_t NextStackOffset = SpillAreaPaddingBytes; |
| 404 std::vector<size_t> LocalsSize(Func->getNumNodes()); | 400 std::vector<size_t> LocalsSize(Func->getNumNodes()); |
| 405 const bool SimpleCoalescing = !callsReturnsTwice(); | 401 const bool SimpleCoalescing = !callsReturnsTwice(); |
| 406 | 402 |
| 407 for (Variable *Var : SortedSpilledVariables) { | 403 for (Variable *Var : SortedSpilledVariables) { |
| 408 size_t Increment = typeWidthInBytesOnStack(Var->getType()); | 404 size_t Increment = typeWidthInBytesOnStack(Var->getType()); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 return "." + SectionSuffix; | 495 return "." + SectionSuffix; |
| 500 } | 496 } |
| 501 | 497 |
| 502 } // end of anonymous namespace | 498 } // end of anonymous namespace |
| 503 | 499 |
| 504 void TargetDataLowering::emitGlobal(const VariableDeclaration &Var, | 500 void TargetDataLowering::emitGlobal(const VariableDeclaration &Var, |
| 505 const IceString &SectionSuffix) { | 501 const IceString &SectionSuffix) { |
| 506 if (!BuildDefs::dump()) | 502 if (!BuildDefs::dump()) |
| 507 return; | 503 return; |
| 508 | 504 |
| 509 // If external and not initialized, this must be a cross test. | 505 // If external and not initialized, this must be a cross test. Don't generate |
| 510 // Don't generate a declaration for such cases. | 506 // a declaration for such cases. |
| 511 const bool IsExternal = | 507 const bool IsExternal = |
| 512 Var.isExternal() || Ctx->getFlags().getDisableInternal(); | 508 Var.isExternal() || Ctx->getFlags().getDisableInternal(); |
| 513 if (IsExternal && !Var.hasInitializer()) | 509 if (IsExternal && !Var.hasInitializer()) |
| 514 return; | 510 return; |
| 515 | 511 |
| 516 Ostream &Str = Ctx->getStrEmit(); | 512 Ostream &Str = Ctx->getStrEmit(); |
| 517 const bool HasNonzeroInitializer = Var.hasNonzeroInitializer(); | 513 const bool HasNonzeroInitializer = Var.hasNonzeroInitializer(); |
| 518 const bool IsConstant = Var.getIsConstant(); | 514 const bool IsConstant = Var.getIsConstant(); |
| 519 const SizeT Size = Var.getNumBytes(); | 515 const SizeT Size = Var.getNumBytes(); |
| 520 const IceString MangledName = Var.mangleName(Ctx); | 516 const IceString MangledName = Var.mangleName(Ctx); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 Str << " + " << Offset; | 566 Str << " + " << Offset; |
| 571 else | 567 else |
| 572 Str << " - " << -Offset; | 568 Str << " - " << -Offset; |
| 573 } | 569 } |
| 574 Str << "\n"; | 570 Str << "\n"; |
| 575 break; | 571 break; |
| 576 } | 572 } |
| 577 } | 573 } |
| 578 } | 574 } |
| 579 } else { | 575 } else { |
| 580 // NOTE: for non-constant zero initializers, this is BSS (no bits), | 576 // NOTE: for non-constant zero initializers, this is BSS (no bits), so an |
| 581 // so an ELF writer would not write to the file, and only track | 577 // ELF writer would not write to the file, and only track virtual offsets, |
| 582 // virtual offsets, but the .s writer still needs this .zero and | 578 // but the .s writer still needs this .zero and cannot simply use the .size |
| 583 // cannot simply use the .size to advance offsets. | 579 // to advance offsets. |
| 584 Str << "\t.zero\t" << Size << "\n"; | 580 Str << "\t.zero\t" << Size << "\n"; |
| 585 } | 581 } |
| 586 | 582 |
| 587 Str << "\t.size\t" << MangledName << ", " << Size << "\n"; | 583 Str << "\t.size\t" << MangledName << ", " << Size << "\n"; |
| 588 } | 584 } |
| 589 | 585 |
| 590 std::unique_ptr<TargetHeaderLowering> | 586 std::unique_ptr<TargetHeaderLowering> |
| 591 TargetHeaderLowering::createLowering(GlobalContext *Ctx) { | 587 TargetHeaderLowering::createLowering(GlobalContext *Ctx) { |
| 592 TargetArch Target = Ctx->getFlags().getTargetArch(); | 588 TargetArch Target = Ctx->getFlags().getTargetArch(); |
| 593 #define SUBZERO_TARGET(X) \ | 589 #define SUBZERO_TARGET(X) \ |
| 594 if (Target == Target_##X) \ | 590 if (Target == Target_##X) \ |
| 595 return TargetHeader##X::create(Ctx); | 591 return TargetHeader##X::create(Ctx); |
| 596 #include "llvm/Config/SZTargets.def" | 592 #include "llvm/Config/SZTargets.def" |
| 597 | 593 |
| 598 llvm::report_fatal_error("Unsupported target header lowering"); | 594 llvm::report_fatal_error("Unsupported target header lowering"); |
| 599 } | 595 } |
| 600 | 596 |
| 601 TargetHeaderLowering::~TargetHeaderLowering() = default; | 597 TargetHeaderLowering::~TargetHeaderLowering() = default; |
| 602 | 598 |
| 603 } // end of namespace Ice | 599 } // end of namespace Ice |
| OLD | NEW |