Por que Clang coagir parâmetros de estrutura a ints

Ao usar parâmetros de estrutura em uma função, o clang altera a assinatura da função. Em vez de usar um tipo de estrutura, a assinatura será um int coagido de tamanho igual. No meu projeto de compilador, eu uso o tipo de estrutura llvm para a assinatura do método (que parece mais lógico).

Isso não seria um problema, exceto pelo fato de que a montagem resultante produzida pelo LLVM ao usar os tipos struct ou coerced é diferente e nãocompatível com chamadas. Isso resulta no meu compilador não sendo compatível com ABI com funções C com estruturas.

Por que o clang faz isso? Isso é algo especificado na C ABI?

Aqui está um exemplo simples de arquivo fonte C:

struct TwoInt { int a, b; };

struct EightChar { char a, b, c, d, e, f, g, h; };

void doTwoInt(struct TwoInt a) {}

void doEightChar(struct EightChar a) {}

int main()
{
        struct TwoInt ti;
        struct EightChar fc;

        doTwoInt(ti);
        doEightChar(fc);

        return 0;
}

LLVM-IR resultante de Clang

%struct.TwoInt = type { i32, i32 }
%struct.EightChar = type { i8, i8, i8, i8, i8, i8, i8, i8 }

define void @doTwoInt(i64 %a.coerce) nounwind uwtable {
  %a = alloca %struct.TwoInt, align 8
  %1 = bitcast %struct.TwoInt* %a to i64*
  store i64 %a.coerce, i64* %1, align 1
  ret void
}

define void @doEightChar(i64 %a.coerce) nounwind uwtable {
  %a = alloca %struct.EightChar, align 8
  %1 = bitcast %struct.EightChar* %a to i64*
  store i64 %a.coerce, i64* %1, align 1
  ret void
}

define i32 @main() nounwind uwtable {
  %1 = alloca i32, align 4
  %ti = alloca %struct.TwoInt, align 4
  %fc = alloca %struct.EightChar, align 1
  store i32 0, i32* %1
  %2 = bitcast %struct.TwoInt* %ti to i64*
  %3 = load i64* %2, align 1
  call void @doTwoInt(i64 %3)
  %4 = bitcast %struct.EightChar* %fc to i64*
  %5 = load i64* %4, align 1
  call void @doEightChar(i64 %5)
  ret i32 0
}

O que eu esperava (e o que meu compilador gera):

%TwoInt = type { i32, i32 }
%EightChar = type { i8, i8, i8, i8, i8, i8, i8, i8 }

define void @doTwoInt(%TwoInt %a) {
  %1 = alloca i32
  %2 = alloca %TwoInt
  store %TwoInt %a, %TwoInt* %2
  ret void
}

define void @doEightChar(%EightChar %a) {
  %1 = alloca i32
  %2 = alloca %EightChar
  store %EightChar %a, %EightChar* %2
  ret void
}

define i32 @main() {
  %1 = alloca i32
  %ti = alloca %TwoInt
  %fc = alloca %EightChar
  %2 = load %TwoInt* %ti
  call void @doTwoInt(%TwoInt %2)
  %3 = load %EightChar* %fc
  call void @doEightChar(%EightChar %3)
  ret i32 0
}

questionAnswers(1)

yourAnswerToTheQuestion