Index: include/llvm/Analysis/TargetLibraryInfo.h
===================================================================
--- include/llvm/Analysis/TargetLibraryInfo.h
+++ include/llvm/Analysis/TargetLibraryInfo.h
@@ -191,6 +191,14 @@
   void setShouldSignExtI32Param(bool Val) {
     ShouldSignExtI32Param = Val;
   }
+
+  /// Returns the size of the wchar_t type in bytes.
+  unsigned getWCharSize(const Module &M) const;
+
+  /// Returns size of the default wchar_t type on target \p T. This is mostly
+  /// intended to verify that the size in the frontend matches LLVM. All other
+  /// queries should use getWCharSize() instead.
+  static unsigned getTargetWCharSize(const Triple &T);
 };
 
 /// Provides information about what library functions are available for
@@ -307,6 +315,11 @@
     return Attribute::None;
   }
 
+  /// \copydoc TargetLibraryInfoImpl::getWCharSize()
+  unsigned getWCharSize(const Module &M) const {
+    return Impl->getWCharSize(M);
+  }
+
   /// Handle invalidation from the pass manager.
   ///
   /// If we try to invalidate this info, just return false. It cannot become
Index: include/llvm/Analysis/ValueTracking.h
===================================================================
--- include/llvm/Analysis/ValueTracking.h
+++ include/llvm/Analysis/ValueTracking.h
@@ -218,9 +218,27 @@
                                             DL);
   }
 
-  /// Returns true if the GEP is based on a pointer to a string (array of i8), 
-  /// and is indexing into this string.
-  bool isGEPBasedOnPointerToString(const GEPOperator *GEP);
+  /// Returns true if the GEP is based on a pointer to a string (array of
+  // \p CharSize integers) and is indexing into this string.
+  bool isGEPBasedOnPointerToString(const GEPOperator *GEP,
+                                   unsigned CharSize = 8);
+
+  /// Represents offset+length into a ConstantDataArray.
+  struct ConstantDataArraySlice {
+    /// ConstantDataArray pointer. nullptr indicates a zeroinitializer (a valid
+    /// initializer, it just doesn't fit the ConstantDataArray interface).
+    const ConstantDataArray *Array;
+    /// Slice starts at this Offset.
+    uint64_t Offset;
+    /// Length of the slice.
+    uint64_t Length;
+  };
+
+  /// Returns true if the value \p V is a pointer into a ContantDataArray.
+  /// If successfull \p Index will point to a ConstantDataArray info object
+  /// with an apropriate offset.
+  bool getConstantDataArrayInfo(const Value *V, ConstantDataArraySlice &Slice,
+                                unsigned ElementSize, uint64_t Offset = 0);
 
   /// This function computes the length of a null-terminated C string pointed to
   /// by V. If successful, it returns true and returns the string in Str. If
@@ -233,7 +251,7 @@
 
   /// If we can compute the length of the string pointed to by the specified
   /// pointer, return 'len+1'.  If we can't, return 0.
-  uint64_t GetStringLength(const Value *V);
+  uint64_t GetStringLength(const Value *V, unsigned CharSize = 8);
 
   /// This method strips off any GEP address adjustments and pointer casts from
   /// the specified value, returning the original object being addressed. Note
Index: include/llvm/IR/Constants.h
===================================================================
--- include/llvm/IR/Constants.h
+++ include/llvm/IR/Constants.h
@@ -634,8 +634,8 @@
   /// The size of the elements is known to be a multiple of one byte.
   uint64_t getElementByteSize() const;
 
-  /// This method returns true if this is an array of i8.
-  bool isString() const;
+  /// This method returns true if this is an array of \p CharSize integers.
+  bool isString(unsigned CharSize = 8) const;
 
   /// This method returns true if the array "isString", ends with a null byte,
   /// and does not contains any other null bytes.
Index: include/llvm/Transforms/Utils/SimplifyLibCalls.h
===================================================================
--- include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -121,6 +121,7 @@
   Value *optimizeMemCpy(CallInst *CI, IRBuilder<> &B);
   Value *optimizeMemMove(CallInst *CI, IRBuilder<> &B);
   Value *optimizeMemSet(CallInst *CI, IRBuilder<> &B);
+  Value *optimizeWcslen(CallInst *CI, IRBuilder<> &B);
   // Wrapper for all String/Memory Library Call Optimizations
   Value *optimizeStringMemoryLibCall(CallInst *CI, IRBuilder<> &B);
 
