Как я могу найти размер типа?

Я держу 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 также преобразует значения в константы.