Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Remove duplicate branches. #172

Open
wants to merge 2 commits into from

1 participant

@Blei
Collaborator

The DCPU16 backend can generate duplicate branches when generating code
for == comparisons followed by >= or <= comparisons. See the test and
the new optimization pass for details.

This fixes the duplicate IFE instructions reported by #168.

I'm not sure if this is the correct approach or if some easier or more general method
is available. This code will have to be rewritten when we decompose the BRCC instructions
into "real" instructions (#141).

@ghost

mhh As a work around it's okay for now. But I don't think that we should write custom passes for every kind of optimization (okay, it's our first pass for now). We should definitly try to simplify this when we have #141.

@Blei
Collaborator

Yeah, I think so too. I will not mind at all if this will not be merged. I guess it was mostly an exercise to see how such a pass could work, a "real" solution would be much nicer.

@ghost

BUT you can pull this request if you want. (As long as it doesn't introduce heavy bugs ... like our 16bit char change) ;)

Blei added some commits
@Blei Blei Remove duplicate branches.
The DCPU16 backend can generate duplicate branches when generating code
for == comparisons followed by >= or <= comparisons. See the test and
the new optimization pass for details.
38475c2
@Blei Blei Rework hacky loop handling. 4869b34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 17, 2012
  1. @Blei

    Remove duplicate branches.

    Blei authored
    The DCPU16 backend can generate duplicate branches when generating code
    for == comparisons followed by >= or <= comparisons. See the test and
    the new optimization pass for details.
  2. @Blei

    Rework hacky loop handling.

    Blei authored
This page is out of date. Refresh to see the latest.
View
1  lib/Target/DCPU16/CMakeLists.txt
@@ -21,6 +21,7 @@ add_llvm_target(DCPU16CodeGen
DCPU16AsmPrinter.cpp
DCPU16MCInstLower.cpp
DCPU16Peephole.cpp
+ DCPU16DuplicateBranch.cpp
)
add_subdirectory(InstPrinter)
View
3  lib/Target/DCPU16/DCPU16.h
@@ -48,6 +48,9 @@ namespace llvm {
FunctionPass *createDCPU16ISelDag(DCPU16TargetMachine &TM, CodeGenOpt::Level OptLevel);
FunctionPass *createDCPU16Peephole();
+ FunctionPass *createDCPU16DuplicateBranch();
+
+ bool isBR_CC(unsigned Opcode);
} // end namespace llvm;
View
138 lib/Target/DCPU16/DCPU16DuplicateBranch.cpp
@@ -0,0 +1,138 @@
+//===-- DCPU16DuplicateBranch.cpp - DCPU16 Duplicate Branch Optimization --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass optimizes "duplicate" branches. This can happen if we have a
+// sequence as follows (pseudocode):
+//
+// if (a == b) {
+// goto branch1;
+// } else if (a >= b) {
+// goto branch2;
+// }
+//
+// Due to the slightly strange branches of the DCPU16, this will be assembled
+// to:
+//
+// ; a == b
+// IFE A, B
+// SET PC, branch1
+// ; a >= b
+// IFE A, B
+// SET PC, branch2
+// IFG A, B
+// SET PC, branch2
+//
+// As you can see, the second `IFE` is superfluous and can be deleted.
+//
+// CAUTION: Only run this pass just before machine code generation (or any
+// other time when it is guaranteed that the relative position of basic blocks
+// doesn't change anymore)!
+//
+//===----------------------------------------------------------------------===//
+
+#include "DCPU16.h"
+#include "DCPU16TargetMachine.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+
+using namespace llvm;
+
+namespace {
+ class DCPU16DuplicateBranch : public MachineFunctionPass {
+
+ public:
+ static char ID;
+ DCPU16DuplicateBranch() : MachineFunctionPass(ID) { }
+
+ bool runOnMachineFunction(MachineFunction &MF);
+
+ const char *getPassName() const {
+ return "DCPU16 duplicate branch optimization";
+ }
+ };
+}
+
+char DCPU16DuplicateBranch::ID = 0;
+
+static bool isSameMachineOperand(MachineOperand &MO1, MachineOperand &MO2) {
+ if (MO1.isImm()) {
+ if (!MO2.isImm() || MO1.getImm() != MO2.getImm())
+ return false;
+ } else if (MO1.isReg()) {
+ if (!MO2.isReg() || MO1.getReg() != MO2.getReg())
+ return false;
+ } else {
+ assert(false && "Only registers and immediates supported");
+ }
+ return true;
+}
+
+static bool isSameBR_CC(MachineInstr *MI1, MachineInstr *MI2) {
+ assert(isBR_CC(MI1->getOpcode()) && "not a BR_CC");
+ assert(isBR_CC(MI2->getOpcode()) && "not a BR_CC");
+ if (MI1->getOpcode() != MI2->getOpcode())
+ // Different opcode (and as a result different LHS/RHS)
+ return false;
+ if (MI1->getOperand(0).getImm() != MI2->getOperand(0).getImm())
+ // Different comparison/branch code
+ return false;
+ MachineOperand &LHS1 = MI1->getOperand(1);
+ MachineOperand &RHS1 = MI1->getOperand(2);
+ MachineOperand &LHS2 = MI2->getOperand(1);
+ MachineOperand &RHS2 = MI2->getOperand(2);
+ if (!isSameMachineOperand(LHS1, LHS2) || !isSameMachineOperand(RHS1, RHS2))
+ return false;
+
+ return true;
+}
+
+bool DCPU16DuplicateBranch::runOnMachineFunction(MachineFunction &MF) {
+ bool Changed = false;
+ // Kept when iterating over basic blocks. Should be ok, as long as this
+ // pass is only used at the end (i.e. just before machine code generation).
+ MachineInstr *prevBRCC = NULL;
+
+ // Loop over all of the basic blocks.
+ for (MachineFunction::iterator MBBb = MF.begin(), MBBe = MF.end();
+ MBBb != MBBe; ++MBBb) {
+
+ MachineBasicBlock* MBB = MBBb;
+
+ // Traverse the basic block.
+ MachineBasicBlock::iterator MII = MBB->begin(), MIIe = MBB->end();
+ while (MII != MIIe) {
+ MachineInstr *MI = MII;
+
+ if (isBR_CC(MI->getOpcode())) {
+ if (prevBRCC != NULL
+ && isSameBR_CC(prevBRCC, MI)) {
+
+ MachineBasicBlock::iterator oldMII = MII;
+ ++MII;
+ oldMII->eraseFromParent();
+ Changed = true;
+
+ // Step over the additional ++MII;
+ continue;
+ } else {
+ prevBRCC = MI;
+ }
+ } else {
+ prevBRCC = NULL;
+ }
+
+ ++MII;
+ }
+ }
+
+ return Changed;
+}
+
+FunctionPass *llvm::createDCPU16DuplicateBranch() {
+ return new DCPU16DuplicateBranch();
+}
View
2  lib/Target/DCPU16/DCPU16InstrInfo.cpp
@@ -105,7 +105,7 @@ void DCPU16InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
.addReg(SrcReg, getKillRegState(KillSrc));
}
-static bool isBR_CC(unsigned Opcode) {
+bool llvm::isBR_CC(unsigned Opcode) {
switch (Opcode) {
default: return false;
case DCPU16::BR_CCrr:
View
6 lib/Target/DCPU16/DCPU16TargetMachine.cpp
@@ -51,6 +51,7 @@ class DCPU16PassConfig : public TargetPassConfig {
}
virtual bool addInstSelector();
+ virtual bool addPreEmitPass();
};
} // namespace
@@ -65,3 +66,8 @@ bool DCPU16PassConfig::addInstSelector() {
PM->add(createDCPU16Peephole());
return false;
}
+
+bool DCPU16PassConfig::addPreEmitPass() {
+ PM->add(createDCPU16DuplicateBranch());
+ return true;
+}
View
37 test/CodeGen/DCPU16/duplicate_branch.ll
@@ -0,0 +1,37 @@
+; RUN: llc < %s -march=dcpu16 | FileCheck %s
+target datalayout = "e-p:16:16:16-i8:16:16-i16:16:16-i32:16:16-s0:16:16-n16"
+target triple = "dcpu16"
+
+define void @duplicate_branch(i16 %a, i16 %b, i16 %c) nounwind {
+entry:
+ %cmp = icmp eq i16 %a, %b
+ br i1 %cmp, label %return, label %if.else
+
+if.else: ; preds = %entry
+ %cmp1 = icmp slt i16 %a, %b
+ br i1 %cmp1, label %if.then2, label %if.else3
+
+if.then2: ; preds = %if.else
+ %div = sdiv i16 %c, 10
+ br label %if.end4
+
+if.else3: ; preds = %if.else
+ %mul = mul nsw i16 %c, 10
+ br label %if.end4
+
+if.end4: ; preds = %if.then2, %if.else3
+ %c.addr.0 = phi i16 [ %div, %if.then2 ], [ %mul, %if.else3 ]
+ tail call void @foo(i16 %c.addr.0) nounwind
+ br label %return
+
+return: ; preds = %entry, %if.end4
+ ret void
+}
+; CHECK: :duplicate_branch
+; CHECK: IFE A, B
+; CHECK: SET PC, .LBB0_5
+; CHECK-NOT: IFE A, B
+; CHECK: IFA A, B
+; CHECK: SET PC, .LBB0_3
+
+declare void @foo(i16)
Something went wrong with that request. Please try again.