mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
DeadCodeElimination: remove dead overflow producing operations together with the cond_fail which handles the overflow.
This commit is contained in:
@@ -74,6 +74,10 @@ class DCE : public SILFunctionTransform {
|
||||
PostDominanceInfo *PDT;
|
||||
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.
|
||||
bool BranchesChanged;
|
||||
/// Trackes if the pass changed ApplyInsts.
|
||||
@@ -173,15 +177,51 @@ void DCE::markValueLive(ValueBase *V) {
|
||||
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.
|
||||
void DCE::markLive(SILFunction &F) {
|
||||
|
||||
llvm::SmallVector<CondFailInst *, 16> CondFailInsts;
|
||||
|
||||
// Find the initial set of instructions in this function that appear
|
||||
// to be live in the sense that they are not trivially something we
|
||||
// can delete by examining only that instruction.
|
||||
for (auto &BB : F)
|
||||
for (auto &I : BB)
|
||||
for (auto &BB : F) {
|
||||
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))
|
||||
markValueLive(&I);
|
||||
}
|
||||
}
|
||||
|
||||
// Now propagate liveness backwards from each instruction in our
|
||||
// worklist, adding new instructions to the worklist as we discover
|
||||
@@ -281,6 +321,11 @@ void DCE::propagateLiveness(SILInstruction *I) {
|
||||
for (Operand *DU : getDebugUses(*I))
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ bb5:
|
||||
%47 = struct $Int32 (%46 : $Builtin.Int32)
|
||||
br bb6(%47 : $Int32)
|
||||
|
||||
// CHECK: bb6
|
||||
// CHECK: bb6{{.*}}):
|
||||
bb6(%49 : $Int32):
|
||||
%50 = integer_literal $Builtin.Int32, 10
|
||||
%52 = struct_extract %29 : $Int32, #Int32._value
|
||||
@@ -142,11 +142,13 @@ bb7:
|
||||
// CHECK: br bb8
|
||||
br bb8(%58 : $Int32)
|
||||
|
||||
// CHECK: bb8
|
||||
// CHECK: bb8(%{{[0-9]+}} : $Int32):
|
||||
bb8(%60 : $Int32):
|
||||
%61 = struct_extract %31 : $Int32, #Int32._value
|
||||
%62 = integer_literal $Builtin.Int32, 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)
|
||||
%66 = tuple_extract %65 : $(Builtin.Int32, Builtin.Int1), 0
|
||||
%67 = tuple_extract %65 : $(Builtin.Int32, Builtin.Int1), 1
|
||||
@@ -155,11 +157,15 @@ bb8(%60 : $Int32):
|
||||
%70 = struct_extract %30 : $Int32, #Int32._value
|
||||
%71 = integer_literal $Builtin.Int32, 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
|
||||
%76 = tuple_extract %74 : $(Builtin.Int32, Builtin.Int1), 1
|
||||
// CHECK: cond_fail
|
||||
cond_fail %76 : $Builtin.Int1
|
||||
%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,
|
||||
br bb3(%49 : $Int32, %60 : $Int32, %78 : $Int32, %69 : $Int32)
|
||||
|
||||
@@ -182,3 +188,5 @@ bb10:
|
||||
// CHECK: return
|
||||
return %90 : $()
|
||||
}
|
||||
|
||||
sil @take_int32 : $@convention(thin) (Int32) -> ()
|
||||
|
||||
Reference in New Issue
Block a user