@@ -165,6 +166,9 @@
   /// hasFloatVersion - Checks if there is a float version of the specified
   /// function by checking for an existing function with name FuncName + f
   bool hasFloatVersion(StringRef FuncName);
+
+  /// Shared code to optimize strlen+wcslen.
+  Value *optimizeStringLength(CallInst *CI, IRBuilder<> &B, unsigned CharSize);
 };
 } // End llvm namespace
 
Index: lib/Analysis/TargetLibraryInfo.cpp
===================================================================
--- lib/Analysis/TargetLibraryInfo.cpp
+++ lib/Analysis/TargetLibraryInfo.cpp
@@ -13,6 +13,7 @@
 
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/Support/CommandLine.h"
 using namespace llvm;
 
@@ -1518,6 +1519,17 @@
   return *Impl;
 }
 
+unsigned TargetLibraryInfoImpl::getTargetWCharSize(const Triple &T) {
+  // See also clang/lib/Basic/Targets.cpp.
+  return T.isPS4() || T.isOSWindows() || T.getArch() == Triple::xcore ? 2 : 4;
+}
+
+unsigned TargetLibraryInfoImpl::getWCharSize(const Module &M) const {
+  if (auto *ShortWChar = cast_or_null<ConstantAsMetadata>(
+      M.getModuleFlag("wchar_size")))
+    return cast<ConstantInt>(ShortWChar->getValue())->getZExtValue();
+  return getTargetWCharSize(Triple(M.getTargetTriple()));
+}
 
 TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass()
     : ImmutablePass(ID), TLIImpl(), TLI(TLIImpl) {
Index: lib/Analysis/ValueTracking.cpp
===================================================================
--- lib/Analysis/ValueTracking.cpp
+++ lib/Analysis/ValueTracking.cpp
@@ -26,6 +26,7 @@
 #include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/GetElementPtrTypeIterator.h"
 #include "llvm/IR/GlobalAlias.h"
@@ -2953,14 +2954,16 @@
   return Ptr;
 }
 
