LINUX.ORG.RU

Как в llvm узнать размер и выравнивание типа?

 


0

2

Никак не могу найти как в llvm узнать размер и выравнивание типа.
Пример:
...
%struc.k = type {i8 , i16}
...
%1=размер struc.k
%2=выравнивание struc.k
В %1 должно быть 4, а в %2 должно быть 2.



Последнее исправление: Taetricus (всего исправлений: 1)

кто вам должен?

anonymous
()

размер

%foo = type { i8, i16 }

%foo-packed = type <{ i8, i16 }>

    %1 = getelementptr %foo* null, i64 1
    %2 = ptrtoint %foo* %1 to i64               ; 4

    %3 = getelementptr %foo-packed* null, i64 1
    %4 = ptrtoint %foo-packed* %3 to i64        ; 3

размер и выравнивание

target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

%foo = type { i8, i16 } ; использовать непосредственно 4 и 2 в виде констант

%foo-packed = type <{ i8, i16 }> ; 3 и 1

Если есть фронтенд, то datalayout выставляется в нём, эти константы тоже берутся на стадии генерации IR - http://llvm.org/docs/doxygen/html/classllvm_1_1ConstantExpr.html.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

И так же - разница адресов полей:

    %1 = getelementptr inbounds %foo* null, i32 0, i32 0
    %2 = getelementptr inbounds %foo* null, i32 0, i32 1
    %3 = ptrtoint i8* %1 to i64
    %4 = ptrtoint i16* %2 to i64
    %5 = sub i64 %4, %3	                ; 2

оба оптимизируются непосредственно в константы 4 и 2, но проще их и использовать, выставив datalayout или сверившись с дефолтными значениями, ну либо писать IR фронтендом.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Спасибо, в плане размера то, что я и хотел.
Правильно ли я понял, что если я пропишу в datalayout нужное выравнивание для базовых типов, то в данном примере:
%foo = type { i8, i16 }
...
%1 = alloca i32
...
адрес в %1 будет выровнен по 2-х байтой границе?

оба оптимизируются непосредственно в константы 4 и 2, но проще их и использовать, выставив datalayout или сверившись с дефолтными значениями


Я просто хотел чтобы ll код для разных платформ был более менее одинаков, а размеры указателей на разных платформах отличаются, следовательно если пользователь напишет программу в которой ему нужно будет узнать размер типа то для разных платфор он должен получать разные значения.

quasimoto
Если вы неплохо знаете llvm, можно ли к вам обращаться с вопросами?
А то я пишу компилятор для своего ЯП, в начале писал чтобы код сразу транслировался в ассемблер, но затем решил, что рациональнее использовать llvm так как, некоторые проблемы которые пришлось решать мне, уже решены разработчики llvm.
На асме 7 лет и при написании компилятора вопросов не возникало, а llvm начал изучать недавно и возникают вопросы, а документации на русском практически нет.

Taetricus
() автор топика
Ответ на: комментарий от Taetricus

Правильно ли я понял, что если я пропишу в datalayout

Нет, там имеется в виду, что для того чтобы подобрать правильные константы для size и align у данной структуры нужно знать свойства целевой платформы, просто выставление datalayout ничего не даст - http://llvm.org/docs/LangRef.html#data-layout (та часть где «The function of the data layout string may not be what you expect»).

адрес в %1 будет выровнен по 2-х байтой границе?

http://llvm.org/docs/LangRef.html#alloca-instruction

Это должно быть что-то вроде:

    %1 = alloca i8, align 8
    %2 = alloca i16, align 8
    %3 = alloca i32, align 8
    %4 = alloca i64, align 8
    %5 = alloca %foo, align 8
    ; ^ везде выровнено по 8-ми байтной границе

Я просто хотел чтобы ll код для разных платформ был более менее одинаков

Если разрабатываемый язык достаточно низкоуровневый, в частности, поддерживает основные типы архитектуры, завязывается на ABI платформы, имеет sizeof и т.п., то IR код будет разный, в том смысле, что просто так не получится его переносить.

Так что pipeline должен быть такой:

исходный код -> front-end (компилятор) -> llvm [IR есть, но просто в памяти] -> elf / pe / mach-o

В случае AOT или

runtime -> исходный код -> встроенный компилятор -> llvm execution engine [IR] -> результат + эффекты -> runtime

в случае JIT.

То есть IR вообще руками не предполагается писать, предполагается писать фронтенд (то есть AOT компилятор или кусок рантайма) на C++ или любом языке у которого есть хороший биндинг к LLVM.

если пользователь напишет программу в которой ему нужно будет узнать размер типа то для разных платфор он должен получать разные значения.

http://nondot.org/sabre/LLVMNotes/SizeOf-OffsetOf-VariableSizedStructs.txt

http://llvm.org/docs/doxygen/html/Constants_8cpp_source.html («sizeof is implemented as» и далее)

то есть можно нагенерировать таких инструкций.

Но, как я понимаю, правильнее будет использовать llvm::ConstantExpr для независящих от архитектуры типов, llvm::TargetData для всего остального, либо что-то своё если распределением структур занимается свой рантайм. То есть вычисление sizeof и т.п. должно происходить в самом компиляторе. Например, clang сам вычисляет размеры, так что если посмотреть IR без оптимизаций, то там будут просто константы (разные на разных архитектурах).

А то я пишу компилятор для своего ЯП

Чтобы реализовать ЯП над LLVM лучшего пути чем чтение официальной документации и туториалов, исходников LLVM и исходников существующих компиляторов (clang и rust, например) я не вижу.

quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.