如何告诉 clang 我的 LLVM 目标应该使用 16 位“int”?
Posted
技术标签:
【中文标题】如何告诉 clang 我的 LLVM 目标应该使用 16 位“int”?【英文标题】:How to tell clang that my LLVM Target should use 16-bit 'int'? 【发布时间】:2016-09-16 06:25:56 【问题描述】:对于我的 PIC 后端,我希望 'int' 为 16 位。我/我的目标如何告诉 clang 'int' 的大小应该是多少?仅定义 16 位寄存器似乎还不够。
目前“clang -O2 -emit-llvm -target pic”转换
int foo(int a, int b) return a + b;
到这个 IR 代码,使用 32 位整数:
; ModuleID = '../test/sum.c'
source_filename = "../test/sum.c"
target datalayout = "e-m:e-p:16:16-i16:16-a:0:16-n16-S16"
target triple = "pic"
; Function Attrs: norecurse nounwind readnone
define i32 @foo(i32 %a, i32 %b) local_unnamed_addr #0
entry:
%add = add nsw i32 %b, %a
ret i32 %add
attributes #0 = norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false"
!llvm.ident = !!0
!0 = !!"clang version 4.0.0 (http://llvm.org/git/clang.git 92920e1616528c259756dd8190d4a47058fae127) (http://llvm.org/git/llvm.git 7ca31361200d6bc8a75fa06f112083a8be544287)"
这可能是也可能不是我在PIC Backend: 16-bit registers / return type 中描述的“Return operand #1 has unhandled type i16”消息的原因。但是,在转向其他问题之前,我可能应该正确地确定 clang 输出中使用的类型。
【问题讨论】:
【参考方案1】:已解决:clang 从它自己的 Target 中获取 int(和其他类型)的大小,在 clang/lib/Basics/Targets.cpp 中定义。本机大小设置“-n16”不足以覆盖(默认?)i32 设置。而是:
IntWidth = 32;
IntAlign = 32;
在我的目标的构造函数中就可以了。
这也解决了奇怪的“未处理的返回类型 i16”问题。不知道为什么。
【讨论】:
【参考方案2】:我强烈建议养成使用 ISO/IEC 9899 包含文件 <stdint.h>
和 <stdbool.h>
的习惯。在您的情况下,您可以声明
int16_t foo(int16_t a, int16_t b) return a + b;
并且保证变量和返回值是 16 位有符号整数,与目标处理器无关。查看文件内容,或 ISO 文档附录 B.17(搜索 ISO/IEC 9899,您会很容易找到 pdf 文档),以查看所有类型选项。
这些包含文件(连同变量名称的前缀,如 u16foo 和 i32bar 以向我说明标识符的大小和签名)已经拯救了我的皮肤太多次了。
【讨论】:
当然,如果程序员打算使用特定尺寸,最好明确说明尺寸。然而,这并不能解决我的问题,原因有两个:a) int 的意思是“一个合理的、通常是原生的字长的整数”,在我的例子中是 16 位。 b) 当我使用 short(int16_t 实际上只是一个 typedef)时,我确实得到了 16 位参数和返回类型 - 但是,一旦我删除了“-O2”,LLVM 就会将它们转换为 i32,然后尝试添加和转换它又回来了——所有这一切都失败了,因为我没有 32 个算术或寄存器。 听起来像clang认为你的目标是32位。我不使用它,所以我无法评论配置或优化。关于使用 stdint typedefs,这是一个偏好/样式的问题。就个人而言,我从未观察到编译器会覆盖显式大小,无论优化级别如何。 相信我的回答完美解决了您的问题。您的开场白是“对于我的 PIC 后端,我希望 'int' 为 16 位。”这是 'stdint.h' 和它的表亲的目的。int16_t
是 typedef 无关紧要 - 重要的是对于给定的编译器和目标,int16_t
保证为您提供 16 位。您通过说您的构建在使用 short
时有效,这证明了我的观点,这是在 16 位目标上与 int16_t
等效的类型。如果您想要一个通用的解决方案(即“合理字长的整数”),我的回答不起作用,但这不是您所要求的。
这不是重点。 C 根据定义,在进行算术运算时,几乎所有内容都转换为 int。添加两个 int16_t 将创建一个 int 值,该值在赋值时转换回 int16_t - 除非:1. 编译器知道您的 uP 使用 16 位字,并且 2. 它可以证明结果是相同的。所以后端需要知道原生字的大小,我后端的作者必须告诉它。以上是关于如何告诉 clang 我的 LLVM 目标应该使用 16 位“int”?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Clang 在 C 程序中嵌入 LLVM 程序集或内在函数?