LLVM后端怎么生成函数序言和尾声

星静酱_4834

星静酱_4834

2026-10-06

879人浏览

原创

函数序言和尾声由prologepiloginserter pass在寄存器分配后、指令调度完成时调用targetframelowering::emitprologue/emitepilogue生成,插入到machineinstr列表中,不依赖ir或dag,仅操作机器指令。

llvm后端怎么生成函数序言和尾声

函数序言(prologue)和尾声(epilogue)由 TargetFrameLowering 子类生成,不是手写汇编,也不是在指令选择阶段插入——它发生在寄存器分配之后、指令调度完成、MachineInstr 已成型但尚未发射的阶段。

什么时候调用 emitPrologue 和 emitEpilogue

LLVM 后端在 MachineFunctionPass 流水线中,由 PrologEpilogInserter pass 负责统一插入。该 pass 会遍历每个 MachineFunction,在入口基本块开头调用 TargetFrameLowering::emitPrologue,在每个有返回指令(如 RET、BR_RET)的基本块末尾调用 emitEpilogue。

  • 这个 pass 运行在寄存器分配(RegisterAllocator)之后,因此能准确知道哪些虚拟寄存器被 spill 到栈上,也清楚帧指针(FP)、栈指针(SP)的偏移关系
  • 它不关心 IR 或 DAG,只操作 MachineInstr 列表,直接往 MBB->instr_begin() 或 MBB->instr_end() 插入新指令
  • 如果你看到序言里有 ADD SP, SP, #-16 或 STR R0, [SP, #-4]! 这类指令,它们是 C++ 代码动态 emit 出来的,不是 TableGen 模式匹配出来的

TargetFrameLowering 必须重写的两个核心函数

每个目标后端都需继承并实现 TargetFrameLowering,最关键的两个虚函数是:

Viral Video
Viral Video

一款基于AI的文字转视频创作工具,可将文字创意快速转化为适合社交媒体传播的视频内容和短视频素材。

下载
  • emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB):负责分配栈空间、保存 callee-saved 寄存器、设置帧指针(如果需要)。注意:它不负责计算栈大小——那是 computeStackSize 阶段干的,结果存在 MF.getFrameInfo()->getStackSize()
  • emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB):恢复 callee-saved 寄存器、调整栈指针、跳过帧指针恢复逻辑(除非显式启用 hasFP)
  • 还必须实现 hasFP(const MachineFunction &MF) —— 它决定是否把帧指针当作独立寄存器管理;若返回 true,emitPrologue 通常要插入 MOV FP, SP 类似指令,且后续所有栈访问都基于 FP 偏移而非 SP

常见错误:栈偏移算错、寄存器保存顺序颠倒、漏处理变长栈分配

序言/尾声出错,往往不是语法问题,而是语义错位。典型表现包括:

  • 函数返回后寄存器值异常 → 检查 getCalleeSavedRegs() 返回的寄存器列表是否与 emitPrologue 中实际保存的顺序、数量、条件(如是否仅在有栈溢出时才保存)严格一致
  • 局部变量读写越界或值错乱 → 栈帧大小计算错误,常见于未正确处理 hasVarSizedObjects():若函数含变长数组(alloca),getStackSize() 不再是常量,必须在运行时计算并用指令动态调整 SP
  • 调试信息错乱或 GDB 显示栈回溯断裂 → 忘记在 emitPrologue 中调用 addRegOffset 注册 CFI 指令(如 CFI_ADJUST_CFA_OFFSET、CFI_REMEMBER_STATE),导致 DWARF 无法重建调用栈
  • 硬故障或非法指令 → 在 emitPrologue 中试图使用未定义的机器指令(比如用 ARM::STRi12 但当前 subtarget 不支持 Thumb2),应优先通过 getInstrInfo()->get(...) 获取合法 MCID

调试建议:用 -mllvm -print-machineinstrs 看真实插入点

光看 C++ 实现容易误判执行时机。最有效的方式是编译时加参数观察中间状态:

  • llc -march=yourtarget -mllvm -print-machineinstrs input.ll 2>&1 | grep -A5 -B5 "PROLOG" 可定位到序言指令实际插在哪条 MachineInstr 前后
  • 配合 -debug-only=regalloc 或 -debug-only=stack-slot 查看帧信息如何被计算和传播
  • 若修改了 emitPrologue 但没生效,先确认 YourTargetFrameLowering 是否已注册进 YourTargetTargetMachine::createTargetFrameLowering,且 TM.getSubtargetImpl()->getFrameLowering() 确实返回你的实例

序言和尾声看似只是几条栈操作指令,但它横跨帧布局、寄存器保存策略、CFI 调试信息、变长分配四大耦合模块,任何一处 mismatch 都会导致静默崩溃或难以复现的栈破坏——动手前务必通读本 target 的 FrameLowering 实现和对应 ABI 文档。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2303

5

前端和后端的区别
前端和后端的区别

前端关注的是用户界面的设计和交互,而后端则注重数据处理和逻辑控制。想了解更多前端后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

6070

13

后端的主要工作内容介绍
后端的主要工作内容介绍

后端是应用程序的服务端部分,负责核心任务,如数据库交互、业务逻辑处理和响应客户端请求。想了解更多后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

5406

10

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

120

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

100

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

80

12

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

2026.09.30

60

26

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

2026.09.29

80

15

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

2026.09.23

280

15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程