简介

本文内容基于LLVM 13.0.0。

目前基于LLVM的Fortran编译器(或者驱动)有3种,分别是flang、f18和flang-new。

flang是pgfortran的开源版本,基于PGI/NVIDIA的商业Fortran 编译器,它并不从属于LLVM项目。NVIDIA团队在2018年宣布了Fortran的新前端——f18,f18是使用现代 C++ 从头开始​​编写的,它将与 LLVM 最佳实践紧密结合,并以 LLVM 和 clang 的风格编写,f18已经被纳入为LLVM子项目。flang-new是一款新的flang驱动,在未来将会取代f18驱动。flang-new目前没有实现Fortran程序从源码生成.out的完整过程,f18可以生成.out,但是是借助外部编译器来完成的,默认外部编译器为gfortran。

以下表格展示了f18和flang-new在编译器驱动和前端驱动的细分,编译器驱动程序将允许您控制所有编译阶段(即预处理、前端代码生成、中间/后端代码优化和降级、链接),前端驱动程序将所有前端库粘​​合在一起,并为前端提供易于使用且直观的接口。

Compiler driver

Frontend driver

f18

f18

f18

flang-new

flang-new

flang-new -fc1

在前端驱动方面,flang-new -fc1和f18完全兼容,在编译器驱动方面,flang-new尚不支持代码生成(code-generate),f18调用一个独立的外部Fortran编译器来生成代码。

编译安装

flang

根据github上的介绍,安装flang需要下载flang项目(https://github.com/flang-compiler/flang)和定制的LLVM项目(https://github.com/flang-compiler/classic-flang-llvm-project)。

编译时,先用gcc编译安装定制的LLVM,再用生成的clang编译安装libpgmath库和flang。编译LLVM时,需要把clang和openmp都装上,因为flang需要使用到openmp库。

编译安装成功后,flang相关的可执行文件也放在LLVM的bin目录下,其中flang1负责输出PGI IR,flang2负责输出LLVM IR。

f18&flang-new

宏FLANG_BUILD_NEW_DRIVER控制是否需要安装flang-new,默认为on,flang-new依赖于clang驱动,所以在安装flang-new的时候也需要安装clang,通过LLVM_ENABLE_PROJECTS把clang设置上,如果FLANG_BUILD_NEW_DRIVER设置为off,则不需要安装clang。

在f18被移除之后,宏FLANG_BUILD_NEW_DRIVER也会被一并删除,这意味着接下来LLVM中flang驱动对clang的依赖将是必须和永久的。

cmake -G "Unix Makefiles"
-DLLVM_ENABLE_PROJECTS='clang;flang'
-DCMAKE_INSTALL_PREFIX=../x86_tools
-DCMAKE_BUILD_TYPE=Release
-DLLVM_TARGETS_TO_BUILD=X86
../llvm

编译安装成功后在bin目录下生成了以下两个flang驱动——f18和flang-new:

图中的flang并不是独立的可执行文件,不能通过gdb被调试,目前在使用时会被扩展为f18,在未来会根据FLANG_BUILD_NEW_DRIVER的设置被扩展为flang-new,同样地,flang_fc1被扩展为flang-new -fc1。

原理介绍

flang

flang在PGI Fortran编译器的基础之上,新增了将PGI中间表示转换为LLVM中间表示的能力,并提供了PGI Fortran的运行时,有了LLVM中间表示后就可以利用起LLVM的后端功能,从而进一步生成二进制文件。可以说,flang也是借助了外部编译器来完成Fortran的编译。

如前文所述,flang1负责输出PGI IR,flang2负责输出LLVM IR。flang1包含以下阶段:

1.扫描提取文本token

2.创建语法树和符号表

3.转换ASTcanonical为AST

4.将一般AST转换为优化的AST

5.创建AST ILM文件,即PGI IR1

flang2包含以下阶段:

1.ILM扩展为ILI文件,即PGI IR2

2.优化ILI文件

3.将ILI优化为LLVM IR

flang-new

编译阶段说明

官方文档表明flang编译分为以下8个阶段:

1.预扫描和预处理

flang-new -fc1 -E src.f90

这一阶段与一般的编译器的预处理阶段是一致的,操作包括宏替换、删除空格和注释等。

2.解析

flang-new -fc1 -fdebug-dump-parse-tree src.f90

将第1步中的输出转储为解析树

flang-new -fc1 -fdebug-unparse src.f90

将解析树转换为标准的Fortran源码

3.验证标签并规范化Do语句

4.解析名称

flang-new -fc1 -fdebug-dump-symbols src.f90

5.检查DO CONCURRENT约束

6.编写模块文件

7.分析表达式和任务

8.生成中间表示

实际上,由于开发尚未完成,目前的f18和flang-new还不能生成LLVM中间表示。

编译器驱动

flang-new的编译器驱动的主入口点的实现在flang/tools/flang-driver/driver.cpp中,它是基于clang的驱动库来实现的,这样的好处在于以下2点:

1. 受益于clang对各种目标、平台和操作系统的支持

2. 利用clang驱动LLVM中各种后端以及链接器、汇编器能力,所有的flang驱动器选项和clang的选项都定义在clang/include/clang/Driver/Options.td里,对于两者通用的选项,定义是同等共享的。

基于clangDriver的编译器驱动通过创建跟大量编译阶段相关的动作(action)来工作,比如clang::driver::Action::ActionClass枚举里定义的 PreprocessJobClassCompileJobClassBackendJobClass LinkJobClassLinkJobClass,以及一些比较特殊的不直接映射到常见编译步骤的动作,比如MigrateJobClassInputClass。具体运行哪个动作,由编译选项决定,比如:

  1. -E表示PreprocessJobClass
  2. -c表示CompileJobClass

在大多数情况下,驱动会创建一个关于动作(action)/任务(job)/阶段(phase)的链(chain)来串起整个流程,可以使用-ccc-print-phases选项打印出驱动器为当前编译所生成的序列:

flang-new -ccc-print-phases -c file.f

+- 0: input, "file.f", f95-cpp-input

+- 1: preprocessor, {0}, f95

+- 2: compiler, {1}, ir

+- 3: backend, {2}, assembler

4: assembler, {3}, object

前端驱动

flang-new的前端驱动程序是用户和flang前端之间的主要接口,主入口点fc1_main在flang/tools/flang-driver/driver.cpp里实现,通过flang-new -fc1访问。前端驱动程序一次只会运行一个动作(action),如果指定多个操作选项,则仅最后一个有效。

源码分析

flang

在编译安装后的bin目录中可以看到flang可执行文件是指向clang的,所以当执行flang时,main函数进的是clang的driver.cpp(clang/tools/driver/driver.cpp),通过以下代码解析当前需要使用flang:

auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);

