Index: src/IceInstARM32.cpp |
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp |
index 67f0fd4ad7bb8c336a64161f230d2708ebdeeddb..349d928ac4acf50c9cb90fe8d20d40d46ad3edb3 100644 |
--- a/src/IceInstARM32.cpp |
+++ b/src/IceInstARM32.cpp |
@@ -47,32 +47,58 @@ const struct InstARM32ShiftAttributes_ { |
#undef X |
}; |
+const struct InstARM32CondAttributes_ { |
+ CondARM32::Cond Opposite; |
+ const char *EmitString; |
+} InstARM32CondAttributes[] = { |
+#define X(tag, encode, opp, emit) \ |
+ { CondARM32::opp, emit } \ |
+ , |
+ ICEINSTARM32COND_TABLE |
+#undef X |
+}; |
+ |
} // end of anonymous namespace |
const char *InstARM32::getWidthString(Type Ty) { |
return TypeARM32Attributes[Ty].WidthString; |
} |
-void emitTwoAddr(const char *Opcode, const Inst *Inst, const Cfg *Func) { |
+const char *InstARM32Pred::predString(CondARM32::Cond Pred) { |
+ return InstARM32CondAttributes[Pred].EmitString; |
+} |
+ |
+void InstARM32Pred::dumpOpcodePred(Ostream &Str, const char *Opcode, |
+ Type Ty) const { |
+ Str << Opcode << getPredicate() << "." << Ty; |
+} |
+ |
+CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) { |
+ return InstARM32CondAttributes[Cond].Opposite; |
+} |
+ |
+void emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst, |
+ const Cfg *Func) { |
if (!ALLOW_DUMP) |
return; |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(Inst->getSrcSize() == 2); |
Variable *Dest = Inst->getDest(); |
assert(Dest == Inst->getSrc(0)); |
- Str << "\t" << Opcode << "\t"; |
+ Str << "\t" << Opcode << Inst->getPredicate() << "\t"; |
Dest->emit(Func); |
Str << ", "; |
Inst->getSrc(1)->emit(Func); |
} |
-void emitThreeAddr(const char *Opcode, const Inst *Inst, const Cfg *Func, |
- bool SetFlags) { |
+void emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst, |
+ const Cfg *Func, bool SetFlags) { |
if (!ALLOW_DUMP) |
return; |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(Inst->getSrcSize() == 2); |
- Str << "\t" << Opcode << (SetFlags ? "s" : "") << "\t"; |
+ Str << "\t" << Opcode << (SetFlags ? "s" : "") << Inst->getPredicate() |
+ << "\t"; |
Inst->getDest()->emit(Func); |
Str << ", "; |
Inst->getSrc(0)->emit(Func); |
@@ -154,14 +180,81 @@ OperandARM32FlexReg::OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, |
Vars[1] = ShiftVar; |
} |
-InstARM32Ldr::InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem) |
- : InstARM32(Func, InstARM32::Ldr, 1, Dest) { |
+InstARM32Br::InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, |
+ const CfgNode *TargetFalse, CondARM32::Cond Pred) |
+ : InstARM32Pred(Func, InstARM32::Br, 0, nullptr, Pred), |
+ TargetTrue(TargetTrue), TargetFalse(TargetFalse) {} |
+ |
+bool InstARM32Br::optimizeBranch(const CfgNode *NextNode) { |
+ // If there is no next block, then there can be no fallthrough to |
+ // optimize. |
+ if (NextNode == nullptr) |
+ return false; |
+ // If there is no fallthrough node, such as a non-default case label |
+ // for a switch instruction, then there is no opportunity to |
+ // optimize. |
+ if (getTargetFalse() == nullptr) |
+ return false; |
+ |
+ // Unconditional branch to the next node can be removed. |
+ if (isUnconditionalBranch() && getTargetFalse() == NextNode) { |
+ assert(getTargetTrue() == nullptr); |
+ setDeleted(); |
+ return true; |
+ } |
+ // If the fallthrough is to the next node, set fallthrough to nullptr |
+ // to indicate. |
+ if (getTargetFalse() == NextNode) { |
+ TargetFalse = nullptr; |
+ return true; |
+ } |
+ // If TargetTrue is the next node, and TargetFalse is not nullptr |
+ // (which was already tested above), then invert the branch |
+ // condition, swap the targets, and set new fallthrough to nullptr. |
+ if (getTargetTrue() == NextNode) { |
+ assert(Predicate != CondARM32::AL); |
+ setPredicate(getOppositeCondition(getPredicate())); |
+ TargetTrue = getTargetFalse(); |
+ TargetFalse = nullptr; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool InstARM32Br::repointEdge(CfgNode *OldNode, CfgNode *NewNode) { |
+ if (TargetFalse == OldNode) { |
+ TargetFalse = NewNode; |
+ return true; |
+ } else if (TargetTrue == OldNode) { |
+ TargetTrue = NewNode; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget) |
+ : InstARM32(Func, InstARM32::Call, 1, Dest) { |
+ HasSideEffects = true; |
+ addSource(CallTarget); |
+} |
+ |
+InstARM32Cmp::InstARM32Cmp(Cfg *Func, Variable *Src1, Operand *Src2, |
+ CondARM32::Cond Predicate) |
+ : InstARM32Pred(Func, InstARM32::Cmp, 2, nullptr, Predicate) { |
+ addSource(Src1); |
+ addSource(Src2); |
+} |
+ |
+InstARM32Ldr::InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem, |
+ CondARM32::Cond Predicate) |
+ : InstARM32Pred(Func, InstARM32::Ldr, 1, Dest, Predicate) { |
addSource(Mem); |
} |
InstARM32Mla::InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, |
- Variable *Src1, Variable *Acc) |
- : InstARM32(Func, InstARM32::Mla, 3, Dest) { |
+ Variable *Src1, Variable *Acc, |
+ CondARM32::Cond Predicate) |
+ : InstARM32Pred(Func, InstARM32::Mla, 3, Dest, Predicate) { |
addSource(Src0); |
addSource(Src1); |
addSource(Acc); |
@@ -175,8 +268,9 @@ InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) |
} |
InstARM32Umull::InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, |
- Variable *Src0, Variable *Src1) |
- : InstARM32(Func, InstARM32::Umull, 2, DestLo), |
+ Variable *Src0, Variable *Src1, |
+ CondARM32::Cond Predicate) |
+ : InstARM32Pred(Func, InstARM32::Umull, 2, DestLo, Predicate), |
// DestHi is expected to have a FakeDef inserted by the lowering code. |
DestHi(DestHi) { |
addSource(Src0); |
@@ -197,6 +291,7 @@ template <> const char *InstARM32Adc::Opcode = "adc"; |
template <> const char *InstARM32Add::Opcode = "add"; |
template <> const char *InstARM32And::Opcode = "and"; |
template <> const char *InstARM32Eor::Opcode = "eor"; |
+template <> const char *InstARM32Lsl::Opcode = "lsl"; |
template <> const char *InstARM32Mul::Opcode = "mul"; |
template <> const char *InstARM32Orr::Opcode = "orr"; |
template <> const char *InstARM32Sbc::Opcode = "sbc"; |
@@ -218,8 +313,7 @@ template <> void InstARM32Mov::emit(const Cfg *Func) const { |
Variable *Dest = getDest(); |
if (Dest->hasReg()) { |
Str << "\t" |
- << "mov" |
- << "\t"; |
+ << "mov" << getPredicate() << "\t"; |
getDest()->emit(Func); |
Str << ", "; |
getSrc(0)->emit(Func); |
@@ -227,8 +321,7 @@ template <> void InstARM32Mov::emit(const Cfg *Func) const { |
Variable *Src0 = llvm::cast<Variable>(getSrc(0)); |
assert(Src0->hasReg()); |
Str << "\t" |
- << "str" |
- << "\t"; |
+ << "str" << getPredicate() << "\t"; |
Src0->emit(Func); |
Str << ", "; |
Dest->emit(Func); |
@@ -241,6 +334,115 @@ template <> void InstARM32Mov::emitIAS(const Cfg *Func) const { |
llvm_unreachable("Not yet implemented"); |
} |
+void InstARM32Br::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ Str << "\t" |
+ << "b" << getPredicate() << "\t"; |
+ if (isUnconditionalBranch()) { |
+ Str << getTargetFalse()->getAsmName(); |
+ } else { |
+ Str << getTargetTrue()->getAsmName(); |
+ if (getTargetFalse()) { |
+ Str << "\n\t" |
+ << "b" |
+ << "\t" << getTargetFalse()->getAsmName(); |
+ } |
+ } |
+} |
+ |
+void InstARM32Br::emitIAS(const Cfg *Func) const { |
+ (void)Func; |
+ llvm_unreachable("Not yet implemented"); |
+} |
+ |
+void InstARM32Br::dump(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ Str << "br "; |
+ |
+ if (getPredicate() == CondARM32::AL) { |
+ Str << "label %" << getTargetFalse()->getName(); |
+ return; |
+ } |
+ |
+ Str << getPredicate() << ", label %" << getTargetTrue()->getName(); |
+ if (getTargetFalse()) { |
+ Str << ", label %" << getTargetFalse()->getName(); |
+ } |
+} |
+ |
+void InstARM32Call::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(getSrcSize() == 1); |
+ if (llvm::isa<ConstantInteger32>(getCallTarget())) { |
+ // This shouldn't happen (typically have to copy the full 32-bits |
+ // to a register and do an indirect jump). |
+ llvm::report_fatal_error("ARM32Call to ConstantInteger32"); |
+ } else if (const auto CallTarget = |
+ llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { |
+ // Calls only have 24-bits, but the linker should insert veneers to |
+ // extend the range if needed. |
+ Str << "\t" |
+ << "bl" |
+ << "\t"; |
+ CallTarget->emitWithoutPrefix(Func->getTarget()); |
+ } else { |
+ Str << "\t" |
+ << "blx" |
+ << "\t"; |
+ getCallTarget()->emit(Func); |
+ } |
+ Func->getTarget()->resetStackAdjustment(); |
+} |
+ |
+void InstARM32Call::emitIAS(const Cfg *Func) const { |
+ (void)Func; |
+ llvm_unreachable("Not yet implemented"); |
+} |
+ |
+void InstARM32Call::dump(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ if (getDest()) { |
+ dumpDest(Func); |
+ Str << " = "; |
+ } |
+ Str << "call "; |
+ getCallTarget()->dump(Func); |
+} |
+ |
+void InstARM32Cmp::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(getSrcSize() == 2); |
+ Str << "\t" |
+ << "cmp" << getPredicate() << "\t"; |
+ getSrc(0)->emit(Func); |
+ Str << ", "; |
+ getSrc(1)->emit(Func); |
+} |
+ |
+void InstARM32Cmp::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ (void)Func; |
+ llvm_unreachable("Not yet implemented"); |
+} |
+ |
+void InstARM32Cmp::dump(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpOpcodePred(Str, "cmp", getSrc(0)->getType()); |
+ dumpSources(Func); |
+} |
+ |
void InstARM32Ldr::emit(const Cfg *Func) const { |
if (!ALLOW_DUMP) |
return; |
@@ -249,7 +451,7 @@ void InstARM32Ldr::emit(const Cfg *Func) const { |
assert(getDest()->hasReg()); |
Type Ty = getSrc(0)->getType(); |
Str << "\t" |
- << "ldr" << getWidthString(Ty) << "\t"; |
+ << "ldr" << getWidthString(Ty) << getPredicate() << "\t"; |
getDest()->emit(Func); |
Str << ", "; |
getSrc(0)->emit(Func); |
@@ -266,7 +468,9 @@ void InstARM32Ldr::dump(const Cfg *Func) const { |
return; |
Ostream &Str = Func->getContext()->getStrDump(); |
dumpDest(Func); |
- Str << " = ldr." << getSrc(0)->getType() << " "; |
+ Str << " = "; |
+ dumpOpcodePred(Str, "ldr", getDest()->getType()); |
+ Str << " "; |
dumpSources(Func); |
} |
@@ -277,8 +481,7 @@ void InstARM32Mla::emit(const Cfg *Func) const { |
assert(getSrcSize() == 3); |
assert(getDest()->hasReg()); |
Str << "\t" |
- << "mla" |
- << "\t"; |
+ << "mla" << getPredicate() << "\t"; |
getDest()->emit(Func); |
Str << ", "; |
getSrc(0)->emit(Func); |
@@ -299,7 +502,9 @@ void InstARM32Mla::dump(const Cfg *Func) const { |
return; |
Ostream &Str = Func->getContext()->getStrDump(); |
dumpDest(Func); |
- Str << " = mla." << getSrc(0)->getType() << " "; |
+ Str << " = "; |
+ dumpOpcodePred(Str, "mla", getDest()->getType()); |
+ Str << " "; |
dumpSources(Func); |
} |
@@ -308,7 +513,7 @@ template <> void InstARM32Movw::emit(const Cfg *Func) const { |
return; |
Ostream &Str = Func->getContext()->getStrEmit(); |
assert(getSrcSize() == 1); |
- Str << "\t" << Opcode << "\t"; |
+ Str << "\t" << Opcode << getPredicate() << "\t"; |
getDest()->emit(Func); |
Str << ", "; |
Constant *Src0 = llvm::cast<Constant>(getSrc(0)); |
@@ -327,7 +532,7 @@ template <> void InstARM32Movt::emit(const Cfg *Func) const { |
assert(getSrcSize() == 2); |
Variable *Dest = getDest(); |
Constant *Src1 = llvm::cast<Constant>(getSrc(1)); |
- Str << "\t" << Opcode << "\t"; |
+ Str << "\t" << Opcode << getPredicate() << "\t"; |
Dest->emit(Func); |
Str << ", "; |
if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) { |
@@ -373,8 +578,7 @@ void InstARM32Umull::emit(const Cfg *Func) const { |
assert(getSrcSize() == 2); |
assert(getDest()->hasReg()); |
Str << "\t" |
- << "umull" |
- << "\t"; |
+ << "umull" << getPredicate() << "\t"; |
getDest()->emit(Func); |
Str << ", "; |
DestHi->emit(Func); |
@@ -395,7 +599,9 @@ void InstARM32Umull::dump(const Cfg *Func) const { |
return; |
Ostream &Str = Func->getContext()->getStrDump(); |
dumpDest(Func); |
- Str << " = umull." << getSrc(0)->getType() << " "; |
+ Str << " = "; |
+ dumpOpcodePred(Str, "umull", getDest()->getType()); |
+ Str << " "; |
dumpSources(Func); |
} |