Как я могу найти размер типа?
Я держу Type*
в руке. Как узнать его размер (объекты размера этого типа будут занимать в памяти) в битах/байтах? Я вижу всевозможные методы, позволяющие мне получить "примитивный" или "скалярный" размер, но это не поможет мне с агрегатными типами...
Ответы
Ответ 1
Размер зависит от цели (по нескольким причинам, одним из которых является выравнивание).
С LLVM до версии 3.1 (в том числе), поэтому вам нужно использовать TargetData
, в частности его метод getTypeAllocSize
. Это возвращает размер в байтах, там также бит версии с именем getTypeAllocSizeInBits
. Экземпляр TargetData
можно получить, создав его из текущего модуля: TargetData* TD = new TargetData(M)
.
В версиях LLVM версии 3.2 и выше тип DataLayout заменяет TargetData
. Однако он предоставляет те же методы getTypeAllocSize
.
Ответ 2
Если вам нужен только размер, потому что вы вставляете его в ИК-порт (например, чтобы отправить его на вызов malloc()
), вы можете использовать инструкцию getelementptr
для выполнения грязной работы (с помощью малое кастинг), описанный здесь (с обновлением для современного LLVM):
Хотя LLVM не содержит специального назначения sizeof
/offsetof
, getelementptr
может использоваться для оценки этих значений. Основная идея заключается в использовании getelementptr
из указателя null
для вычисления значения по желанию. Поскольку getelementptr
выводит значение в качестве указателя, результат заносится в целое число перед использованием.
Например, чтобы получить размер какого-либо типа, %T
, мы будем использовать что-то вроде это:
%Size = getelementptr %T* null, i32 1
%SizeI = ptrtoint %T* %Size to i32
Этот код эффективно притворяется, что существует массив элементов T
, начиная с указателя null
. Это получает указатель на второй элемент T
(элемент # 1) в массиве и рассматривает его как целое. Это вычисляет размер одного элемента T
.
Хорошая вещь заключается в том, что это полезно в тех случаях, когда вам не важно, что такое значение; где вам просто нужно передать правильное значение из IR на что-то. Это, безусловно, самый распространенный случай для моей потребности в sizeof()
-аликих операциях в генерации IR.
Далее также описывается, как выполнить эквивалент offsetof()
:
Чтобы получить смещение некоторого поля в структуре, используется подобный трюк. Для Например, чтобы получить адрес второго элемента (элемент # 1) { i8, i32* }
(что зависит от требования выравнивания цели для указателей), что-то как это следует использовать:
%Offset = getelementptr {i8,i32*}* null, i32 0, i32 1
%OffsetI = ptrtoint i32** %Offset to i32
Это работает так же, как трюк sizeof
: мы притворяемся, что есть экземпляр тип указателя null
и получить адрес интересующего нас поля in. Этот адрес является смещением поля.
Обратите внимание, что в обоих случаях выражение будет оцениваться как постоянное время генерации кода, поэтому для использования этого Методика.
Оптимизатор IR также преобразует значения в константы.