此时的TargetAndMode打印出来为:

$1 = {TargetPrefix = "", ModeSuffix = "flang", DriverMode = 0x118ea194 "--driver-mode=flang", TargetIsValid = false}

与常规clang驱动流程的不同之处在于,flang会使用ClassicFlang.cpp中的ConstructJob()函数来组装flang的任务,该函数中指定了一系列调flang1和flang2所需要的参数和宏等内容,然后添加任务。

……const char *UpperExec = Args.MakeArgString(getToolChain().GetProgramPath("flang1"));……C.addCommand(std::make_unique<Command>(JA, *this, UpperExec, UpperCmdArgs, Inputs));const char *UpperExec = Args.MakeArgString(getToolChain().GetProgramPath("flang2"));……C.addCommand(std::make_unique<Command>(JA, *this, UpperExec, UpperCmdArgs, Inputs));

有了上面两个任务,Driver会调到以下函数逐个执行:

void Compilation::ExecuteJobs(const JobList &Jobs,FailingCommandList &FailingCommands) const {// According to UNIX standard, driver need to continue compiling all the// inputs on the command line even one of them failed.// In all but CLMode, execute all the jobs unless the necessary inputs for the// job is missing due to previous failures.for (const auto &Job : Jobs) {if (!InputsOk(Job, FailingCommands))continue;const Command *FailingCommand = nullptr;if (int Res = ExecuteCommand(Job, FailingCommand)) {FailingCommands.push_back(std::make_pair(Res, FailingCommand));// Bail as soon as one command fails in cl driver mode.if (TheDriver.IsCLMode())return;}}}

最终会传递给llvm::sys::ExecuteAndWait()函数。

return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,/*secondsToWait*/ 0,/*memoryLimit*/ 0, ErrMsg, ExecutionFailed);

完整调用栈如下图所示,flang1和flang2是完全一致的。

f18

f18的main函数在flang/tools/f18/f18.cpp中,在main函数中通过F18_FC环境变量确定了外部Fortran编译器,对参数做了一系列准备后,通过Link()->Exec()最终调到llvm/lib/Support/Program.cpp中的llvm::sys::ExecuteAndWait()函数实现程序的执行。未来f18.cpp将会被移除,与之相关的代码也将被更新或删除。

int main(int argc, char *const argv[]) {atexit(CleanUpAtExit);DriverOptions driver;const char *F18_FC{getenv("F18_FC")};driver.F18_FCArgs.push_back(F18_FC ? F18_FC : "gfortran");bool isPGF90{driver.F18_FCArgs.back().rfind("pgf90") != std::string::npos};……if (!driver.compileOnly && !objlist.empty()) {Link(liblist, objlist, driver);}return exitStatus;}

flang-new

flang-new没有调用外部Fortran编译器,而是自己组织action,同样也是调到llvm::sys::ExecuteAndWait()函数实现程序的执行,但由于尚未开发完成,在ExecuteAction()的时候直接报错。

void EmitObjAction::ExecuteAction() {CompilerInstance &ci = this->instance();unsigned DiagID = ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "code-generation is not available yet");ci.diagnostics().Report(DiagID);}