-bool llvm::isGEPBasedOnPointerToString(const GEPOperator *GEP) {
+bool llvm::isGEPBasedOnPointerToString(const GEPOperator *GEP,
+                                       unsigned CharSize) {
   // Make sure the GEP has exactly three arguments.
   if (GEP->getNumOperands() != 3)
     return false;
 
-  // Make sure the index-ee is a pointer to array of i8.
+  // Make sure the index-ee is a pointer to array of \p CharSize integers.
+  // CharSize.
   ArrayType *AT = dyn_cast<ArrayType>(GEP->getSourceElementType());
-  if (!AT || !AT->getElementType()->isIntegerTy(8))
+  if (!AT || !AT->getElementType()->isIntegerTy(CharSize))
     return false;
 
   // Check to make sure that the first operand of the GEP is an integer and
@@ -2972,11 +2975,9 @@
   return true;
 }
 
-/// This function computes the length of a null-terminated C string pointed to
-/// by V. If successful, it returns true and returns the string in Str.
-/// If unsuccessful, it returns false.
-bool llvm::getConstantStringInfo(const Value *V, StringRef &Str,
-                                 uint64_t Offset, bool TrimAtNul) {
+bool llvm::getConstantDataArrayInfo(const Value *V,
+                                    ConstantDataArraySlice &Slice,
+                                    unsigned ElementSize, uint64_t Offset) {
   assert(V);
 
   // Look through bitcast instructions and geps.
@@ -2987,7 +2988,7 @@
   if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
     // The GEP operator should be based on a pointer to string constant, and is
     // indexing into the string constant.
-    if (!isGEPBasedOnPointerToString(GEP))
+    if (!isGEPBasedOnPointerToString(GEP, ElementSize))
       return false;
 
     // If the second index isn't a ConstantInt, then this is a variable index
@@ -2998,8 +2999,8 @@
       StartIdx = CI->getZExtValue();
     else
       return false;
-    return getConstantStringInfo(GEP->getOperand(0), Str, StartIdx + Offset,
-                                 TrimAtNul);
+    return getConstantDataArrayInfo(GEP->getOperand(0), Slice, ElementSize,
+                                    StartIdx + Offset);
   }
 
   // The GEP instruction, constant or instruction, must reference a global
@@ -3009,30 +3010,69 @@
   if (!GV || !GV->isConstant() || !GV->hasDefinitiveInitializer())
     return false;
 
-  // Handle the all-zeros case.
+  const ConstantDataArray *Array;
+  ArrayType *ArrayTy;
   if (GV->getInitializer()->isNullValue()) {
-    // This is a degenerate case. The initializer is constant zero so the
-    // length of the string must be zero.
-    Str = "";
-    return true;
+    Type *GVTy = GV->getValueType();
+    if ( (ArrayTy = dyn_cast<ArrayType>(GVTy)) ) {
+      // A zeroinitializer for the array; There is no ConstantDataArray.
+      Array = nullptr;
+    } else {
+      if (GVTy->isIntegerTy(ElementSize)) {
+        Slice.Array = nullptr;
+        Slice.Offset = 0;
+        Slice.Length = 1;
+        return true;
+      }
+      return false;
+    }
+  } else {
+    // This must be a ConstantDataArray.
+    Array = dyn_cast<ConstantDataArray>(GV->getInitializer());
+    if (!Array)
+      return false;
+    ArrayTy = Array->getType();
   }
+  if (!ArrayTy->getElementType()->isIntegerTy(ElementSize))
+    return false;
 
-  // This must be a ConstantDataArray.
-  const auto *Array = dyn_cast<ConstantDataArray>(GV->getInitializer());
-  if (!Array || !Array->isString())
+  uint64_t NumElts = ArrayTy->getArrayNumElements();
+  if (Offset > NumElts)
     return false;
 
-  // Get the number of elements in the array.
-  uint64_t NumElts = Array->getType()->getArrayNumElements();
+  Slice.Array = Array;
+  Slice.Offset = Offset;
+  Slice.Length = NumElts - Offset;
+  return true;
+}
 
-  // Start out with the entire array in the StringRef.
-  Str = Array->getAsString();
+/// This function computes the length of a null-terminated C string pointed to
+/// by V. If successful, it returns true and returns the string in Str.
+/// If unsuccessful, it returns false.
+bool llvm::getConstantStringInfo(const Value *V, StringRef &Str,
+                                 uint64_t Offset, bool TrimAtNul) {
+  ConstantDataArraySlice Slice;
+  if (!getConstantDataArrayInfo(V, Slice, 8, Offset))
+    return false;
 
-  if (Offset > NumElts)
+  if (Slice.Array == nullptr) {
+    if (TrimAtNul) {
+      Str = StringRef();
+      return true;
+    }
+    if (Slice.Length == 1) {
+      Str = StringRef("", 1);
+      return true;
+    }
+    // We cannot instantiate a StringRef as we do not have an apropriate string
+    // of 0s at hand.
     return false;
+  }
 
+  // Start out with the entire array in the StringRef.
+  Str = Slice.Array->getAsString();
   // Skip over 'offset' bytes.
-  Str = Str.substr(Offset);
+  Str = Str.substr(Slice.Offset);
 
   if (TrimAtNul) {
     // Trim off the \0 and anything after it.  If the array is not nul
@@ -3050,7 +3090,8 @@
 /// If we can compute the length of the string pointed to by
 /// the specified pointer, return 'len+1'.  If we can't, return 0.
 static uint64_t GetStringLengthH(const Value *V,
-                                 SmallPtrSetImpl<const PHINode*> &PHIs) {
+                                 SmallPtrSetImpl<const PHINode*> &PHIs,
+                                 unsigned CharSize) {
   // Look through noop bitcast instructions.
   V = V->stripPointerCasts();
 
@@ -3063,7 +3104,7 @@
     // If it was new, see if all the input strings are the same length.
     uint64_t LenSoFar = ~0ULL;
     for (Value *IncValue : PN->incoming_values()) {
-      uint64_t Len = GetStringLengthH(IncValue, PHIs);
+      uint64_t Len = GetStringLengthH(IncValue, PHIs, CharSize);
       if (Len == 0) return 0; // Unknown length -> unknown.
 
       if (Len == ~0ULL) continue;
@@ -3079,9 +3120,9 @@
 
   // strlen(select(c,x,y)) -> strlen(x) ^ strlen(y)
   if (const SelectInst *SI = dyn_cast<SelectInst>(V)) {
-    uint64_t Len1 = GetStringLengthH(SI->getTrueValue(), PHIs);
+    uint64_t Len1 = GetStringLengthH(SI->getTrueValue(), PHIs, CharSize);
     if (Len1 == 0) return 0;
-    uint64_t Len2 = GetStringLengthH(SI->getFalseValue(), PHIs);
+    uint64_t Len2 = GetStringLengthH(SI->getFalseValue(), PHIs, CharSize);
     if (Len2 == 0) return 0;
     if (Len1 == ~0ULL) return Len2;
     if (Len2 == ~0ULL) return Len1;
@@ -3090,20 +3131,30 @@
   }
 
   // Otherwise, see if we can read the string.
-  StringRef StrData;
-  if (!getConstantStringInfo(V, StrData))
+  ConstantDataArraySlice Slice;
+  if (!getConstantDataArrayInfo(V, Slice, CharSize))
     return 0;
 
-  return StrData.size()+1;
+  if (Slice.Array == nullptr)
+    return 1;
+
+  // Search for nul characters
+  unsigned NullIndex = 0;
+  for (unsigned E = Slice.Length; NullIndex < E; ++NullIndex) {
+    if (Slice.Array->getElementAsInteger(Slice.Offset + NullIndex) == 0)
+      break;
+  }
+
+  return NullIndex + 1;
 }
 
 /// If we can compute the length of the string pointed to by
 /// the specified pointer, return 'len+1'.  If we can't, return 0.
-uint64_t llvm::GetStringLength(const Value *V) {
+uint64_t llvm::GetStringLength(const Value *V, unsigned CharSize) {
   if (!V->getType()->isPointerTy()) return 0;
 
   SmallPtrSet<const PHINode*, 32> PHIs;
-  uint64_t Len = GetStringLengthH(V, PHIs);
+  uint64_t Len = GetStringLengthH(V, PHIs, CharSize);
   // If Len is ~0ULL, we had an infinite phi cycle: this is dead code, so return
   // an empty string as a length.
   return Len == ~0ULL ? 1 : Len;
Index: lib/IR/Constants.cpp
===================================================================
--- lib/IR/Constants.cpp
+++ lib/IR/Constants.cpp
@@ -2616,8 +2616,8 @@
   return ConstantInt::get(getElementType(), getElementAsInteger(Elt));
 }
 
-bool ConstantDataSequential::isString() const {
-  return isa<ArrayType>(getType()) && getElementType()->isIntegerTy(8);
+bool ConstantDataSequential::isString(unsigned CharSize) const {
+  return isa<ArrayType>(getType()) && getElementType()->isIntegerTy(CharSize);
 }
 
 bool ConstantDataSequential::isCString() const {
Index: lib/Transforms/Utils/SimplifyLibCalls.cpp
===================================================================
--- lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -426,57 +426,70 @@
   return Dst;
 }
 
-Value *LibCallSimplifier::optimizeStrLen(CallInst *CI, IRBuilder<> &B) {
+Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilder<> &B,
+                                               unsigned CharSize) {
   Value *Src = CI->getArgOperand(0);
 
   // Constant folding: strlen("xyz") -> 3
-  if (uint64_t Len = GetStringLength(Src))
+  if (uint64_t Len = GetStringLength(Src, CharSize))
     return ConstantInt::get(CI->getType(), Len - 1);
 
   // If s is a constant pointer pointing to a string literal, we can fold
-  // strlen(s + x) to strlen(s) - x, when x is known to be in the range 
+  // strlen(s + x) to strlen(s) - x, when x is known to be in the range
   // [0, strlen(s)] or the string has a single null terminator '\0' at the end.
-  // We only try to simplify strlen when the pointer s points to an array 
+  // We only try to simplify strlen when the pointer s points to an array
   // of i8. Otherwise, we would need to scale the offset x before doing the
-  // subtraction. This will make the optimization more complex, and it's not 
-  // very useful because calling strlen for a pointer of other types is 
+  // subtraction. This will make the optimization more complex, and it's not
+  // very useful because calling strlen for a pointer of other types is
   // very uncommon.
   if (GEPOperator *GEP = dyn_cast<GEPOperator>(Src)) {
-    if (!isGEPBasedOnPointerToString(GEP))
+    if (!isGEPBasedOnPointerToString(GEP, CharSize))
       return nullptr;
 
-    StringRef Str;
-    if (getConstantStringInfo(GEP->getOperand(0), Str, 0, false)) {
-      size_t NullTermIdx = Str.find('\0');
-      
-      // If the string does not have '\0', leave it to strlen to compute
-      // its length.
-      if (NullTermIdx == StringRef::npos)
-        return nullptr;
-     
+    ConstantDataArraySlice Slice;
+    if (getConstantDataArrayInfo(GEP->getOperand(0), Slice, CharSize)) {
+      uint64_t NullTermIdx;
+      if (Slice.Array == nullptr) {
+        NullTermIdx = 0;
+      } else {
+        NullTermIdx = ~((uint64_t)0);
+        for (uint64_t I = 0, E = Slice.Length; I < E; ++I) {
+          if (Slice.Array->getElementAsInteger(I + Slice.Offset) == 0) {
+            NullTermIdx = I;
+            break;
+          }
+        }
+        // If the string does not have '\0', leave it to strlen to compute
+        // its length.
+        if (NullTermIdx == ~((uint64_t)0))
+          return nullptr;
+      }
+
       Value *Offset = GEP->getOperand(2);
       unsigned BitWidth = Offset->getType()->getIntegerBitWidth();
       KnownBits Known(BitWidth);
       computeKnownBits(Offset, Known, DL, 0, nullptr, CI, nullptr);
       Known.Zero.flipAllBits();
-      size_t ArrSize = 
+      uint64_t ArrSize =
              cast<ArrayType>(GEP->getSourceElementType())->getNumElements();
 
-      // KnownZero's bits are flipped, so zeros in KnownZero now represent 
-      // bits known to be zeros in Offset, and ones in KnowZero represent 
+      // KnownZero's bits are flipped, so zeros in KnownZero now represent
+      // bits known to be zeros in Offset, and ones in KnowZero represent
       // bits unknown in Offset. Therefore, Offset is known to be in range
-      // [0, NullTermIdx] when the flipped KnownZero is non-negative and 
+      // [0, NullTermIdx] when the flipped KnownZero is non-negative and
       // unsigned-less-than NullTermIdx.
       //
-      // If Offset is not provably in the range [0, NullTermIdx], we can still 
-      // optimize if we can prove that the program has undefined behavior when 
-      // Offset is outside that range. That is the case when GEP->getOperand(0) 
+      // If Offset is not provably in the range [0, NullTermIdx], we can still
+      // optimize if we can prove that the program has undefined behavior when
+      // Offset is outside that range. That is the case when GEP->getOperand(0)
       // is a pointer to an object whose memory extent is NullTermIdx+1.
-      if ((Known.Zero.isNonNegative() && Known.Zero.ule(NullTermIdx)) || 
+      if ((Known.Zero.isNonNegative() && Known.Zero.ule(NullTermIdx)) ||
           (GEP->isInBounds() && isa<GlobalVariable>(GEP->getOperand(0)) &&
-           NullTermIdx == ArrSize - 1))
-        return B.CreateSub(ConstantInt::get(CI->getType(), NullTermIdx), 
+           NullTermIdx == ArrSize - 1)) {
+        Offset = B.CreateSExtOrTrunc(Offset, CI->getType());
+        return B.CreateSub(ConstantInt::get(CI->getType(), NullTermIdx),
                            Offset);
+      }
     }
 
     return nullptr;
@@ -484,8 +497,8 @@
 
   // strlen(x?"foo":"bars") --> x ? 3 : 4
   if (SelectInst *SI = dyn_cast<SelectInst>(Src)) {
-    uint64_t LenTrue = GetStringLength(SI->getTrueValue());
-    uint64_t LenFalse = GetStringLength(SI->getFalseValue());
+    uint64_t LenTrue = GetStringLength(SI->getTrueValue(), CharSize);
+    uint64_t LenFalse = GetStringLength(SI->getFalseValue(), CharSize);
     if (LenTrue && LenFalse) {
       Function *Caller = CI->getParent()->getParent();
       emitOptimizationRemark(CI->getContext(), "simplify-libcalls", *Caller,
@@ -505,6 +518,17 @@
   return nullptr;
 }
 
+Value *LibCallSimplifier::optimizeStrLen(CallInst *CI, IRBuilder<> &B) {
+  return optimizeStringLength(CI, B, 8);
+}
+
+Value *LibCallSimplifier::optimizeWcslen(CallInst *CI, IRBuilder<> &B) {
+  Module &M = *CI->getParent()->getParent()->getParent();
+  unsigned WCharSize = TLI->getWCharSize(M) * 8;
+
+  return optimizeStringLength(CI, B, WCharSize);
+}
+
 Value *LibCallSimplifier::optimizeStrPBrk(CallInst *CI, IRBuilder<> &B) {
   StringRef S1, S2;
   bool HasS1 = getConstantStringInfo(CI->getArgOperand(0), S1);
@@ -2026,6 +2050,8 @@
       return optimizeMemMove(CI, Builder);
     case LibFunc_memset:
       return optimizeMemSet(CI, Builder);
+    case LibFunc_wcslen:
+      return optimizeWcslen(CI, Builder);
     default:
       break;
     }
Index: test/Transforms/InstCombine/wcslen-1.ll
===================================================================
--- /dev/null
+++ test/Transforms/InstCombine/wcslen-1.ll
@@ -0,0 +1,191 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the wcslen library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+declare i64 @wcslen(i32*)
+
+@hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+@longer = constant [7 x i32] [i32 108, i32 111, i32 110, i32 103, i32 101, i32 114, i32 0]
+@null = constant [1 x i32] zeroinitializer
+@null_hello = constant [7 x i32] [i32 0, i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+@nullstring = constant i32 0
+@a = common global [32 x i32] zeroinitializer, align 1
+@null_hello_mid = constant [13 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 32, i32 119, i32 111, i32 114, i32 0, i32 108, i32 100, i32 0]
+
+define i64 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    ret i64 5
+;
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+define i64 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_p = getelementptr [1 x i32], [1 x i32]* @null, i64 0, i64 0
+  %null_l = call i64 @wcslen(i32* %null_p)
+  ret i64 %null_l
+}
+
+define i64 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_hello_p = getelementptr [7 x i32], [7 x i32]* @null_hello, i64 0, i64 0
+  %null_hello_l = call i64 @wcslen(i32* %null_hello_p)
+  ret i64 %null_hello_l
+}
+
+define i64 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+; CHECK-NEXT:    ret i64 0
+;
+  %len = tail call i64 @wcslen(i32* @nullstring) nounwind
+  ret i64 %len
+}
+
+; Check wcslen(x) == 0 --> *x == 0.
+
+define i1 @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+; CHECK-NEXT:    ret i1 false
+;
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  %eq_hello = icmp eq i64 %hello_l, 0
+  ret i1 %eq_hello
+}
+
+define i1 @test_simplify6(i32* %str_p) {
+; CHECK-LABEL: @test_simplify6(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i32, i32* [[STR_P:%.*]], align 4
+; CHECK-NEXT:    [[EQ_NULL:%.*]] = icmp eq i32 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[EQ_NULL]]
+;
+  %str_l = call i64 @wcslen(i32* %str_p)
+  %eq_null = icmp eq i64 %str_l, 0
+  ret i1 %eq_null
+}
+
+; Check wcslen(x) != 0 --> *x != 0.
+
+define i1 @test_simplify7() {
+; CHECK-LABEL: @test_simplify7(
+; CHECK-NEXT:    ret i1 true
+;
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  %ne_hello = icmp ne i64 %hello_l, 0
+  ret i1 %ne_hello
+}
+
+define i1 @test_simplify8(i32* %str_p) {
+; CHECK-LABEL: @test_simplify8(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i32, i32* [[STR_P:%.*]], align 4
+; CHECK-NEXT:    [[NE_NULL:%.*]] = icmp ne i32 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[NE_NULL]]
+;
+  %str_l = call i64 @wcslen(i32* %str_p)
+  %ne_null = icmp ne i64 %str_l, 0
+  ret i1 %ne_null
+}
+
+define i64 @test_simplify9(i1 %x) {
+; CHECK-LABEL: @test_simplify9(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i64 5, i64 6
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %hello = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %longer = getelementptr [7 x i32], [7 x i32]* @longer, i64 0, i64 0
+  %s = select i1 %x, i32* %hello, i32* %longer
+  %l = call i64 @wcslen(i32* %s)
+  ret i64 %l
+}
+
+; Check the case that should be simplified to a sub instruction.
+; wcslen(@hello + x) --> 5 - x
+
+define i64 @test_simplify10(i32 %x) {
+; CHECK-LABEL: @test_simplify10(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i64 5, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %hello_p = getelementptr inbounds [6 x i32], [6 x i32]* @hello, i32 0, i32 %x
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 7)) --> 9 - (x & 7)
+
+define i64 @test_simplify11(i32 %x) {
+; CHECK-LABEL: @test_simplify11(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 7
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[AND]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i64 9, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %and = and i32 %x, 7
+  %hello_p = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+; Check cases that shouldn't be simplified.
+
+define i64 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+; CHECK-NEXT:    [[A_L:%.*]] = call i64 @wcslen(i32* getelementptr inbounds ([32 x i32], [32 x i32]* @a, i64 0, i64 0))
+; CHECK-NEXT:    ret i64 [[A_L]]
+;
+  %a_p = getelementptr [32 x i32], [32 x i32]* @a, i64 0, i64 0
+  %a_l = call i64 @wcslen(i32* %a_p)
+  ret i64 %a_l
+}
+
+; wcslen(@null_hello + x) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify2(i32 %x) {
+; CHECK-LABEL: @test_no_simplify2(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i32 0, i32 %x
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify3(i32 %x) {
+; CHECK-LABEL: @test_no_simplify3(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[AND]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %and = and i32 %x, 15
+  %hello_p = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
+@str16 = constant [1 x i16] [i16 0]
+
+define i64 @test_no_simplify4() {
+; CHECK-LABEL: @test_no_simplify4(
+; CHECK-NEXT:    [[L:%.*]] = call i64 @wcslen(i32* bitcast ([1 x i16]* @str16 to i32*))
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %l = call i64 @wcslen(i32* bitcast ([1 x i16]* @str16 to i32*))
+  ret i64 %l
+}
Index: test/Transforms/InstCombine/wcslen-2.ll
===================================================================
--- /dev/null
+++ test/Transforms/InstCombine/wcslen-2.ll
@@ -0,0 +1,18 @@
+; Test that the wcslen library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+@hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0]
+
+declare i64 @wcslen(i32*, i32)
+
+define i64 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+  %hello_p = getelementptr [6 x i32], [6 x i32]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i32* %hello_p, i32 187)
+; CHECK-NEXT: %hello_l = call i64 @wcslen
+  ret i64 %hello_l
+; CHECK-NEXT: ret i64 %hello_l
+}
Index: test/Transforms/InstCombine/wcslen-3.ll
===================================================================
--- /dev/null
+++ test/Transforms/InstCombine/wcslen-3.ll
@@ -0,0 +1,197 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the wcslen library call simplifier works correctly.
+;
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; Test behavior for wchar_size==2
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"wchar_size", i32 2}
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+declare i64 @wcslen(i16*)
+
+@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0]
+@longer = constant [7 x i16] [i16 108, i16 111, i16 110, i16 103, i16 101, i16 114, i16 0]
+@null = constant [1 x i16] zeroinitializer
+@null_hello = constant [7 x i16] [i16 0, i16 104, i16 101, i16 108, i16 108, i16 111, i16 0]
+@nullstring = constant i16 0
+@a = common global [32 x i16] zeroinitializer, align 1
+@null_hello_mid = constant [13 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 32, i16 119, i16 111, i16 114, i16 0, i16 108, i16 100, i16 0]
+
+define i64 @test_simplify1() {
+; CHECK-LABEL: @test_simplify1(
+; CHECK-NEXT:    ret i64 5
+;
+  %hello_p = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+define i64 @test_simplify2() {
+; CHECK-LABEL: @test_simplify2(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_p = getelementptr [1 x i16], [1 x i16]* @null, i64 0, i64 0
+  %null_l = call i64 @wcslen(i16* %null_p)
+  ret i64 %null_l
+}
+
+define i64 @test_simplify3() {
+; CHECK-LABEL: @test_simplify3(
+; CHECK-NEXT:    ret i64 0
+;
+  %null_hello_p = getelementptr [7 x i16], [7 x i16]* @null_hello, i64 0, i64 0
+  %null_hello_l = call i64 @wcslen(i16* %null_hello_p)
+  ret i64 %null_hello_l
+}
+
+define i64 @test_simplify4() {
+; CHECK-LABEL: @test_simplify4(
+; CHECK-NEXT:    ret i64 0
+;
+  %len = tail call i64 @wcslen(i16* @nullstring) nounwind
+  ret i64 %len
+}
+
+; Check wcslen(x) == 0 --> *x == 0.
+
+define i1 @test_simplify5() {
+; CHECK-LABEL: @test_simplify5(
+; CHECK-NEXT:    ret i1 false
+;
+  %hello_p = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  %eq_hello = icmp eq i64 %hello_l, 0
+  ret i1 %eq_hello
+}
+
+define i1 @test_simplify6(i16* %str_p) {
+; CHECK-LABEL: @test_simplify6(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i16, i16* [[STR_P:%.*]], align 2
+; CHECK-NEXT:    [[EQ_NULL:%.*]] = icmp eq i16 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[EQ_NULL]]
+;
+  %str_l = call i64 @wcslen(i16* %str_p)
+  %eq_null = icmp eq i64 %str_l, 0
+  ret i1 %eq_null
+}
+
+; Check wcslen(x) != 0 --> *x != 0.
+
+define i1 @test_simplify7() {
+; CHECK-LABEL: @test_simplify7(
+; CHECK-NEXT:    ret i1 true
+;
+  %hello_p = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  %ne_hello = icmp ne i64 %hello_l, 0
+  ret i1 %ne_hello
+}
+
+define i1 @test_simplify8(i16* %str_p) {
+; CHECK-LABEL: @test_simplify8(
+; CHECK-NEXT:    [[STRLENFIRST:%.*]] = load i16, i16* [[STR_P:%.*]], align 2
+; CHECK-NEXT:    [[NE_NULL:%.*]] = icmp ne i16 [[STRLENFIRST]], 0
+; CHECK-NEXT:    ret i1 [[NE_NULL]]
+;
+  %str_l = call i64 @wcslen(i16* %str_p)
+  %ne_null = icmp ne i64 %str_l, 0
+  ret i1 %ne_null
+}
+
+define i64 @test_simplify9(i1 %x) {
+; CHECK-LABEL: @test_simplify9(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i64 5, i64 6
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %hello = getelementptr [6 x i16], [6 x i16]* @hello, i64 0, i64 0
+  %longer = getelementptr [7 x i16], [7 x i16]* @longer, i64 0, i64 0
+  %s = select i1 %x, i16* %hello, i16* %longer
+  %l = call i64 @wcslen(i16* %s)
+  ret i64 %l
+}
+
+; Check the case that should be simplified to a sub instruction.
+; wcslen(@hello + x) --> 5 - x
+
+define i64 @test_simplify10(i16 %x) {
+; CHECK-LABEL: @test_simplify10(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[X:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i64 5, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %hello_p = getelementptr inbounds [6 x i16], [6 x i16]* @hello, i16 0, i16 %x
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 7)) --> 9 - (x & 7)
+
+define i64 @test_simplify11(i16 %x) {
+; CHECK-LABEL: @test_simplify11(
+; CHECK-NEXT:    [[AND:%.*]] = and i16 [[X:%.*]], 7
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[AND]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i64 9, [[TMP1]]
+; CHECK-NEXT:    ret i64 [[TMP2]]
+;
+  %and = and i16 %x, 7
+  %hello_p = getelementptr inbounds [13 x i16], [13 x i16]* @null_hello_mid, i16 0, i16 %and
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+; Check cases that shouldn't be simplified.
+
+define i64 @test_no_simplify1() {
+; CHECK-LABEL: @test_no_simplify1(
+; CHECK-NEXT:    [[A_L:%.*]] = call i64 @wcslen(i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a, i64 0, i64 0))
+; CHECK-NEXT:    ret i64 [[A_L]]
+;
+  %a_p = getelementptr [32 x i16], [32 x i16]* @a, i64 0, i64 0
+  %a_l = call i64 @wcslen(i16* %a_p)
+  ret i64 %a_l
+}
+
+; wcslen(@null_hello + x) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify2(i16 %x) {
+; CHECK-LABEL: @test_no_simplify2(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[X:%.*]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i16], [7 x i16]* @null_hello, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i16* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i16], [7 x i16]* @null_hello, i16 0, i16 %x
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+; wcslen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.
+
+define i64 @test_no_simplify3(i16 %x) {
+; CHECK-LABEL: @test_no_simplify3(
+; CHECK-NEXT:    [[AND:%.*]] = and i16 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[AND]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i16], [13 x i16]* @null_hello_mid, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i16* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %and = and i16 %x, 15
+  %hello_p = getelementptr inbounds [13 x i16], [13 x i16]* @null_hello_mid, i16 0, i16 %and
+  %hello_l = call i64 @wcslen(i16* %hello_p)
+  ret i64 %hello_l
+}
+
+@str32 = constant [1 x i32] [i32 0]
+
+; This could in principle be simplified, but the current implementation bails on
+; type mismatches.
+define i64 @test_no_simplify4() {
+; CHECK-LABEL: @test_no_simplify4(
+; CHECK-NEXT:    [[L:%.*]] = call i64 @wcslen(i16* bitcast ([1 x i32]* @str32 to i16*))
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %l = call i64 @wcslen(i16* bitcast ([1 x i32]* @str32 to i16*))
+  ret i64 %l
+}