Looping with UInt64


(Gerriet M. Denkmann) #1

With:
let nbrBytes = 400_000_000
let localArray = UnsafeMutablePointer<UInt8>.allocate(capacity: nbrBytes)
// touch every page before summing:
for i in 0 ..< nbrBytes / 4096 { localArray[ 4096 * i ] = 1 }

This rather innocent loop:
var count: UInt64 = 0
for index in 0 ..< loopLimit { count += UInt64( localArray[ Int(index) ] ) }

takes 2.4 times as long if preceded by:
  let loopLimit = UInt64(nbrBytes)
compared to:
  let loopLimit = Int(nbrBytes)

Why can’t Swift iterate in UInt64 as efficient as with Int?
Any real issue here which I am overlooking or just a compiler bug?

Gerriet.


(Greg Parker) #2

Looks like missed optimization opportunities due to the signedness of the index.

If the index is a signed type (Int, Int32, Int64) then the compiler optimizes away all of the integer overflow checks and performs two operations per loop iteration.
If the index is unsigned (UInt, UInt32, UInt64) then the compiler doesn't unroll the loop and doesn't remove all of the overflow checks.
I don't see any reason why the same optimizations would be disallowed in the unsigned case so it's probably a gap in some optimizer pass somewhere.

···

On Oct 11, 2016, at 11:04 PM, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

With:
let nbrBytes = 400_000_000
let localArray = UnsafeMutablePointer<UInt8>.allocate(capacity: nbrBytes)
// touch every page before summing:
for i in 0 ..< nbrBytes / 4096 { localArray[ 4096 * i ] = 1 }

This rather innocent loop:
var count: UInt64 = 0
for index in 0 ..< loopLimit { count += UInt64( localArray[ Int(index) ] ) }

takes 2.4 times as long if preceded by:
  let loopLimit = UInt64(nbrBytes)
compared to:
  let loopLimit = Int(nbrBytes)

Why can’t Swift iterate in UInt64 as efficient as with Int?
Any real issue here which I am overlooking or just a compiler bug?

--
Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler