STATISTIC(NumRetsDup, "Number of return instructions duplicated");
STATISTIC(NumDbgValueMoved, "Number of debug value instructions moved");
STATISTIC(NumSelectsExpanded, "Number of selects turned into branches");
+STATISTIC(NumAndCmpsMoved, "Number of and/cmp's pushed into branches");
static cl::opt<bool> DisableBranchOpts(
"disable-cgp-branch-opts", cl::Hidden, cl::init(false),
"disable-cgp-select2branch", cl::Hidden, cl::init(false),
cl::desc("Disable select to branch conversion."));
+static cl::opt<bool> EnableAndCmpSinking(
+ "enable-andcmp-sinking", cl::Hidden, cl::init(true),
+ cl::desc("Enable sinkinig and/cmp into branches."));
+
namespace {
typedef SmallPtrSet<Instruction *, 16> SetOfInstrs;
typedef DenseMap<Instruction *, Type *> InstrToOrigTy;
bool OptimizeShuffleVectorInst(ShuffleVectorInst *SI);
bool DupRetToEnableTailCallOpts(BasicBlock *BB);
bool PlaceDbgValues(Function &F);
+ bool sinkAndCmp(Function &F);
};
}
}
bool CodeGenPrepare::runOnFunction(Function &F) {
+ if (skipOptnoneFunction(F))
+ return false;
+
bool EverMadeChange = false;
// Clear per function information.
InsertedTruncsSet.clear();
// find a node corresponding to the value.
EverMadeChange |= PlaceDbgValues(F);
+ // If there is a mask, compare against zero, and branch that can be combined
+ // into a single target instruction, push the mask and compare into branch
+ // users. Do this before OptimizeBlock -> OptimizeInst ->
+ // OptimizeCmpExpression, which perturbs the pattern being searched for.
+ if (!DisableBranchOpts)
+ EverMadeChange |= sinkAndCmp(F);
+
bool MadeChange = true;
while (MadeChange) {
MadeChange = false;
DEBUG(dbgs() << "AFTER:\n" << *DestBB << "\n\n\n");
}
-/// OptimizeNoopCopyExpression - If the specified cast instruction is a noop
-/// copy (e.g. it's casting from one pointer type to another, i32->i8 on PPC),
-/// sink it into user blocks to reduce the number of virtual
-/// registers that must be created and coalesced.
-///
-/// Return true if any changes are made.
-///
-static bool OptimizeNoopCopyExpression(CastInst *CI, const TargetLowering &TLI){
- // If this is a noop copy,
- EVT SrcVT = TLI.getValueType(CI->getOperand(0)->getType());
- EVT DstVT = TLI.getValueType(CI->getType());
-
- // This is an fp<->int conversion?
- if (SrcVT.isInteger() != DstVT.isInteger())
- return false;
-
- // If this is an extension, it will be a zero or sign extension, which
- // isn't a noop.
- if (SrcVT.bitsLT(DstVT)) return false;
-
- // If these values will be promoted, find out what they will be promoted
- // to. This helps us consider truncates on PPC as noop copies when they
- // are.
- if (TLI.getTypeAction(CI->getContext(), SrcVT) ==
- TargetLowering::TypePromoteInteger)
- SrcVT = TLI.getTypeToTransformTo(CI->getContext(), SrcVT);
- if (TLI.getTypeAction(CI->getContext(), DstVT) ==
- TargetLowering::TypePromoteInteger)
- DstVT = TLI.getTypeToTransformTo(CI->getContext(), DstVT);
-
- // If, after promotion, these are the same types, this is a noop copy.
- if (SrcVT != DstVT)
- return false;
-
+/// SinkCast - Sink the specified cast instruction into its user blocks
+static bool SinkCast(CastInst *CI) {
BasicBlock *DefBB = CI->getParent();
/// InsertedCasts - Only insert a cast in each block once.
return MadeChange;
}
+/// OptimizeNoopCopyExpression - If the specified cast instruction is a noop
+/// copy (e.g. it's casting from one pointer type to another, i32->i8 on PPC),
+/// sink it into user blocks to reduce the number of virtual
+/// registers that must be created and coalesced.
+///
+/// Return true if any changes are made.
+///
+static bool OptimizeNoopCopyExpression(CastInst *CI, const TargetLowering &TLI){
+ // If this is a noop copy,
+ EVT SrcVT = TLI.getValueType(CI->getOperand(0)->getType());
+ EVT DstVT = TLI.getValueType(CI->getType());
+
+ // This is an fp<->int conversion?
+ if (SrcVT.isInteger() != DstVT.isInteger())
+ return false;
+
+ // If this is an extension, it will be a zero or sign extension, which
+ // isn't a noop.
+ if (SrcVT.bitsLT(DstVT)) return false;
+
+ // If these values will be promoted, find out what they will be promoted
+ // to. This helps us consider truncates on PPC as noop copies when they
+ // are.
+ if (TLI.getTypeAction(CI->getContext(), SrcVT) ==
+ TargetLowering::TypePromoteInteger)
+ SrcVT = TLI.getTypeToTransformTo(CI->getContext(), SrcVT);
+ if (TLI.getTypeAction(CI->getContext(), DstVT) ==
+ TargetLowering::TypePromoteInteger)
+ DstVT = TLI.getTypeToTransformTo(CI->getContext(), DstVT);
+
+ // If, after promotion, these are the same types, this is a noop copy.
+ if (SrcVT != DstVT)
+ return false;
+
+ return SinkCast(CI);
+}
+
/// OptimizeCmpExpression - sink the given CmpInst into user blocks to reduce
/// the number of virtual registers that must be created and coalesced. This is
/// a clear win except on targets with multiple condition code registers
cast<IntegerType>(V->getType())->getBitWidth()) {
V = Builder.CreateTrunc(V, IntPtrTy, "sunkaddr");
} else {
- V = Builder.CreateSExt(V, IntPtrTy, "sunkaddr");
+ // It is only safe to sign extend the BaseReg if we know that the math
+ // required to create it did not overflow before we extend it. Since
+ // the original IR value was tossed in favor of a constant back when
+ // the AddrMode was created we need to bail out gracefully if widths
+ // do not match instead of extending it.
+ if (Result != AddrMode.BaseReg)
+ cast<Instruction>(Result)->eraseFromParent();
+ return false;
}
if (AddrMode.Scale != 1)
V = Builder.CreateMul(V, ConstantInt::get(IntPtrTy, AddrMode.Scale),
return true;
if (isa<ZExtInst>(I) || isa<SExtInst>(I)) {
- bool MadeChange = MoveExtToFormExtLoad(I);
- return MadeChange | OptimizeExtUses(I);
+ /// Sink a zext or sext into its user blocks if the target type doesn't
+ /// fit in one register
+ if (TLI && TLI->getTypeAction(CI->getContext(),
+ TLI->getValueType(CI->getType())) ==
+ TargetLowering::TypeExpandInteger) {
+ return SinkCast(CI);
+ } else {
+ bool MadeChange = MoveExtToFormExtLoad(I);
+ return MadeChange | OptimizeExtUses(I);
+ }
}
return false;
}
}
return MadeChange;
}
+
+// If there is a sequence that branches based on comparing a single bit
+// against zero that can be combined into a single instruction, and the
+// target supports folding these into a single instruction, sink the
+// mask and compare into the branch uses. Do this before OptimizeBlock ->
+// OptimizeInst -> OptimizeCmpExpression, which perturbs the pattern being
+// searched for.
+bool CodeGenPrepare::sinkAndCmp(Function &F) {
+ if (!EnableAndCmpSinking)
+ return false;
+ if (!TLI || !TLI->isMaskAndBranchFoldingLegal())
+ return false;
+ bool MadeChange = false;
+ for (Function::iterator I = F.begin(), E = F.end(); I != E; ) {
+ BasicBlock *BB = I++;
+
+ // Does this BB end with the following?
+ // %andVal = and %val, #single-bit-set
+ // %icmpVal = icmp %andResult, 0
+ // br i1 %cmpVal label %dest1, label %dest2"
+ BranchInst *Brcc = dyn_cast<BranchInst>(BB->getTerminator());
+ if (!Brcc || !Brcc->isConditional())
+ continue;
+ ICmpInst *Cmp = dyn_cast<ICmpInst>(Brcc->getOperand(0));
+ if (!Cmp || Cmp->getParent() != BB)
+ continue;
+ ConstantInt *Zero = dyn_cast<ConstantInt>(Cmp->getOperand(1));
+ if (!Zero || !Zero->isZero())
+ continue;
+ Instruction *And = dyn_cast<Instruction>(Cmp->getOperand(0));
+ if (!And || And->getOpcode() != Instruction::And || And->getParent() != BB)
+ continue;
+ ConstantInt* Mask = dyn_cast<ConstantInt>(And->getOperand(1));
+ if (!Mask || !Mask->getUniqueInteger().isPowerOf2())
+ continue;
+ DEBUG(dbgs() << "found and; icmp ?,0; brcc\n"); DEBUG(BB->dump());
+
+ // Push the "and; icmp" for any users that are conditional branches.
+ // Since there can only be one branch use per BB, we don't need to keep
+ // track of which BBs we insert into.
+ for (Value::use_iterator UI = Cmp->use_begin(), E = Cmp->use_end();
+ UI != E; ) {
+ Use &TheUse = *UI;
+ // Find brcc use.
+ BranchInst *BrccUser = dyn_cast<BranchInst>(*UI);
+ ++UI;
+ if (!BrccUser || !BrccUser->isConditional())
+ continue;
+ BasicBlock *UserBB = BrccUser->getParent();
+ if (UserBB == BB) continue;
+ DEBUG(dbgs() << "found Brcc use\n");
+
+ // Sink the "and; icmp" to use.
+ MadeChange = true;
+ BinaryOperator *NewAnd =
+ BinaryOperator::CreateAnd(And->getOperand(0), And->getOperand(1), "",
+ BrccUser);
+ CmpInst *NewCmp =
+ CmpInst::Create(Cmp->getOpcode(), Cmp->getPredicate(), NewAnd, Zero,
+ "", BrccUser);
+ TheUse = NewCmp;
+ ++NumAndCmpsMoved;
+ DEBUG(BrccUser->getParent()->dump());
+ }
+ }
+ return MadeChange;
+}