Передача структур по значению в соответствии с соглашением о вызовах C в LLVM IR - PullRequest
0 голосов
/ 15 декабря 2018

Я хотел бы передать структуры по значению между C ++ и JL'd-программой LLVM.Я видел много дискуссий по этому поводу и даже несколько вопросов о SO.Я читал, что мне нужно сделать то, что называется «приведение аргументов», если я хочу, чтобы моя программа действительно передавала по значению.Использование byval и sret выглядит как простое кроссплатформенное решение.Это по-прежнему немного болезненно, и код C ++ должен помнить о том, чтобы передавать указатели вместо значений (хотя вызывающий код - C ++, поэтому я мог бы использовать магию шаблонов).

Чем больше я читаю об этой проблеметем меньше я, кажется, это понимаю.Соглашение о вызовах - это специфическая для платформы проблема, которую должен решать генератор кода, верно?Я не понимаю, почему генератор кода, специфичный для платформы, не просто имеет дело со специфическим для платформы способом обработки структур (в соответствии с C ABI платформы).Внешний интерфейс должен быть независимым от платформы!

Есть ли проход, который приводит меня к аргументации?Проход, который посещает каждое объявление функции и каждый вызов функции и преобразует все структуры так, чтобы они были совместимы с C ABI платформы?Я чувствую, что это то, что использовали бы все интерфейсы, если бы он существовал, а Clang не использовал его, так что, возможно, это невозможно.Почему это не жизнеспособное решение?Если проход может иметь дело только с этим, то я бы ожидал, что он будет частью LLVM.

Я не понимаю, почему каждый фронтенд должен выполнять приведение аргументов.Я даже не понимаю, как применять аргументацию.Я видел несколько случаев, когда люди брали код генерации кода Clang и выделяли часть, которая выполняет приведение аргументов.К сожалению, это кажется лучшим решением, если я хочу реальной совместимости с C ABI.Тот факт, что даже можно повторно использовать часть другого интерфейса для совершенно другого языка, заставляет меня продолжать задаваться вопросом, почему это должно быть сделано в интерфейсе?

Что-то должно быть сделано с этим!Мы не можем просто продолжать писать один и тот же код совместимости с C ABI в каждом интерфейсе.Это нелепо!Может быть, я просто не понимаю.

Может кто-нибудь прояснить это для меня?Я думаю об использовании byval и sret просто потому, что это проще, чем модифицировать генератор кода Clang.Есть ли более простой способ?

1 Ответ

0 голосов
/ 15 декабря 2018

При обходе структур по значению в LLVM IR вы должны составить свои собственные правила.Я выбрал простейший набор правил из всех возможных.

Допустим, у меня есть такая программа:

struct MyStruct {
  int a;
  char b, c, d, e;
};

MyStruct identityImpl(MyStruct s) {
  return s;
}

MyStruct identity(MyStruct s) {
  return identityImpl(s);
}

IR LLVM для этой программы эквивалентен следующему:

void identityImpl(MyStruct *ret, const MyStruct *s) {
  MyStruct localS = *s;
  *ret = localS;
}

void identity(MyStruct *ret, const MyStruct *s) {
  MyStruct localS = *s;
  MyStruct localRet;
  identityImpl(&localRet, &localS);
  *ret = localRet;
}

Это не самый эффективный способ передачи структуры, потому что MyStruct может помещаться в 64-битный регистр.Однако оптимизатор может удалить localS и использовать s напрямую, если он может доказать, что localS никогда не записывается в.Обе эти функции оптимизируются до одного вызова memcpy.

Это заняло всего полдня.Переход по маршруту Clang, вероятно, занял бы не менее недели.Я все еще думаю, что довольно прискорбно, что я должен был сделать это, но теперь я понимаю проблему.Передача структур не определяется C ABI платформы.

...