DeadCodeElimination: remove dead overflow producing operations together with the cond_fail which handles the overflow.

This commit is contained in:
Erik Eckstein
2015-11-04 09:46:53 -08:00
parent 2cf7f18f11
commit 2504257a1a
2 changed files with 58 additions and 5 deletions

View File

@@ -74,6 +74,10 @@ class DCE : public SILFunctionTransform {
PostDominanceInfo *PDT; PostDominanceInfo *PDT;
llvm::DenseMap<SILBasicBlock *, ControllingInfo> ControllingInfoMap; llvm::DenseMap<SILBasicBlock *, ControllingInfo> ControllingInfoMap;
// Maps instructions which produce a failing condition (like overflow
// builtins) to the actual cond_fail instructions which handle the failure.
llvm::DenseMap<SILInstruction *, CondFailInst *> CondFailProducers;
/// Tracks if the pass changed branches. /// Tracks if the pass changed branches.
bool BranchesChanged; bool BranchesChanged;
/// Trackes if the pass changed ApplyInsts. /// Trackes if the pass changed ApplyInsts.
@@ -173,15 +177,51 @@ void DCE::markValueLive(ValueBase *V) {
propagateLiveBlockArgument(Arg); propagateLiveBlockArgument(Arg);
} }
/// Gets the producing instruction of a cond_fail condition. Currently these
/// are overflow builtints but may be extended to other instructions in the
/// future.
static SILInstruction *getProducer(CondFailInst *CFI) {
// Check for the pattern:
// %1 = builtin "some_operation_with_overflow"
// %2 = tuple_extract %1
// %3 = cond_fail %2
SILValue FailCond = CFI->getOperand();
if (auto *TEI = dyn_cast<TupleExtractInst>(FailCond)) {
if (auto *BI = dyn_cast<BuiltinInst>(TEI->getOperand())) {
return BI;
}
}
return nullptr;
}
// Determine which instructions from this function we need to keep. // Determine which instructions from this function we need to keep.
void DCE::markLive(SILFunction &F) { void DCE::markLive(SILFunction &F) {
llvm::SmallVector<CondFailInst *, 16> CondFailInsts;
// Find the initial set of instructions in this function that appear // Find the initial set of instructions in this function that appear
// to be live in the sense that they are not trivially something we // to be live in the sense that they are not trivially something we
// can delete by examining only that instruction. // can delete by examining only that instruction.
for (auto &BB : F) for (auto &BB : F) {
for (auto &I : BB) for (auto &I : BB) {
if (auto *CFI = dyn_cast<CondFailInst>(&I)) {
// Special case cond_fail instructions. A cond_fail is only alive
// if its (identifyable) producer is alive. We handle this in
// propagateLiveness.
if (SILInstruction *Prod = getProducer(CFI)) {
CondFailInst *&MappedCFI = CondFailProducers[Prod];
if (!MappedCFI) {
// For simplicity we only handle a single cond_fail for each
// producer (which is the usual case).
MappedCFI = CFI;
continue;
}
}
}
if (seemsUseful(&I)) if (seemsUseful(&I))
markValueLive(&I); markValueLive(&I);
}
}
// Now propagate liveness backwards from each instruction in our // Now propagate liveness backwards from each instruction in our
// worklist, adding new instructions to the worklist as we discover // worklist, adding new instructions to the worklist as we discover
@@ -281,6 +321,11 @@ void DCE::propagateLiveness(SILInstruction *I) {
for (Operand *DU : getDebugUses(*I)) for (Operand *DU : getDebugUses(*I))
markValueLive(DU->getUser()); markValueLive(DU->getUser());
// The same situation for cond_fail instructions. Only if the producer of
// the cond_fail is alive, the cond_fail itself is alive.
if (CondFailInst *CFI = CondFailProducers.lookup(I)) {
markValueLive(CFI);
}
return; return;
} }

View File

@@ -124,7 +124,7 @@ bb5:
%47 = struct $Int32 (%46 : $Builtin.Int32) %47 = struct $Int32 (%46 : $Builtin.Int32)
br bb6(%47 : $Int32) br bb6(%47 : $Int32)
// CHECK: bb6 // CHECK: bb6{{.*}}):
bb6(%49 : $Int32): bb6(%49 : $Int32):
%50 = integer_literal $Builtin.Int32, 10 %50 = integer_literal $Builtin.Int32, 10
%52 = struct_extract %29 : $Int32, #Int32._value %52 = struct_extract %29 : $Int32, #Int32._value
@@ -142,11 +142,13 @@ bb7:
// CHECK: br bb8 // CHECK: br bb8
br bb8(%58 : $Int32) br bb8(%58 : $Int32)
// CHECK: bb8 // CHECK: bb8(%{{[0-9]+}} : $Int32):
bb8(%60 : $Int32): bb8(%60 : $Int32):
%61 = struct_extract %31 : $Int32, #Int32._value %61 = struct_extract %31 : $Int32, #Int32._value
%62 = integer_literal $Builtin.Int32, 1 %62 = integer_literal $Builtin.Int32, 1
%64 = integer_literal $Builtin.Int1, -1 %64 = integer_literal $Builtin.Int1, -1
// CHECK-NOT: builtin "sadd_with_overflow_Int32"
// CHECK-NOT: cond_fail
%65 = builtin "sadd_with_overflow_Int32"(%61 : $Builtin.Int32, %62 : $Builtin.Int32, %64 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) %65 = builtin "sadd_with_overflow_Int32"(%61 : $Builtin.Int32, %62 : $Builtin.Int32, %64 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%66 = tuple_extract %65 : $(Builtin.Int32, Builtin.Int1), 0 %66 = tuple_extract %65 : $(Builtin.Int32, Builtin.Int1), 0
%67 = tuple_extract %65 : $(Builtin.Int32, Builtin.Int1), 1 %67 = tuple_extract %65 : $(Builtin.Int32, Builtin.Int1), 1
@@ -155,11 +157,15 @@ bb8(%60 : $Int32):
%70 = struct_extract %30 : $Int32, #Int32._value %70 = struct_extract %30 : $Int32, #Int32._value
%71 = integer_literal $Builtin.Int32, 1 %71 = integer_literal $Builtin.Int32, 1
%73 = integer_literal $Builtin.Int1, -1 %73 = integer_literal $Builtin.Int1, -1
%74 = builtin "sadd_with_overflow_Int32"(%70 : $Builtin.Int32, %71 : $Builtin.Int32, %73 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // CHECK: builtin "ssub_with_overflow_Int32"
%74 = builtin "ssub_with_overflow_Int32"(%70 : $Builtin.Int32, %71 : $Builtin.Int32, %73 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%75 = tuple_extract %74 : $(Builtin.Int32, Builtin.Int1), 0 %75 = tuple_extract %74 : $(Builtin.Int32, Builtin.Int1), 0
%76 = tuple_extract %74 : $(Builtin.Int32, Builtin.Int1), 1 %76 = tuple_extract %74 : $(Builtin.Int32, Builtin.Int1), 1
// CHECK: cond_fail
cond_fail %76 : $Builtin.Int1 cond_fail %76 : $Builtin.Int1
%78 = struct $Int32 (%75 : $Builtin.Int32) %78 = struct $Int32 (%75 : $Builtin.Int32)
%tif = function_ref @take_int32 : $@convention(thin) (Int32) -> ()
%atif = apply %tif(%78) : $@convention(thin) (Int32) -> ()
// CHECK: br bb3(undef : $Int32, undef : $Int32, // CHECK: br bb3(undef : $Int32, undef : $Int32,
br bb3(%49 : $Int32, %60 : $Int32, %78 : $Int32, %69 : $Int32) br bb3(%49 : $Int32, %60 : $Int32, %78 : $Int32, %69 : $Int32)
@@ -182,3 +188,5 @@ bb10:
// CHECK: return // CHECK: return
return %90 : $() return %90 : $()
} }
sil @take_int32 : $@convention(thin) (Int32) -> ()