+ const Value *RetVal = Ret->getOperand(0), *CallVal = I;
+ SmallVector<unsigned, 4> RetPath, CallPath;
+ SmallVector<CompositeType *, 4> RetSubTypes, CallSubTypes;
+
+ bool RetEmpty = !firstRealType(RetVal->getType(), RetSubTypes, RetPath);
+ bool CallEmpty = !firstRealType(CallVal->getType(), CallSubTypes, CallPath);
+
+ // Nothing's actually returned, it doesn't matter what the callee put there
+ // it's a valid tail call.
+ if (RetEmpty)
+ return true;
+
+ // Iterate pairwise through each of the value types making up the tail call
+ // and the corresponding return. For each one we want to know whether it's
+ // essentially going directly from the tail call to the ret, via operations
+ // that end up not generating any code.
+ //
+ // We allow a certain amount of covariance here. For example it's permitted
+ // for the tail call to define more bits than the ret actually cares about
+ // (e.g. via a truncate).
+ do {
+ if (CallEmpty) {
+ // We've exhausted the values produced by the tail call instruction, the
+ // rest are essentially undef. The type doesn't really matter, but we need
+ // *something*.
+ Type *SlotType = RetSubTypes.back()->getTypeAtIndex(RetPath.back());
+ CallVal = UndefValue::get(SlotType);
+ }
+
+ // The manipulations performed when we're looking through an insertvalue or
+ // an extractvalue would happen at the front of the RetPath list, so since
+ // we have to copy it anyway it's more efficient to create a reversed copy.
+ using std::copy;
+ SmallVector<unsigned, 4> TmpRetPath, TmpCallPath;
+ copy(RetPath.rbegin(), RetPath.rend(), std::back_inserter(TmpRetPath));
+ copy(CallPath.rbegin(), CallPath.rend(), std::back_inserter(TmpCallPath));
+
+ // Finally, we can check whether the value produced by the tail call at this
+ // index is compatible with the value we return.
+ if (!slotOnlyDiscardsData(RetVal, CallVal, TmpRetPath, TmpCallPath,
+ AllowDifferingSizes, TLI))
+ return false;
+
+ CallEmpty = !nextRealType(CallSubTypes, CallPath);
+ } while(nextRealType(RetSubTypes, RetPath));
+
+ return true;