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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 if (!BuildDefs::dump()) | 441 if (!BuildDefs::dump()) |
444 return; | 442 return; |
445 Ostream &Str = Func->getContext()->getStrEmit(); | 443 Ostream &Str = Func->getContext()->getStrEmit(); |
446 assert(getSrcSize() == 1); | 444 assert(getSrcSize() == 1); |
447 Variable *Dest = getDest(); | 445 Variable *Dest = getDest(); |
448 if (Dest->hasReg()) { | 446 if (Dest->hasReg()) { |
449 IceString ActualOpcode = Opcode; | 447 IceString ActualOpcode = Opcode; |
450 Operand *Src0 = getSrc(0); | 448 Operand *Src0 = getSrc(0); |
451 if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { | 449 if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { |
452 if (!Src0V->hasReg()) { | 450 if (!Src0V->hasReg()) { |
453 // Always use the whole stack slot. A 32-bit load has a larger range | 451 // Always use the whole stack slot. A 32-bit load has a larger range of |
454 // of offsets than 16-bit, etc. | 452 // offsets than 16-bit, etc. |
455 ActualOpcode = IceString("ldr"); | 453 ActualOpcode = IceString("ldr"); |
456 } | 454 } |
457 } else { | 455 } else { |
458 if (llvm::isa<OperandARM32Mem>(Src0)) | 456 if (llvm::isa<OperandARM32Mem>(Src0)) |
459 ActualOpcode = IceString("ldr") + getWidthString(Dest->getType()); | 457 ActualOpcode = IceString("ldr") + getWidthString(Dest->getType()); |
460 } | 458 } |
461 Str << "\t" << ActualOpcode << getPredicate() << "\t"; | 459 Str << "\t" << ActualOpcode << getPredicate() << "\t"; |
462 getDest()->emit(Func); | 460 getDest()->emit(Func); |
463 Str << ", "; | 461 Str << ", "; |
464 getSrc(0)->emit(Func); | 462 getSrc(0)->emit(Func); |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 } | 653 } |
656 } | 654 } |
657 } | 655 } |
658 | 656 |
659 void InstARM32Call::emit(const Cfg *Func) const { | 657 void InstARM32Call::emit(const Cfg *Func) const { |
660 if (!BuildDefs::dump()) | 658 if (!BuildDefs::dump()) |
661 return; | 659 return; |
662 Ostream &Str = Func->getContext()->getStrEmit(); | 660 Ostream &Str = Func->getContext()->getStrEmit(); |
663 assert(getSrcSize() == 1); | 661 assert(getSrcSize() == 1); |
664 if (llvm::isa<ConstantInteger32>(getCallTarget())) { | 662 if (llvm::isa<ConstantInteger32>(getCallTarget())) { |
665 // This shouldn't happen (typically have to copy the full 32-bits | 663 // This shouldn't happen (typically have to copy the full 32-bits to a |
666 // to a register and do an indirect jump). | 664 // register and do an indirect jump). |
667 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); | 665 llvm::report_fatal_error("ARM32Call to ConstantInteger32"); |
668 } else if (const auto CallTarget = | 666 } else if (const auto CallTarget = |
669 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { | 667 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { |
670 // Calls only have 24-bits, but the linker should insert veneers to | 668 // Calls only have 24-bits, but the linker should insert veneers to extend |
671 // extend the range if needed. | 669 // the range if needed. |
672 Str << "\t" | 670 Str << "\t" |
673 << "bl" | 671 << "bl" |
674 << "\t"; | 672 << "\t"; |
675 CallTarget->emitWithoutPrefix(Func->getTarget()); | 673 CallTarget->emitWithoutPrefix(Func->getTarget()); |
676 } else { | 674 } else { |
677 Str << "\t" | 675 Str << "\t" |
678 << "blx" | 676 << "blx" |
679 << "\t"; | 677 << "\t"; |
680 getCallTarget()->emit(Func); | 678 getCallTarget()->emit(Func); |
681 } | 679 } |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1151 if (getShiftOp() != kNoShift) { | 1149 if (getShiftOp() != kNoShift) { |
1152 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; | 1150 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
1153 if (Func) | 1151 if (Func) |
1154 getShiftAmt()->dump(Func); | 1152 getShiftAmt()->dump(Func); |
1155 else | 1153 else |
1156 getShiftAmt()->dump(Str); | 1154 getShiftAmt()->dump(Str); |
1157 } | 1155 } |
1158 } | 1156 } |
1159 | 1157 |
1160 } // end of namespace Ice | 1158 } // end of namespace Ice |
OLD | NEW |