| 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 |