Какое копирование elision на самом деле делает для структур? - PullRequest
0 голосов
/ 16 мая 2018

Общее мнение о программировании на Swift (по состоянию на май 2018 г., Swift 4.1, Xcode 9.3) заключается в том, что структуры должны быть предпочтительными, если ваша логика явно не требует общей ссылки на объект.

Как мы знаем,проблема со структурами заключается в том, что они передаются по значению, и поэтому копия создается при передаче структуры или возвращении из функции.Если у вас есть большая структура (скажем, с 12 свойствами в ней), то это копирование может стать дорогим.

Обычно это защищают люди, которые говорят, что быстрый компилятор и / или LLVM могут удалить копии (т.е. передатьссылка на структуру, а не на ее копирование), и ее нужно делать только в том случае, если вы действительно изменили структуру.

Это все хорошо, но об этом всегда говорят в теоретических терминах - «Как оптимизация, LLVM может исключить копии "и все в таком духе.

Мой вопрос: кто-нибудь может сказать нам, что на самом деле происходит ? Действительно ли компилятор исключает копии, или это просто теоретическая оптимизация будущего, которая может когда-нибудь существовать? (Например, компилятор C # также теоретически может исключать структурные копии, но на самом деле он этого не делает, и Microsoft рекомендует не использовать структуры для вещей размером более 16 байт [1])

Если swift делает elide struct copy, есть ли какое-то объяснение или эвристика относительно того, если и когда это происходит?

Примечание: я говорю о пользовательских структурах, а не о встроенных в stdlib вещах, таких как массивы исловари

[1] https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct

1 Ответ

0 голосов
/ 16 мая 2018

Во-первых, Swift не использует соглашение о вызовах платформы.В macOS, C, C ++ и Objective-C все используют x86_64 System V ABI, а Swift - нет.Заметным изменением является то, что CC Swift имеет четыре возвращаемых GPR (rax, rdx, rcx, r8) вместо двух.

Это почти наверняка усложняется, когда вы смешиваете числа с плавающей запятой, но если вы идетевсе целочисленные и целочисленные типы (например, указатели), структуры передаются и возвращаются регистром, копией, если они вписываются в ширину не более 4 регистров.Кроме того, структуры передаются и возвращаются по адресу.В случае возвращаемого значения вызывающий отвечает за настройку стекового пространства и передачу адреса этого пространства вызываемому объекту в качестве скрытого параметра.

Поскольку Swift ABI не завершен, это все ещеВозможны изменения, возможно.

Однако простое прохождение указателей не означает, что копий не происходит.Например:

public class Let {
    let large: Large

    init(large: Large) {
        self.large = large
    }
}

public func withLet(l: Let) {
    doSomething(foo: l.large)
}

В этом примере, -O в Swift 4.1, withLet делает следующий компромисс:

  • l.large копируется в локальный временный
  • l высвобождается после копирования, а до doSomething вызывается

Копия будет неизбежна с изменяемым или вычисляемым свойством (поскольку ихзначение может изменяться в течение всего времени вызова), но я предполагаю, что в сфере возможностей могут быть переданы let константы по адресу напрямую.Однако в этом случае l придется остаться в живых до тех пор, пока не вернется doSomething.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...