ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

类型转换一次搞懂:mapping-high-level-constructs-to-llvm-ir中LLVM IR类型转换(casts)实用指南

2026/8/23 10:20:58 拓冰建站 浏览量
类型转换一次搞懂:mapping-high-level-constructs-to-llvm-ir中LLVM IR类型转换(casts)实用指南 类型转换一次搞懂mapping-high-level-constructs-to-llvm-ir中LLVM IR类型转换casts实用指南【免费下载链接】mapping-high-level-constructs-to-llvm-irA guide that explains how high level programming language constructs are mapped to the LLVM intermediate language.项目地址: https://gitcode.com/gh_mirrors/ma/mapping-high-level-constructs-to-llvm-irmapping-high-level-constructs-to-llvm-ir是一本解释 C/C 高层语法如何逐条映射到 LLVM IR 的开源书籍项目。本文带你一次性搞懂LLVM IR 类型转换casts9 种转换指令是什么、怎么选、有哪些常见坑全部基于书中真实示例10 分钟掌握 LLVM IR 类型转换的实用核心。 为什么新手要先看懂 LLVM IR 类型转换在 C 语言里word byte;这样的赋值会被编译器静悄悄地完成隐式转换你几乎感知不到它的存在。但在 LLVM IR 中每一次转换都必须写成一条显式指令——这正是这本书的价值把高层语言的魔法拆开给你看。读懂类型转换指令你能获得两项能力读得懂编译器任何 C/C 代码编译后的 IR 里都大量出现zext、trunc等指令看懂它们才能读懂 IR写得出代码生成器如果你打算实现一门语言Python、Rust、DSL…到 LLVM 的后端类型转换是必须亲手处理的第一块积木。书中以 32 位目标机为例、并使用未修饰的清晰命名就是为了降低 LLVM IR 的学习曲线见README.md的项目说明。 9 种 cast 指令全景图一张表记住全部LLVM IR 共有9 种类型转换指令按作用对象可分为 4 大类指令类别作用典型示例bitcast位级转换重新解释比特模式不改变任何一位i8*→struct*zext零扩展无符号整数变宽i8→i32sext符号扩展有符号整数变宽i8 -17→i32 -17trunc截断整数变窄有符号/无符号通用i32→i8fpext浮点扩展浮点数变宽float→doublefptrunc浮点截断浮点数变窄double→floatptrtoint指针→整数把指针转成整数i8*→i32inttoptr整数→指针把整数转回指针i32→i8*addrspacecast地址空间转换指针在地址空间之间转换通用指针 → 受限地址空间 记忆口诀变宽看扩展zext/sext/fpext变窄看截断trunc/fptrunc换解释看 bitcast穿墙看 ptrtoint/inttoptr。 如何快速选对转换指令3 步判断法遇到一个转换需求按下面 3 个问题决策即可变宽还是变窄变宽 → 扩展类指令zext/sext/fpext变窄 → 截断类指令trunc/fptrunc整数还是浮点数整数 →zext/sext/trunc浮点 →fpext/fptrunc有符号还是无符号仅限整数变宽无符号 →zext高位补 0有符号 →sext高位复制符号位特殊场景只改变指针的解释方式而不改值用bitcast系统编程中需要对指针做算术时先用ptrtoint转成整数算完再用inttoptr转回来。 书中原例解读3 个高频转换场景以下示例全部来自项目basic-constructs/casts.rst章节配合basic-constructs/listings/中的源码可以逐一对照。场景 1bitcast 重解释 malloc 返回的指针C 里给结构体分配内存时(Foo *) malloc(...)这一步在 IR 中就是一个bitcastFoo *foo (Foo *) malloc(sizeof(Foo));%1 call i8* malloc(i32 4) %foo bitcast i8* %1 to %Foo*注意bitcast不改变任何比特只是让同一串比特换了一个身份——i8*变身为Foo*。场景 2zext 让无符号字节变宽把 8 位无符号数提升为 32 位时高位补 0数值保持117%1 load i8, i8* byte ; 117 %2 zext i8 %1 to i32 ; 0x00000075 117如果这里误用sext结果也会是 117符号位为 0但换成负数就有差别了见下面的 FAQ。场景 3fpext 让 float 升级 doublefloat到double的升级永远不会丢失精度IR 用fpext表达%1 load float, float* small ; 1.25 %2 fpext float %1 to double ; 1.25精度更高反向的double→float则用fptrunc此时可能损失精度。 转换指令在哪里执行基本块与控制流类型转换指令不是孤立存在的它们和load、store、call一样都是基本块basic block中的一条普通指令按顺序执行。书中控制流章节用一个 if-else 求最大值的例子画出了基本块的控制流图帮你建立指令如何被组织的直观印象图中entry基本块完成比较后跳转到%true或%false两个分支最终汇聚到end。你可以把上文学到的zext、trunc等转换指令想象成嵌在某个基本块内、随块顺序执行的普通一行——理解了这套骨架读任何复杂的 IR 都不慌。该示例源码与图片位于control-structures/listings/目录如simple_if_max.cpp、simple_if_max_phi.ll。 项目相关文件清单与本地构建按学习顺序重点文件如下路径为仓库内相对位置a-quick-primer/index.rst—— IR 快速入门建议先读basic-constructs/casts.rst—— 本文全部 9 种 casts 的权威出处basic-constructs/index.rst—— 基本构造章节入口全局变量、结构体、函数、联合体等basic-constructs/listings/—— 各章节 C / LLVM IR 示例源码control-structures/、object-oriented-constructs/、advanced-constructs/—— 控制流、面向对象、闭包/生成器等进阶章节Makefile、common.mk、conf.py、Dockerfile—— 文档构建配置本地构建步骤克隆仓库后即可使用git clone https://gitcode.com/gh_mirrors/ma/mapping-high-level-constructs-to-llvm-ir cd mapping-high-level-constructs-to-llvm-ir make html # 需要 build-essential、python3-sphinx、sphinx-rtd-theme没有 Python 环境也可以直接用 Dockersudo make docker-build创建镜像再执行sudo make docker-make Ohtml生成的书在_build/html目录。❓ FAQ关于 LLVM IR 类型转换的 3 个常见疑问Q1trunc为什么有符号和无符号都能用因为 LLVM IR 约定所有有符号整数都采用二进制补码表示截断低若干位对两种类型都是合法操作所以不需要区分指令。Q2bitcast和memcpy有什么区别bitcast不产生任何内存读写只是让优化器换个类型看同一块数据零开销memcpy是真实的拷贝会移动数据。把void*当作Foo*用就该选bitcast。Q3为什么 C 代码没写IR 里却多出了 zext/sextC 的隐式转换在 IR 中被显形了。例如char有符号传给 32 位参数编译器会自动插入sext。这正是本书反复演示的高层构造 → IR映射过程也是你阅读真实编译器输出时最该关注的差异点。小结LLVM IR 类型转换就 9 条指令——变宽用zext/sext/fpext变窄用trunc/fptrunc重解释用bitcast指针穿墙用ptrtoint/inttoptr。配合basic-constructs/casts.rst原文与示例源码反复对照你很快就能自由穿梭于 C 代码与 LLVM IR 之间。【免费下载链接】mapping-high-level-constructs-to-llvm-irA guide that explains how high level programming language constructs are mapped to the LLVM intermediate language.项目地址: https://gitcode.com/gh_mirrors/ma/mapping-high-level-constructs-to-llvm-ir创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考