No. It's exactly the other way around. We could not give a crap whether it is a built in function, only whether it is pure or const. We do not special case built-in functions anywhere near this optimization.
~/sources/gcc/gcc (git)-[master]- :) $ grep BUILT_IN tree-ssa-sccvn.c
&& DECL_BUILT_IN (TREE_OPERAND (op->op0, 0))
&& gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
&& (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMCPY)
|| gimple_call_builtin_p (def_stmt, BUILT_IN_MEMPCPY)
|| gimple_call_builtin_p (def_stmt, BUILT_IN_MEMMOVE))
~/sources/gcc/gcc (git)-[master]- :) $ grep BUILT_IN tree-ssa-pre.c
~/sources/gcc/gcc (git)-[master]- :( $
The special casing you see in the first part is trying to constant fold a few built-in calls in a utility function, and trying to see through memcpys for memory state.The reason the optimization proceeds is because strlen gets marked as pure by the compiler if there is no non-pure definition that overrides it.
Basically, the compiler defines a function named "strlen" that is pure and nothrow behind your back, but you can override it by providing your own definition. This is unrelated to whether it is a builtin (because the builtin version is __builtin_strlen)