Commit 13f0ca32 by Jaydeep Patil Committed by Jim Stichnoth

Delete unconditional branch to the next node.

R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2275883002 . Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
parent 519fe047
...@@ -200,6 +200,46 @@ InstMIPS32Br::InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, ...@@ -200,6 +200,46 @@ InstMIPS32Br::InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue,
addSource(Src1); addSource(Src1);
} }
CondMIPS32::Cond InstMIPS32::getOppositeCondition(CondMIPS32::Cond Cond) {
return InstMIPS32CondAttributes[Cond].Opposite;
}
bool InstMIPS32Br::optimizeBranch(const CfgNode *NextNode) {
// If there is no next block, then there can be no fallthrough to optimize.
if (NextNode == nullptr)
return false;
// Intra-block conditional branches can't be optimized.
if (Label != nullptr)
return false;
// Unconditional branch to the next node can be removed.
if (isUnconditionalBranch() && getTargetFalse() == NextNode) {
assert(getTargetTrue() == nullptr);
setDeleted();
return true;
}
// 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 (getTargetTrue() == nullptr)
return false;
// If the fallthrough is to the next node, set fallthrough to nullptr to
// indicate.
if (getTargetTrue() == NextNode) {
TargetTrue = nullptr;
return true;
}
// If TargetFalse is the next node, and TargetTrue is not nullptr
// then invert the branch condition, swap the targets, and set new
// fallthrough to nullptr.
if (getTargetFalse() == NextNode) {
assert(Predicate != CondMIPS32::AL);
setPredicate(getOppositeCondition(getPredicate()));
TargetFalse = getTargetTrue();
TargetTrue = nullptr;
return true;
}
return false;
}
bool InstMIPS32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { bool InstMIPS32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
bool Found = false; bool Found = false;
if (TargetFalse == OldNode) { if (TargetFalse == OldNode) {
...@@ -419,6 +459,11 @@ void InstMIPS32Br::emit(const Cfg *Func) const { ...@@ -419,6 +459,11 @@ void InstMIPS32Br::emit(const Cfg *Func) const {
} }
} }
Str << getTargetFalse()->getAsmName(); Str << getTargetFalse()->getAsmName();
if (getTargetTrue()) {
Str << "\n\t"
<< "b"
<< "\t" << getTargetTrue()->getAsmName();
}
} }
} }
} }
...@@ -439,6 +484,11 @@ void InstMIPS32Br::dump(const Cfg *Func) const { ...@@ -439,6 +484,11 @@ void InstMIPS32Br::dump(const Cfg *Func) const {
dumpSources(Func); dumpSources(Func);
Str << ", "; Str << ", ";
Str << getTargetFalse()->getAsmName(); Str << getTargetFalse()->getAsmName();
if (getTargetTrue()) {
Str << "\n\t"
<< "b"
<< "\t" << getTargetTrue()->getAsmName();
}
} }
} }
} }
......
...@@ -201,6 +201,8 @@ public: ...@@ -201,6 +201,8 @@ public:
static const char *getWidthString(Type Ty); static const char *getWidthString(Type Ty);
CondMIPS32::Cond getOppositeCondition(CondMIPS32::Cond Cond);
void dump(const Cfg *Func) const override; void dump(const Cfg *Func) const override;
void dumpOpcode(Ostream &Str, const char *Opcode, Type Ty) const { void dumpOpcode(Ostream &Str, const char *Opcode, Type Ty) const {
...@@ -669,7 +671,9 @@ public: ...@@ -669,7 +671,9 @@ public:
const CfgNode *getTargetTrue() const { return TargetTrue; } const CfgNode *getTargetTrue() const { return TargetTrue; }
const CfgNode *getTargetFalse() const { return TargetFalse; } const CfgNode *getTargetFalse() const { return TargetFalse; }
CondMIPS32::Cond getPredicate() const { return Predicate; }
void setPredicate(CondMIPS32::Cond Pred) { Predicate = Pred; }
bool optimizeBranch(const CfgNode *NextNode);
bool isUnconditionalBranch() const override { bool isUnconditionalBranch() const override {
return Predicate == CondMIPS32::AL; return Predicate == CondMIPS32::AL;
} }
...@@ -694,7 +698,7 @@ private: ...@@ -694,7 +698,7 @@ private:
const CfgNode *TargetTrue; const CfgNode *TargetTrue;
const CfgNode *TargetFalse; const CfgNode *TargetFalse;
const InstMIPS32Label *Label; // Intra-block branch target const InstMIPS32Label *Label; // Intra-block branch target
const CondMIPS32::Cond Predicate; CondMIPS32::Cond Predicate;
}; };
class InstMIPS32Call : public InstMIPS32 { class InstMIPS32Call : public InstMIPS32 {
......
...@@ -396,9 +396,9 @@ void TargetMIPS32::translateOm1() { ...@@ -396,9 +396,9 @@ void TargetMIPS32::translateOm1() {
} }
bool TargetMIPS32::doBranchOpt(Inst *Instr, const CfgNode *NextNode) { bool TargetMIPS32::doBranchOpt(Inst *Instr, const CfgNode *NextNode) {
(void)Instr; if (auto *Br = llvm::dyn_cast<InstMIPS32Br>(Instr)) {
(void)NextNode; return Br->optimizeBranch(NextNode);
UnimplementedError(getFlags()); }
return false; return false;
} }
......
...@@ -27,6 +27,24 @@ ...@@ -27,6 +27,24 @@
; RUN: --command FileCheck \ ; RUN: --command FileCheck \
; RUN: --check-prefix ARM32OM1 %s ; RUN: --check-prefix ARM32OM1 %s
; TODO(jaydeep.patil): Using --skip-unimplemented for MIPS32
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target mips32 -i %s --args -O2 \
; RUN: --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32O2 %s
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target mips32 -i %s --args -Om1 \
; RUN: --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck \
; RUN: --check-prefix MIPS32OM1 %s
declare void @dummy() declare void @dummy()
; An unconditional branch to the next block should be removed. ; An unconditional branch to the next block should be removed.
...@@ -59,6 +77,22 @@ next: ...@@ -59,6 +77,22 @@ next:
; ARM32OM1-NEXT: b ; ARM32OM1-NEXT: b
; ARM32OM1-NEXT: bl {{.*}} dummy ; ARM32OM1-NEXT: bl {{.*}} dummy
; MIPS32O2-LABEL: testUncondToNextBlock
; MIPS32O2: jal {{.*}} dummy
; MIPS32O2-NEXT: nop
; MIPS32O2-LABEL: <.LtestUncondToNextBlock$next>:
; MIPS32O2-NEXT: jal {{.*}} dummy
; MIPS32O2-NEXT: nop
; MIPS32OM1-LABEL: testUncondToNextBlock
; MIPS32OM1: jal {{.*}} dummy
; MIPS32OM1-NEXT: nop
; MIPS32OM1-NEXT: b {{.*}} <.LtestUncondToNextBlock$next>
; MIPS32OM1-NEXT: nop
; MIPS32OM1-LABEL: <.LtestUncondToNextBlock$next>:
; MIPS32OM1-NEXT: jal {{.*}} dummy
; MIPS32OM1-NEXT: nop
; For a conditional branch with a fallthrough to the next block, the ; For a conditional branch with a fallthrough to the next block, the
; fallthrough branch should be removed. ; fallthrough branch should be removed.
define internal void @testCondFallthroughToNextBlock(i32 %arg) { define internal void @testCondFallthroughToNextBlock(i32 %arg) {
...@@ -112,6 +146,41 @@ target: ...@@ -112,6 +146,41 @@ target:
; ARM32OM1: bl ; ARM32OM1: bl
; ARM32OM1: bx lr ; ARM32OM1: bx lr
; MIPS32O2-LABEL: testCondFallthroughToNextBlock
; MIPS32O2: li {{.*}},123
; MIPS32O2: slt {{.*}},{{.*}},{{.*}}
; MIPS32O2: beqz
; MIPS32O2: nop
; MIPS32O2: .LtestCondFallthroughToNextBlock$fallthrough
; MIPS32O2: jal {{.*}} dummy
; MIPS32O2: nop
; MIPS32O2: jr
; MIPS32O2: nop
; MIPS32O2: .LtestCondFallthroughToNextBlock$target
; MIPS32O2: jal {{.*}} dummy
; MIPS32O2: nop
; MIPS32O2: jr
; MIPS32O2: nop
; MIPS32OM1-LABEL: testCondFallthroughToNextBlock
; MIPS32OM1: li {{.*}},123
; MIPS32OM1: slt {{.*}},{{.*}},{{.*}}
; MIPS32OM1: xori {{.*}},{{.*}},{{.*}}
; MIPS32OM1: beqz
; MIPS32OM1: nop
; MIPS32OM1: b
; MIPS32OM1: nop
; MIPS32OM1: .LtestCondFallthroughToNextBlock$fallthrough
; MIPS32OM1: jal {{.*}} dummy
; MIPS32OM1: nop
; MIPS32OM1: jr
; MIPS32OM1: nop
; MIPS32OM1: .LtestCondFallthroughToNextBlock$target
; MIPS32OM1: jal {{.*}} dummy
; MIPS32OM1: nop
; MIPS32OM1: jr
; MIPS32OM1: nop
; For a conditional branch with the next block as the target and a ; For a conditional branch with the next block as the target and a
; different block as the fallthrough, the branch condition should be ; different block as the fallthrough, the branch condition should be
; inverted, the fallthrough block changed to the target, and the ; inverted, the fallthrough block changed to the target, and the
...@@ -168,6 +237,41 @@ target: ...@@ -168,6 +237,41 @@ target:
; ARM32OM1: bl ; ARM32OM1: bl
; ARM32OM1: bx lr ; ARM32OM1: bx lr
; MIPS32O2-LABEL: testCondTargetNextBlock
; MIPS32O2: li {{.*}},123
; MIPS32O2: slt {{.*}},{{.*}},{{.*}}
; MIPS32O2: bnez
; MIPS32O2: nop
; MIPS32O2: .LtestCondTargetNextBlock$fallthrough
; MIPS32O2: jal {{.*}} dummy
; MIPS32O2: nop
; MIPS32O2: jr
; MIPS32O2: nop
; MIPS32O2: .LtestCondTargetNextBlock$target
; MIPS32O2: jal {{.*}} dummy
; MIPS32O2: nop
; MIPS32O2: jr
; MIPS32O2: nop
; MIPS32OM1-LABEL: testCondTargetNextBlock
; MIPS32OM1: li {{.*}},123
; MIPS32OM1: slt {{.*}},{{.*}},{{.*}}
; MIPS32OM1: xori {{.*}},{{.*}},{{.*}}
; MIPS32OM1: beqz
; MIPS32OM1: nop
; MIPS32OM1: b
; MIPS32OM1: nop
; MIPS32OM1: .LtestCondTargetNextBlock$fallthrough
; MIPS32OM1: jal {{.*}} dummy
; MIPS32OM1: nop
; MIPS32OM1: jr
; MIPS32OM1: nop
; MIPS32OM1: .LtestCondTargetNextBlock$target
; MIPS32OM1: jal {{.*}} dummy
; MIPS32OM1: nop
; MIPS32OM1: jr
; MIPS32OM1: nop
; Unconditional branches to the block after a contracted block should be ; Unconditional branches to the block after a contracted block should be
; removed. ; removed.
define internal void @testUncondToBlockAfterContract() { define internal void @testUncondToBlockAfterContract() {
...@@ -201,3 +305,12 @@ target: ...@@ -201,3 +305,12 @@ target:
; ARM32OM1: bl {{.*}} dummy ; ARM32OM1: bl {{.*}} dummy
; ARM32OM1-NEXT: b ; ARM32OM1-NEXT: b
; ARM32OM1-NEXT: bl {{.*}} dummy ; ARM32OM1-NEXT: bl {{.*}} dummy
; MIPS32O2-LABEL: testUncondToBlockAfterContract
; MIPS32O2: jal {{.*}} dummy
; MIPS32O2: .LtestUncondToBlockAfterContract$target
; MIPS32OM1-LABEL: testUncondToBlockAfterContract
; MIPS32OM1: jal {{.*}} dummy
; MIPS32OM1: b
; MIPS32OM1: .LtestUncondToBlockAfterContract$target
...@@ -22,10 +22,12 @@ branch2: ...@@ -22,10 +22,12 @@ branch2:
ret i32 2 ret i32 2
} }
; COMMON-LABEL: cond_br_eq ; COMMON-LABEL: cond_br_eq
; MIPS32: bne ; MIPS32: bne {{.*}} .Lcond_br_eq$branch2
; MIPS32-NEXT: .Lcond_br_eq$branch1
; MIPS32-OM1: xor ; MIPS32-OM1: xor
; MIPS32-OM1: sltiu {{.*}}, {{.*}}, 1 ; MIPS32-OM1: sltiu {{.*}}, {{.*}}, 1
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_eq$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_eq$branch1
define internal i32 @cond_br_ne(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_ne(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -37,10 +39,12 @@ branch2: ...@@ -37,10 +39,12 @@ branch2:
ret i32 2 ret i32 2
} }
; COMMON-LABEL: cond_br_ne ; COMMON-LABEL: cond_br_ne
; MIPS32: beq ; MIPS32: beq {{.*}} .Lcond_br_ne$branch2
; MIPS32-NEXT: .Lcond_br_ne$branch1
; MIPS32-OM1: xor ; MIPS32-OM1: xor
; MIPS32-OM1: sltu {{.*}}, $zero, {{.*}} ; MIPS32-OM1: sltu {{.*}}, $zero, {{.*}}
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_ne$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_ne$branch1
define internal i32 @cond_br_slt(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_slt(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -53,9 +57,11 @@ branch2: ...@@ -53,9 +57,11 @@ branch2:
} }
; COMMON-LABEL: cond_br_slt ; COMMON-LABEL: cond_br_slt
; MIPS32: slt ; MIPS32: slt
; MIPS32: beqz ; MIPS32: beqz {{.*}} .Lcond_br_slt$branch2
; MIPS32-NEXT: .Lcond_br_slt$branch1
; MIPS32-OM1: slt ; MIPS32-OM1: slt
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_slt$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_slt$branch1
define internal i32 @cond_br_sle(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_sle(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -68,10 +74,12 @@ branch2: ...@@ -68,10 +74,12 @@ branch2:
} }
; COMMON-LABEL: cond_br_sle ; COMMON-LABEL: cond_br_sle
; MIPS32: slt ; MIPS32: slt
; MIPS32: bnez ; MIPS32: bnez {{.*}} .Lcond_br_sle$branch2
; MIPS32-NEXT: .Lcond_br_sle$branch1
; MIPS32-OM1: slt ; MIPS32-OM1: slt
; MIPS32-OM1: xori {{.*}}, {{.*}}, 1 ; MIPS32-OM1: xori {{.*}}, {{.*}}, 1
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_sle$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_sle$branch1
define internal i32 @cond_br_sgt(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_sgt(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -84,9 +92,11 @@ branch2: ...@@ -84,9 +92,11 @@ branch2:
} }
; COMMON-LABEL: cond_br_sgt ; COMMON-LABEL: cond_br_sgt
; MIPS32: slt ; MIPS32: slt
; MIPS32: beqz ; MIPS32-NEXT: beqz {{.*}} .Lcond_br_sgt$branch2
; MIPS32-NEXT: .Lcond_br_sgt$branch1
; MIPS32-OM1: slt ; MIPS32-OM1: slt
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_sgt$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_sgt$branch1
define internal i32 @cond_br_sge(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_sge(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -99,10 +109,12 @@ branch2: ...@@ -99,10 +109,12 @@ branch2:
} }
; COMMON-LABEL: cond_br_sge ; COMMON-LABEL: cond_br_sge
; MIPS32: slt ; MIPS32: slt
; MIPS32: bnez ; MIPS32: bnez {{.*}} .Lcond_br_sge$branch2
; MIPS32-NEXT: .Lcond_br_sge$branch1
; MIPS32-OM1: slt ; MIPS32-OM1: slt
; MIPS32-OM1: xori {{.*}}, {{.*}}, 1 ; MIPS32-OM1: xori {{.*}}, {{.*}}, 1
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_sge$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_sge$branch1
define internal i32 @cond_br_ugt(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_ugt(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -115,9 +127,11 @@ branch2: ...@@ -115,9 +127,11 @@ branch2:
} }
; COMMON-LABEL: cond_br_ugt ; COMMON-LABEL: cond_br_ugt
; MIPS32: sltu ; MIPS32: sltu
; MIPS32: beqz ; MIPS32: beqz {{.*}} .Lcond_br_ugt$branch2
; MIPS32-NEXT: .Lcond_br_ugt$branch1
; MIPS32-OM1: sltu ; MIPS32-OM1: sltu
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_ugt$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_ugt$branch1
define internal i32 @cond_br_uge(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_uge(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -130,10 +144,12 @@ branch2: ...@@ -130,10 +144,12 @@ branch2:
} }
; COMMON-LABEL: cond_br_uge ; COMMON-LABEL: cond_br_uge
; MIPS32: sltu ; MIPS32: sltu
; MIPS32: bnez ; MIPS32: bnez {{.*}} .Lcond_br_uge$branch2
; MIPS32-NEXT: .Lcond_br_uge$branch1
; MIPS32-OM1: sltu ; MIPS32-OM1: sltu
; MIPS32-OM1: xori {{.*}}, {{.*}}, 1 ; MIPS32-OM1: xori {{.*}}, {{.*}}, 1
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_uge$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_uge$branch1
define internal i32 @cond_br_ult(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_ult(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -146,9 +162,11 @@ branch2: ...@@ -146,9 +162,11 @@ branch2:
} }
; COMMON-LABEL: cond_br_ult ; COMMON-LABEL: cond_br_ult
; MIPS32: sltu ; MIPS32: sltu
; MIPS32: beqz ; MIPS32: beqz {{.*}} .Lcond_br_ult$branch2
; MIPS32-NEXT: .Lcond_br_ult$branch1
; MIPS32-OM1: sltu ; MIPS32-OM1: sltu
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_ult$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_ult$branch1
define internal i32 @cond_br_ule(i32 %arg1, i32 %arg2) { define internal i32 @cond_br_ule(i32 %arg1, i32 %arg2) {
entry: entry:
...@@ -161,7 +179,9 @@ branch2: ...@@ -161,7 +179,9 @@ branch2:
} }
; COMMON-LABEL: cond_br_ule ; COMMON-LABEL: cond_br_ule
; MIPS32: sltu ; MIPS32: sltu
; MIPS32: bnez ; MIPS32: bnez {{.*}} .Lcond_br_ule$branch2
; MIPS32-NEXT: .Lcond_br_ule$branch1
; MIPS32-OM1: sltu ; MIPS32-OM1: sltu
; MIPS32-OM1: xori {{.*}}, {{.*}}, 1 ; MIPS32-OM1: xori {{.*}}, {{.*}}, 1
; MIPS32-OM1: beqz ; MIPS32-OM1: beqz {{.*}} .Lcond_br_ule$branch2
; MIPS32-OM1-NEXT: b .Lcond_br_ule$branch1
...@@ -23,7 +23,6 @@ target: ...@@ -23,7 +23,6 @@ target:
} }
; MIPS32-LABEL: uncond1 ; MIPS32-LABEL: uncond1
; MIPS32: b {{[0-9a-f]+}} <.Luncond1$target>
; MIPS32: <.Luncond1$target>: ; MIPS32: <.Luncond1$target>:
; MIPS32: li ; MIPS32: li
; MIPS32: addu ; MIPS32: addu
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment