<p>To directly answer the question, those two lines of code generate different instructions, with differing performance characteristics and hardware pipeline usage.</p>

<pre><code>uint read_value = b.field;                 // generates a load instruction
uint read_value2 = atomicAdd(b.field, 0);  // generates an atomic instruction
</code></pre>

<ul>
<li><a href="http://shader-playground.timjones.io/0733f88ba4b8ddd197c0242b1273044d" rel="nofollow noreferrer">AMD disassembly can be seen in this online Shader Playground</a> -- <code>buffer_load_dword</code> versus <code>buffer_atomic_add</code></li>
<li><a href="https://arxiv.org/abs/1804.06826" rel="nofollow noreferrer">Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking</a> -- <code>LDG</code> versus <code>ATOM</code></li>
</ul>

<p>The <a href="https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.40.pdf" rel="nofollow noreferrer">GLSL spec</a> section 4.10 Memory Qualifiers makes a point that <code>coherent</code> is only about visibility of reads and writes across invocations (shader threads).  They also left a comment on the implied performance:</p>

<blockquote>
  <p>When accessing memory using variables not declared as coherent, the memory accessed by a shader may be cached by the implementation to service future accesses to the same address.  Memory stores may be cached in such a way that the values written might not be visible to other shader invocations accessing the same memory.  The implementation may cache the values fetched by memory reads and return the same values to any shader invocation accessing the same memory, even if the underlying memory has been modified since the first memory read.  While variables not declared as coherent might not be useful for communicating between shader invocations, using non-coherent accesses may result in higher performance.</p>
</blockquote>

<p>The point-of-coherence in GPU memory systems is usually the last-level cache (L2 cache), meaning all coherent accesses must be performed by the L2 cache.  This also means coherent buffers cannot be cached in L1 or other caches closer to the shader processors.  Modern GPUs also have dedicated atomic hardware in the L2 caches; a plain load will not use those, but an <code>atomicAdd(..., 0)</code> will go through those.  The atomic hardware usually has lower bandwidth than the full L2 cache.</p>
If a `buffer` is `coherent`, is there any difference between reading a field or doing `atomicAdd(field, 0)`?
<p>This is with Vulkan semantics, if it makes any difference.</p>

<p>Assume the following:</p>

<pre><code>layout(...) coherent buffer B
{
    uint field;
} b;
</code></pre>

<p>Say the field is being modified by other invocations of the same shader (or a derived shader) through <code>atomic*()</code> funcions.</p>

<p>If a shader invocation wants to perform an atomic read from this <code>field</code> (with the same semantics as <code>atomicCounter()</code> in GLES, had this been an <code>atomic_uint</code> instead), is there any difference between the following two (other than obviously that one of them does a write as well as read)?</p>

<pre><code>uint read_value = b.field;
uint read_value2 = atomicAdd(b.field, 0);
</code></pre>