【问题标题】:Why does clang output alignment specific things为什么clang输出对齐特定的东西
【发布时间】:2017-01-06 18:01:54
【问题描述】:

假设我有一个 c 的基本程序,我用 clang 编译它,如下所示:

#include "stdio.h"
int x = 0x7FFFFFFF;
int main(void)
{

    printf("%d\n",x);
}

clang -emit-llvm temp.c -fno-rtti -O3 -S 编译它会产生以下位码:

; ModuleID = 'temp.c'
target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i686-pc-linux-gnu"

@x = global i32 2147483647, align 4
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1

; Function Attrs: nounwind
define i32 @main() #0 {
entry:
  %0 = load i32, i32* @x, align 4, !tbaa !1
  %call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %0) #1
  ret i32 0
}

; Function Attrs: nounwind
declare i32 @printf(i8* nocapture readonly, ...) #0

attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }

!llvm.ident = !{!0}

!0 = !{!"clang version 3.7.1 "}
!1 = !{!2, !2, i64 0}
!2 = !{!"int", !3, i64 0}
!3 = !{!"omnipotent char", !4, i64 0}
!4 = !{!"Simple C/C++ TBAA"}

现在我真正的问题是关于引用变量x 的行。如果您注意到,x 似乎被声明为对齐变量(它与 4 对齐)。

clang 怎么知道ints 应该对齐?我的主张是,clang 对任何变量的对齐方式一无所知,因为这取决于您使用的后端。例如,我可以为 8 位机器使用后端,那么它根本不需要对齐。

所以我的问题是:为什么铿锵会猜测对齐,因为它确实不可能?

【问题讨论】:

  • 不知道是因为target triple = "i686-pc-linux-gnu"吗?
  • 您下载了特定拱门的 clang 版本....
  • @NathanOliver 这可能......我什至没有看到......
  • 编译器将为它所在的平台编译它,除非您指定不同的 AFAIK。
  • @DarthRubik looks like 可能。

标签: c++ c alignment clang llvm


【解决方案1】:

看着LLVM MAN

模块可以指定特定于目标的数据布局字符串,该字符串指定数据在内存中的布局方式。数据布局的语法很简单:

target datalayout = "layout specification"

布局规范由一个以减号字符 (‘-‘) 分隔的规范列表组成。每个规范都以一个字母开头,并且可能在字母之后包含其他信息,以定义数据布局的某些方面。接受的规格如下:

[...]

n : : ...

这为目标 CPU 指定一组原生整数宽度(以位为单位)。例如,它可能包含用于 32 位 PowerPC 的 n32、用于 PowerPC 64 的 n32:64 或用于 X86-64 的 n8:16:32:64。该集合的元素被认为可以有效地支持大多数通用算术运算。

强调我的

当 LLVM 确定给定类型的对齐方式时,它使用以下规则:

如果所寻找的类型与某一规范完全匹配,则使用该规范。

  1. 如果没有找到匹配,并且寻找的类型是整数类型,那么 大于位宽的最小整数类型 使用了寻找的类型。
  2. 如果没有一个规范大于位宽,则 使用最大整数类型。例如,给定默认值 上面的规格,i7类型会使用i8的对齐方式(接下来 最大)而 i65 和 i256 都将使用 i64 的对齐方式 (指定的最大)。
  3. 如果未找到匹配项,并且寻找的类型是向量类型,则 小于寻找的向量类型的最大向量类型将 用作后备。发生这种情况是因为 可以 例如,以 64 的形式实现。

++全局变量**

[...]

可以为全局指定显式对齐,它必须是 2 的幂。如果不存在,或者如果对齐设置为零,则全局的对齐由目标设置为任何它感觉很方便。如果指定了明确的对齐方式,则全局强制使用该对齐方式。

强调我的

【讨论】:

  • 好的,那么问题就变成了:如果编译器已经知道int 有多大(从您刚刚描述的目标数据布局中),那么为什么稍后还要指定对齐方式? (它应该不需要,因为它已经知道一个 int 与 4 对齐)
  • 我更新了。每次遇到变量时都会根据布局和规范评估对齐方式。
猜你喜欢
  • 1970-01-01
  • 2020-09-07
  • 2020-09-03
  • 2021-05-10
  • 1970-01-01
  • 2022-07-06
  • 2012-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多