M1 Icestorm cores can still perform well
A couple of people seem surprised that the &quot;idiomatic&quot; Swift code seems to perform much worse. Unfortunately the blog post doesn&#x27;t provide much details on the code it is actually running, so I tried my hand at guessing:<p><pre><code>  let vC = [Float](repeating: 1, count: 4)
  
  func unidiomatic() -&gt; Float {
      var vA = [Float](repeating: 0, count: 4)
      let vB = [1, 2, 3, 4] as [Float]
      var tempA: Float = 0.0
      for _ in 0..&lt;1000 {
          for i in 0...3 {
              tempA += vA[i] * vB[i]
          }
          for i in 0...3 {
              vA[i] = vA[i] + vC[i]
          }
      }
      return tempA
  }
  
  func idiomatic() -&gt; Float {
      var vA = [Float](repeating: 0, count: 4)
      let vB = [1, 2, 3, 4]  as [Float]
      var tempA: Float = 0.0
      for _ in 0..&lt;1000 {
          tempA = zip(vA, vB).map(*).reduce(0, +)
          for (index, value) in vA.enumerated() {
              vA[index] = value + vC[index]
          }
      }
      return tempA
  }
</code></pre>
When compiled with optimizations (it&#x27;s unclear if the author did this?), the &quot;idiomatic&quot; code here is indeed much worse. It&#x27;s easy to fix the worst of that by working on a lazy sequence, i.e.<p><pre><code>  tempA = zip(vA, vB).lazy.map(*).reduce(0, +)
</code></pre>
which will save on an extra array allocation and instead run the sum &quot;in place&quot; (in this case, vB is recognized as a constant and in both cases and distributed accordingly). Unfortunately there is still a small amount of overhead because zip doesn&#x27;t know that the arrays are of the same length, so the compiler inserts some extra bounds checks; also, the second loop gets transformed into what is essentially<p><pre><code>  temp = __swift_intrisic_move(vA)
  for (index, value) in vA.enumerated() {
      temp[index] = value + vC[index]
  }
  vA = __swift_intrisic_move(temp)
</code></pre>
but this should ideally bring the performance of the two much closer.