基于LLVM的Fortran编译器分析相关推荐

  1. 基于LLVM编译器的IDA自动结构体分析插件

    引用 这篇文章旨在介绍一款对基于LLVM的retdec开源反编译器工具进行二次开发的IDA自动结构体识别插件实现原理分析 文章目录 引用 简介 源码分析 LLVM编译器简介 Retdec源码分析 Kl ...

  2. 基于LLVM的编译原理简明教程 (1) - 写编译器越来越容易了

    基于LLVM的编译原理简明教程 (1) - 写编译器越来越容易了 进入21世纪,新的编程语言如雨后春笋一样不停地冒出来.需求当然是重要的驱动力量,但是在其中起了重要作用的就是工具链的改善. 2000年 ...

  3. 非线性有限元:基本理论与算法及基于Python、Fortran程序实现与案例分析实践技术

    有限单元法在岩土工程问题中应用非常广泛,很多商业软件如Plaxis/Abaqus/Comsol等都采用有限单元解法.尽管各类商业软件使用方便,但其使用对用户来说往往是一个"黑箱子" ...

  4. 非线性有限元:基本理论与算法及基于Python、Fortran程序实现与案例分析

    非线性有限元:基本理论与算法及基于Python.Fortran程序实现与案例分析 (qq.com) 有限单元法在岩土工程问题中应用非常广泛,很多商业软件如Plaxis/Abaqus/Comsol等都采 ...

  5. 岩土工程--非线性有限元:基本理论与算法及基于Python、Fortran程序实现与案例分析

    非线性有限元:基本理论与算法及基于Python.Fortran程序实现与案例分析实践技术 有限单元法在岩土工程问题中应用非常广泛,很多商业软件如Plaxis/Abaqus/Comsol等都采用有限单元 ...

  6. 转:GCC,LLVM,Clang编译器对比

    GCC,LLVM,Clang编译器对比 转自: http://www.cnblogs.com/qoakzmxncb/archive/2013/04/18/3029105.html 在XCode中,我们 ...

  7. 【转载】基于LLVM Pass实现控制流平坦化

    基于LLVM Pass实现控制流平坦化 文章目录 基于LLVM Pass实现控制流平坦化 0x00. 什么是LLVM和LLVM Pass 0x01. 首先写一个能跑起来的LLVM Pass 0x02. ...

  8. C语言头文件下载迅雷,LLVM汇编|clang llvm(C语言编译器)下载v3.4 免费版 - 欧普软件下载...

    LLVM汇编是一款免费的构架编译器框架系统,采用C++编写而来,软件采用现代化的设计,和语言无关的中间代码,方便的进行编程语言的优化编译工作.此外小编还提供了LLVM安装教程,有需要的朋友赶快下载吧! ...

  9. 开源的fortran编译器LFortran

    基于LLVM,现在是pre alpha.很快就有发布版 LFortran 是一款现代开源 (BSD 许可) 交互式fortran编译器,建在 LLVM 之上.它可以以交互式身份执行用户代码,以便进行探 ...

最新文章

  1. Google综述:细数Transformer模型的17大高效变种
  2. CA ARCserve Backup系列(3)—安装代理(Linux篇)
  3. 面向程序员的数据库访问性能优化法则
  4. 模拟浏览器自动化测试工具Selenium之六设置代理篇
  5. 在 Java 中,为什么需要创建内部类对象之前需要先创建外部类对象
  6. 通用业务流水号功能设计
  7. 新电子书:解决生产中Java应用程序错误的完整指南
  8. [css] 举例说明如何从html元素继承box-sizing?
  9. Reason: image not found
  10. Windows坐标系统
  11. html之文档的头部和元数据定义(上)
  12. AD下安装Exchange及简单收发邮件【视频】
  13. Maximum Submatrix Largest Rectangle
  14. zabbix client安装配置执行
  15. Atitit 高性能架构法艾提拉著作 目录 1. 前期可以立即使用的技术 2 2. 分离法 3 2.1. Web db分离 3 2.2. 读写分离 4 2.3. CDN加速技术 4 2.4. 动静分
  16. Octotree插件安装
  17. Java并发之-队列同步器AQS
  18. 「缠师课后回复精选」第14课: 喝茅台的高潮程序!
  19. 怎么样才能查看别人的IP地址
  20. **旅行-interveiw

热门文章

  1. CBA联赛终于迎来主客场,宁波町渥迎战夺冠热门辽宁本钢
  2. ARM-DAPLINK 仿真器硬件解析
  3. 怎么把i am a student逆置成student a am i?面试题逆置字符串讲解
  4. python解析xml文件elementtree_在python中使用ElementTree解析xml文件
  5. 取消Windows server 2008关机提示的方法
  6. 接连售罄,荣耀9青春版遭印尼用户疯抢
  7. 【那些年,我们一起追的女孩】第十二章
  8. AOT和单文件发布对程序性能的影响
  9. 2021年10月视频行业用户洞察:平台积极拥抱变革探索新机遇
  10. 一个简单的CPU降温方法.