| 1101 | } |
| 1102 | |
| 1103 | StateMap::CondId FunctionalizeCond::StateAlongEdge(const Edge* e) { |
| 1104 | Node* src = e->src(); |
| 1105 | StateMap::CondId id = state_map_.LookupCondId(e->src()); |
| 1106 | |
| 1107 | // Dead nodes only propagate dead state. |
| 1108 | if (state_map_.IsDead(id)) return id; |
| 1109 | |
| 1110 | if (IsSwitch(src)) { |
| 1111 | StateMap::CondState state; |
| 1112 | if (id != nullptr) state = *id; |
| 1113 | OutputTensor predicate; |
| 1114 | TF_CHECK_OK(GetSwitchPredicate(*src, &predicate)); |
| 1115 | if (e->IsControlEdge()) { |
| 1116 | // In gradients of tf.cond(), in each branch, we have a NoOp node as |
| 1117 | // control pivot. These NoOp nodes have control dependency from Switch |
| 1118 | // node. If we don't record this into CondState, branches might have |
| 1119 | // incorrect CondState (e.g. if the branch only has a Const data node). |
| 1120 | // We set it to kNeither because there is no way to tell whether it's |
| 1121 | // for true branch or false branch. This node's desendents might have |
| 1122 | // other incoming edges with defined BranchType, and we correctly handle |
| 1123 | // merging kNeither with other defined BranchType in StateAlongEdge(). |
| 1124 | state[predicate] = BranchType::kNeither; |
| 1125 | } else { |
| 1126 | state[predicate] = BranchType(e->src_output()); |
| 1127 | } |
| 1128 | return state_map_.GetCondId(state); |
| 1129 | } |
| 1130 | return id; |
| 1131 | } |
| 1132 | |
| 1133 | Status FunctionalizeCond::DetermineCondStateMerge(Node* dst) { |
| 1134 | // Only Merge nodes with two inputs are supported, but if this is a redundant |
nothing calls this directly
no test coverage detected