Array.Copy() tries to make the copy efficient by using the memmove()
CRT function, a raw memory-to-memory copy without regard for the actual type stored in the array. It can be substantially more efficient if the array element type is smaller than the natural processor word size.
So you need to know whether memmove() can provide the atomicity guarantee. That is an tricky question that the CLR programmer answered unambiguously. Atomiticy is an essential trait for object references, the garbage collector cannot operate correctly when it can't update those references atomically. So the programmer special-cases this in the CLR code, the comment he provided tells you what you want to know (edited to fit):
// The CRT version of memmove does not always guarantee that updates of
// aligned fields stay atomic (e.g. it is using "rep movsb" in some cases).
// Type safety guarantees and background GC scanning requires object
// references in GC heap to be updated atomically.
That's a very pessimistic view on life. But clearly no, you can't assume Array.Copy() is atomic when the CLR author did not make this assumption.
Practical consideration do perhaps need to prevail. On reasonably common architectures, x86 and x64 have a memmove() implementation that don't make the CLR memory model guarantees worse, they copy 4 or 8 aligned bytes at a time. And practically the for-loop in the generic code substitute is not guaranteed to be atomic since T is not guaranteed to be.
Most practical is that you ought not have to ask the question. Atomicity only matters when you have another thread that is accessing the arrays without any synchronization. Writes to the source array or reads from the destination array. That is however a guaranteed threading race. Writes to the source array are worst, the copy has an arbitrary mix of old and new data. Reads from the destination array randomly produce stale data, like a threading bug normally does. You have to be quite courageous to risk this kind of code.