OLD | NEW |
1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction implementation ----===// | 1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction 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 InstARM32 and OperandARM32 classes, | 11 /// This file implements the InstARM32 and OperandARM32 classes, primarily the |
12 /// primarily the constructors and the dump()/emit() methods. | 12 /// constructors and the dump()/emit() methods. |
13 /// | 13 /// |
14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
15 | 15 |
16 #include "IceInstARM32.h" | 16 #include "IceInstARM32.h" |
17 | 17 |
18 #include "IceAssemblerARM32.h" | 18 #include "IceAssemblerARM32.h" |
19 #include "IceCfg.h" | 19 #include "IceCfg.h" |
20 #include "IceCfgNode.h" | 20 #include "IceCfgNode.h" |
21 #include "IceInst.h" | 21 #include "IceInst.h" |
22 #include "IceOperand.h" | 22 #include "IceOperand.h" |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 addSource(SrcAmount); | 264 addSource(SrcAmount); |
265 } | 265 } |
266 | 266 |
267 InstARM32Br::InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, | 267 InstARM32Br::InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, |
268 const CfgNode *TargetFalse, | 268 const CfgNode *TargetFalse, |
269 const InstARM32Label *Label, CondARM32::Cond Pred) | 269 const InstARM32Label *Label, CondARM32::Cond Pred) |
270 : InstARM32Pred(Func, InstARM32::Br, 0, nullptr, Pred), | 270 : InstARM32Pred(Func, InstARM32::Br, 0, nullptr, Pred), |
271 TargetTrue(TargetTrue), TargetFalse(TargetFalse), Label(Label) {} | 271 TargetTrue(TargetTrue), TargetFalse(TargetFalse), Label(Label) {} |
272 | 272 |
273 bool InstARM32Br::optimizeBranch(const CfgNode *NextNode) { | 273 bool InstARM32Br::optimizeBranch(const CfgNode *NextNode) { |
274 // If there is no next block, then there can be no fallthrough to | 274 // If there is no next block, then there can be no fallthrough to optimize. |
275 // optimize. | |
276 if (NextNode == nullptr) | 275 if (NextNode == nullptr) |
277 return false; | 276 return false; |
278 // Intra-block conditional branches can't be optimized. | 277 // Intra-block conditional branches can't be optimized. |
279 if (Label) | 278 if (Label) |
280 return false; | 279 return false; |
281 // If there is no fallthrough node, such as a non-default case label | 280 // If there is no fallthrough node, such as a non-default case label for a |
282 // for a switch instruction, then there is no opportunity to | 281 // switch instruction, then there is no opportunity to optimize. |
283 // optimize. | |
284 if (getTargetFalse() == nullptr) | 282 if (getTargetFalse() == nullptr) |
285 return false; | 283 return false; |
286 | 284 |
287 // Unconditional branch to the next node can be removed. | 285 // Unconditional branch to the next node can be removed. |
288 if (isUnconditionalBranch() && getTargetFalse() == NextNode) { | 286 if (isUnconditionalBranch() && getTargetFalse() == NextNode) { |
289 assert(getTargetTrue() == nullptr); | 287 assert(getTargetTrue() == nullptr); |
290 setDeleted(); | 288 setDeleted(); |
291 return true; | 289 return true; |
292 } | 290 } |
293 // If the fallthrough is to the next node, set fallthrough to nullptr | 291 // If the fallthrough is to the next node, set fallthrough to nullptr to |
294 // to indicate. | 292 // indicate. |
295 if (getTargetFalse() == NextNode) { | 293 if (getTargetFalse() == NextNode) { |
296 TargetFalse = nullptr; | 294 TargetFalse = nullptr; |
297 return true; | 295 return true; |
298 } | 296 } |
299 // If TargetTrue is the next node, and TargetFalse is not nullptr | 297 // If TargetTrue is the next node, and TargetFalse is not nullptr (which was |
300 // (which was already tested above), then invert the branch | 298 // already tested above), then invert the branch condition, swap the targets, |
301 // condition, swap the targets, and set new fallthrough to nullptr. | 299 // and set new fallthrough to nullptr. |
302 if (getTargetTrue() == NextNode) { | 300 if (getTargetTrue() == NextNode) { |
303 assert(Predicate != CondARM32::AL); | 301 assert(Predicate != CondARM32::AL); |
304 setPredicate(getOppositeCondition(getPredicate())); | 302 setPredicate(getOppositeCondition(getPredicate())); |
305 TargetTrue = getTargetFalse(); | 303 TargetTrue = getTargetFalse(); |
306 TargetFalse = nullptr; | 304 TargetFalse = nullptr; |
307 return true; | 305 return true; |
308 } | 306 } |
309 return false; | 307 return false; |
310 } | 308 } |
311 | 309 |
(...skipping 19 matching lines...) Expand all Loading... |
331 InstARM32Label::InstARM32Label(Cfg *Func, TargetARM32 *Target) | 329 InstARM32Label::InstARM32Label(Cfg *Func, TargetARM32 *Target) |
332 : InstARM32(Func, InstARM32::Label, 0, nullptr), | 330 : InstARM32(Func, InstARM32::Label, 0, nullptr), |
333 Number(Target->makeNextLabelNumber()) {} | 331 Number(Target->makeNextLabelNumber()) {} |
334 | 332 |
335 IceString InstARM32Label::getName(const Cfg *Func) const { | 333 IceString InstARM32Label::getName(const Cfg *Func) const { |
336 return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number); | 334 return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number); |
337 } | 335 } |
338 | 336 |
339 InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) | 337 InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) |
340 : InstARM32(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { | 338 : InstARM32(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { |
341 // Track modifications to Dests separately via FakeDefs. | 339 // Track modifications to Dests separately via FakeDefs. Also, a pop |
342 // Also, a pop instruction affects the stack pointer and so it should not | 340 // instruction affects the stack pointer and so it should not be allowed to |
343 // be allowed to be automatically dead-code eliminated. This is automatic | 341 // be automatically dead-code eliminated. This is automatic since we leave |
344 // since we leave the Dest as nullptr. | 342 // the Dest as nullptr. |
345 } | 343 } |
346 | 344 |
347 InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) | 345 InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) |
348 : InstARM32(Func, InstARM32::Push, Srcs.size(), nullptr) { | 346 : InstARM32(Func, InstARM32::Push, Srcs.size(), nullptr) { |
349 for (Variable *Source : Srcs) | 347 for (Variable *Source : Srcs) |
350 addSource(Source); | 348 addSource(Source); |
351 } | 349 } |
352 | 350 |
353 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) | 351 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) |
354 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { | 352 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 if (!BuildDefs::dump()) | 442 if (!BuildDefs::dump()) |
445 return; | 443 return; |
446 Ostream &Str = Func->getContext()->getStrEmit(); | 444 Ostream &Str = Func->getContext()->getStrEmit(); |
447 assert(getSrcSize() == 1); | 445 assert(getSrcSize() == 1); |
448 Variable *Dest = getDest(); | 446 Variable *Dest = getDest(); |
449 if (Dest->hasReg()) { | 447 if (Dest->hasReg()) { |
450 IceString ActualOpcode = Opcode; | 448 IceString ActualOpcode = Opcode; |
451 Operand *Src0 = getSrc(0); | 449 Operand *Src0 = getSrc(0); |
452 if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { | 450 if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { |
453 if (!Src0V->hasReg()) { | 451 if (!Src0V->hasReg()) { |
454 // Always use the whole stack slot. A 32-bit load has a larger range | 452 // Always use the whole stack slot. A 32-bit load has a larger range of |
455 // of offsets than 16-bit, etc. | 453 // offsets than 16-bit, etc. |
456 ActualOpcode = IceString("ldr"); | 454 ActualOpcode = IceString("ldr"); |
457 } | 455 } |
458 } else { | 456 } else { |
459 if (llvm::isa<OperandARM32Mem>(Src0)) | 457 if (llvm::isa<OperandARM32Mem>(Src0)) |
460 ActualOpcode = IceString("ldr") + getWidthString(Dest->getType()); | 458 ActualOpcode = IceString("ldr") + getWidthString(Dest->getType()); |
461 } | 459 } |
462 Str << "\t" << ActualOpcode << getPredicate() << "\t"; | 460 Str << "\t" << ActualOpcode << getPredicate() << "\t"; |
463 getDest()->emit(Func); | 461 getDest()->emit(Func); |
464 Str << ", "; | 462 Str << ", "; |
465 getSrc(0)->emit(Func); | 463 getSrc(0)->emit(Func); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 } | 584 } |
587 } | 585 } |
588 } | 586 } |
589 | 587 |
590 void InstARM32Call::emit(const Cfg *Func) const { | 588 void InstARM32Call::emit(const Cfg *Func) const { |
591 if (!BuildDefs::dump()) | 589 if (!BuildDefs::dump()) |
592 return; | 590 return; |
593 Ostream &Str = Func->getContext()->getStrEmit(); | 591 Ostream &Str = Func->getContext()->getStrEmit(); |
594 assert(getSrcSize() == 1); | 592 assert(getSrcSize() == 1); |
595 if (llvm::isa<ConstantInteger32>(getCallTarget())) { | 593 if (llvm::isa<ConstantInteger32>(getCallTarget())) { |
596 // This shouldn't happen (typically have to copy the full 32-bits | 594 // This shouldn't happen (typically have to copy the full 32-bits to a |
597 // to a register and do an indirect jump). | 595 // register and do an indirect jump). |
598 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); | 596 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); |
599 } else if (const auto CallTarget = | 597 } else if (const auto CallTarget = |
600 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { | 598 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { |
601 // Calls only have 24-bits, but the linker should insert veneers to | 599 // Calls only have 24-bits, but the linker should insert veneers to extend |
602 // extend the range if needed. | 600 // the range if needed. |
603 Str << "\t" | 601 Str << "\t" |
604 << "bl" | 602 << "bl" |
605 << "\t"; | 603 << "\t"; |
606 CallTarget->emitWithoutPrefix(Func->getTarget()); | 604 CallTarget->emitWithoutPrefix(Func->getTarget()); |
607 } else { | 605 } else { |
608 Str << "\t" | 606 Str << "\t" |
609 << "blx" | 607 << "blx" |
610 << "\t"; | 608 << "\t"; |
611 getCallTarget()->emit(Func); | 609 getCallTarget()->emit(Func); |
612 } | 610 } |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1082 if (getShiftOp() != kNoShift) { | 1080 if (getShiftOp() != kNoShift) { |
1083 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; | 1081 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
1084 if (Func) | 1082 if (Func) |
1085 getShiftAmt()->dump(Func); | 1083 getShiftAmt()->dump(Func); |
1086 else | 1084 else |
1087 getShiftAmt()->dump(Str); | 1085 getShiftAmt()->dump(Str); |
1088 } | 1086 } |
1089 } | 1087 } |
1090 | 1088 |
1091 } // end of namespace Ice | 1089 } // end of namespace Ice |
OLD | NEW |