Как избежать нежелательного сворачивания констант, выполняемого генератором кода LLVM?

Я пытаюсь избежать сворачивания некоторых констант (которые представляют адреса в моем коде), таких как константа 100000000 ниже. Мне это нужно, потому что позже JIT-скомпилированный код может быть исправлен, что изменяет константы из-за перемещения объекта.

Приведенный ниже код - это моя лучшая попытка избежать сворачивания констант (любой ценой). Не работает. Я получаю константу 100011111 в потоке инструкций.

llc -O0 code.ll -print-after-all показывает, что фолд происходит на Expand ISel Pseudo-instructions проходе.

; ModuleID = '0'
target triple = "x86_64-unknown-linux-gnu"

define  i64 @"0"() {
BlockEntry0:
  %cell = alloca i64, align 8
  store volatile i64 0, i64* %cell, align 8
  %volatile_zero3 = load volatile i64, i64* %cell, align 8
  %base = add i64 %volatile_zero3, 100000000
  %volatile_zero4 = load volatile i64, i64* %cell, align 8
  %opaque_offset = add i64 %volatile_zero4, 11111
  %casted_base = inttoptr i64 %base to i8*
  %gep = getelementptr i8, i8* %casted_base, i64 %opaque_offset
  %as_ptr = bitcast i8* %gep to i64*
  %loaded = load i64, i64* %as_ptr, align 4
  %as_function = inttoptr i64 %loaded to i64 (i64)*
  %ret_val = tail call i64 %as_function(i64 0)
  ret i64 %ret_val
}

attributes #0 = { nounwind }

Я понимаю, что мою проблему можно решить, добавив некоторые внутренние компоненты, которые на уровне кодогенерации развернутся до простых movabs reg, imm64. Но я хотел бы на время иметь временное решение.

Вопрос: можно ли сделать в llvm непрозрачную константу, которая не сворачивается?

Моя версия llvm - 3.7.0svn.


person Vladislav Ivanishin    schedule 03.08.2015    source источник
comment
Если значение изменится, действительно ли имеет смысл использовать константу? Может быть, вместо этого использовать глобальную переменную с постоянным инициализатором?   -  person Ismail Badawi    schedule 03.08.2015
comment
@IsmailBadawi, хорошие мысли. Это решило бы проблему, но производительность здесь вызывает беспокойство (на самом деле, это конечная цель). Хотя я не уверен, что эти дополнительные нагрузки действительно повлияют на ситуацию, если мы примем во внимание LICM. Возможно, я попробую использовать глобальный / константный пул, если нет более простого способа.   -  person Vladislav Ivanishin    schedule 03.08.2015
comment
Мне кажется, что исправление кода подвержено ошибкам. Как найти 1000000 и как узнать, что некоторые 1000000 - это то, что вы действительно хотите исправить, а не какой-то артефакт генерации кода, полностью независимый от вашей константы и используемый для других целей (например, битовая маска)? Опять же, если бы вы каким-то образом точно знали, что патчить, вы могли бы просто позволить компилятору сворачивать константы и исправлять константные свернутые результаты ...   -  person Erik Eidt    schedule 04.08.2015
comment
@ErikEidt, я помню адреса (они всегда делаются 64-битными), которые я мог бы исправить - здесь нет проблем. Позже, когда будет выпущен собственный код, я дизассемблирую его (с помощью дизассемблера MC), ищу инструкции, содержащие imm64 в качестве операнда (AFAIK их только 2 в наборе инструкций x64), и проверяю, является ли imm64 одной из констант, которые я отслеживаю. . Ваше второе наблюдение верно: если есть битовая маска, равная одному из моих адресов, я обречен. Я еще не сталкивался с такими большими битовыми масками, когда я понижался до LLVM IR, но я вижу, насколько хрупким является это предположение.   -  person Vladislav Ivanishin    schedule 04.08.2015
comment
@ErikEidt, я думаю, что внутренняя функция LLVM, которая просто перемещает const в регистр и запоминает смещение от начала функции (как это делают встроенные функции stackmap / patchpoint), была бы идеальной. Нет проблем с битовыми масками и т. Д. И без чрезмерных нагрузок. Я просто не знаю, сколько времени у меня уйдет на реализацию, поэтому ищу временное решение.   -  person Vladislav Ivanishin    schedule 04.08.2015


Ответы (1)


Нет, это невозможно. Лучше всего использовать внешнюю глобальную переменную, как упоминалось в комментариях. Фактически, для ваших целей это может быть именно то, что вы хотите сделать, поскольку в этот момент ваш jittable-код получит перемещение в соответствии с тем, что вы действительно хотите, и соответствующим образом исправит во время выполнения rtdyld.

Если вам нужна фактическая константа для jit-кода (например, для вызова определенного адреса, о котором вы знаете), то то, что вы делаете, прекрасно.

person echristo    schedule 04.08.2015
comment
Хорошо .. :) Проблема с глобальными переменными в том, что их тоже нужно где-то размещать. Если это куча, GC должен взять на себя контроль над ними. От измененного кода позже можно отказаться, так же как и соответствующие глобальные переменные. Хотя, думаю, это управляемо. Я открыл для себя llvm.experimental.gc.relocate intrinsic и друзья. Попробую пойти с ними с глобальными объектами в качестве запасного плана. Спасибо за вашу помощь! - person Vladislav Ivanishin; 04.08.2015
comment
Правильно. Я ожидал, что они на самом деле были просто внешними константами, которые где-то находились, иначе вы могли бы передать их в качестве аргументов своей функции. Если они действительно константы, вы могли бы иметь проход оптимизации, который запускается во время джиттинга наверху, который заменяет некоторые именованные переменные, которые у вас есть в вашей программе, на правильные значения. - person echristo; 05.08.2015