
仓颉 LLVM 专属 Intrinsic 全解析GC Barrier 与原子操作的 30 内置函数清单【免费下载链接】llvm-projectLLVM 项目是一个模块化、可复用的编译器及工具链技术的集合。此fork用于添加仓颉编译器的功能并支持仓颉编译器项目。项目地址: https://gitcode.com/Cangjie/llvm-project仓颉 LLVMCangjie llvm-project是在标准 LLVM 基础上为仓颉语言定制的编译器基础设施。本文将完整梳理其中70 个int_cj_专属 Intrinsic内置函数重点覆盖 GC Barrier写屏障、GC 读操作与 4 大原子操作帮助新手快速看懂仓颉编译器如何管理内存、数组与并发。从上图可以看到这套工具链中 Clang 与Cangjie仓颉并列作为表达式解析后端LLVM 则承担反汇编与指令模拟——仓颉专属 Intrinsic 正是连接两者底层的关键桥梁。什么是 Intrinsic为什么仓颉必须扩展Intrinsic内置函数是 LLVM IR 中只声明、不实现的特殊函数编译器在代码生成阶段把它们直接替换为特定指令或运行时调用。仓颉是一门带自动内存管理GC 强类型 高并发特性的语言标准 LLVM 的 Intrinsic 无法表达这些语义因此仓颉团队扩展了一整套int_cj_*前缀的内置函数分为六大类分类数量解决什么问题GC Barrier屏障17 个写对象字段时通知 GC防止指针被移动运行时 Runtime31 个堆分配、除法检查、异常、线程与 GC 统计原子操作 Atomic4 个对象字段的并发读写后端 Backend4 个浮点状态、位置追踪泛型 Generic17 个泛型赋值、vtable/mtable 查找GC 快照 Snapshot4 个写屏障 GC 的堆指针重定位5 分钟定位源码Intrinsic 定义在哪所有仓颉 Intrinsic 的核心定义都在 TableGen 文件中按分区注释组织检索非常方便总定义llvm/include/llvm/IR/Intrinsics.td —— 从Cangjie GC Barrier Intrinsics分区开始快照 GC 分区Intrinsics.td 第 1481-1497 行参数索引封装CJIntrinsics.h —— 用GCReadRef、AtomicLoad等结构体为每个参数命名GC 结构体元信息CJStructTypeGCInfo.h配套的 GC 感知别名分析CJAliasAnalysis.cpp在 IR 中这些函数的名字形如llvm.cj.gcwrite.ref、llvm.cj.atomic.load——也就是把 TableGen 定义名中的下划线换成点号并加上llvm.前缀。用opt -print-after-all观察 IR 输出时这就是你搜索它们的关键词。GC Barrier 内置函数清单写屏障是核心GC Barrier屏障是自动内存管理的心脏向对象字段写入引用时必须插入一条屏障指令让 GC 有机会记录这次写入或移动堆对象。仓颉把屏障细化为ref / struct / static / generic四种粒度写屏障gcwrite 系列9 个IntrinsicIR 名定义行作用llvm.cj.gcwrite.refIntrinsics.td#L437向对象引用字段写值带NoCapture语义llvm.cj.gcwrite.structIntrinsics.td#L440按偏移 大小写结构体字段区标注NoAlias/WriteOnlyllvm.cj.gcwrite.static.refIntrinsics.td#L444写全局/静态引用变量llvm.cj.gcwrite.static.structIntrinsics.td#L447写全局结构体字段区llvm.cj.gcwrite.genericIntrinsics.td#L598泛型对象写屏障llvm.cj.gcwrite.generic.payloadIntrinsics.td#L637写泛型 payload 区llvm.cj.array_copy.refIntrinsics.td#L469引用数组整体拷贝逐元素屏障llvm.cj.array_copy.structIntrinsics.td#L471结构体数组拷贝llvm.cj.array_copy.genericIntrinsics.td#L635泛型数组拷贝读屏障gcread 系列6 个Intrinsic定义行作用llvm.cj.gcread.refIntrinsics.td#L451从对象引用字段读值llvm.cj.gcread.weakrefIntrinsics.td#L454读弱引用可能返回空llvm.cj.gcread.structIntrinsics.td#L458按偏移 大小读结构体字段区llvm.cj.gcread.static.refIntrinsics.td#L462读全局引用变量llvm.cj.gcread.static.structIntrinsics.td#L465读全局结构体字段区llvm.cj.gcread.genericIntrinsics.td#L604泛型对象读屏障其他屏障辅助4 个llvm.cj.copy_struct.fieldL473跨对象拷贝单个结构体字段llvm.cj.cross_access.barrierL475跨访问屏障标记 i64 键llvm.cj.get_exported.ref/llvm.cj.create_export.handleL476-L480导出/回收跨模块引用句柄llvm.cj.get_lambda.addrL481获取闭包地址新手技巧CJIntrinsics.h 中为每个 Intrinsic 定义了参数枚举如GCWriteRef的Val / BaseObj / FieldPtr配合getBaseObj()、getValueArg()等辅助函数是读懂屏障语义的最快入口。原子操作 Intrinsic4 个函数搞定对象字段并发仓颉的原子操作直接作用于对象字段而非裸指针由基对象 字段偏移 内存序三元组定位天然与 GC 兼容Intrinsic定义行内存模型llvm.cj.atomic.storeIntrinsics.td#L560参数新值、基对象、字段指针、内存序llvm.cj.atomic.loadIntrinsics.td#L562返回基对象类型的旧值llvm.cj.atomic.swapIntrinsics.td#L564原子交换并返回旧值llvm.cj.atomic.compare_swapIntrinsics.td#L566CAS成功返回 i1区分成功/失败内存序参数索引在 CJIntrinsics.h#L73-L87 中用AtomicLoad { Obj, Field, Order }等结构体明确命名——例如AtomicCompareSwap的六个参数依次为OldRef, NewRef, Obj, Field, SuccOrder, FailOrder与 C 标准库compare_exchange_strong的语义一一对应。运行时与 GC 快照 Intrinsic堆、异常与 Profiling内存分配与安全检查llvm.cj.malloc.object/llvm.cj.malloc.arrayL492-L497堆上分配对象/数组带Throws标志可触发 GC 后重试llvm.cj.alloca.genericL595泛型栈上分配llvm.cj.division_check.sdiv / udiv / srem / uremL498-L509带溢出/除零检查的除法与取余异常、线程与 GC 统计共 20 余个分组代表 Intrinsic异常throw.exception、post_throw.exception、fill.in.stack.traceL514-L526堆信息get.real.heap.size、get.max.heap.size、dump.heap.dataL527-L534线程get.thread.number、get.native.thread.numberL535-L540GC 指标get.gc.count、get.gc.time.us、invoke.gc、set.gc.thresholdL541-L554Profilingstart.cpu.profiling/stop.cpu.profilingL547-L550写屏障 GC 的快照四件套支持可移动堆snapshot GC的四个 Intrinsic 定义了完整的重定位协议Intrinsics.td#L1481-L1497llvm.cj.gc.statepoint—— 进入状态点保存当前堆指针变量返回 tokenllvm.cj.gc.result—— 从 token 取回 GC 结果llvm.cj.gc.relocate—— 按(token, 指针索引, 变量索引)重定位堆指针llvm.cj.stack.relocate—— 重定位栈上对象这组设计与 LLVM 标准快照 GC 提案的思路一致但把对象索引显式作为立即数参数ImmArg方便优化器做常量折叠。泛型与类型系统 Intrinsic17 个函数的分工仓颉是值类型 引用类型混合语言泛型代码在 IR 层面需要大量类型元数据支持L576-L638类型判定is_subtype、is_typeinfo.equal、is_reference、is_tupletype_of—— 全部标注IntrSpeculatable可安全提前执行元数据获取get.type.info、get.field.offset、get.obj.klass—— 支撑运行时类型系统动态分发get.vtable.func、get.mtable.func、get.method.outertype、vfe.info—— 虚表/接口表查找其中vfe.info用显式参数携带 VFE 元数据确保优化 pass 不丢失函数表偏移信息泛型赋值assign.generic—— 按 TypeInfo 深拷贝泛型值配合gcwrite.generic完成完整写入上手路线图3 步读懂仓颉 Intrinsic先读清单打开 Intrinsics.td#L435-L638每个分区注释Cangjie xxx Intrinsics即分类目录参数列表一目了然再读封装CJIntrinsics.h 的参数枚举把第 2 个参数是什么变成了具名常量配合getAtomicOrder()等访问器理解调用约定最后看消费者优化器如何使用它们检索isCJIntrinsic或在 llvm/lib/Analysis/ 中查看CJAliasAnalysis.cpp、CJFunctionVarLifeTime.cpp即可理解屏障 Intrinsic 如何参与别名分析与活性分析总结这套 70 的int_cj_Intrinsic 家族用GC Barrier保证了可移动堆的正确性用原子对象字段操作简化了并发编程用快照四件套预留了写屏障 GC 的演进空间——这正是仓颉 LLVM 相对标准 LLVM 最大的差异化所在。【免费下载链接】llvm-projectLLVM 项目是一个模块化、可复用的编译器及工具链技术的集合。此fork用于添加仓颉编译器的功能并支持仓颉编译器项目。项目地址: https://gitcode.com/Cangjie/llvm-project创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考