6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

モダンになったFlang(llvm19.1.5)を使ってみる

Last updated at Posted at 2024-12-08

やりたいこと

  • flang-new のインストール.
  • いくつかのファイルをコンパイルしてみる.

Fortran コンパイラ

たくさんあります.
Fortran コンパイラとして有名なのが gfortranifx(旧ifort) でしょう.
gfortran は GNU Compiler Collection のコンパイラです.
ifx は intel fortran compiler のコンパイラです. 今は(商用でなければ?)無料で使えるはずです.
他にも lfortran や PGI/NVIDIA, NAG, Cray, NEC などのコンパイラがあるらしいです.
また, classic flang もあり, これは pgfortran からの派生らしいです.

今回ビルドする flang は llvm-project によるコンパイラです.
f18 プロジェクトから始まって, 前の flang の欠陥に対処して, LLVM project に受け入れられたようです.
つまり

pgfortran
   ↓       ↘
   ↓         classic flang
   ↓           ↓ (修正)
   ↓         f18 project
   ↓ (買収)     ↓
nvfortran    flang-new(llvm)

ってことですかね?
特徴は... 外からだとLLVMを使うことしか分からないですね.
色々試してみたいです.

LLVM

ろーれべるなんちゃらのあたまもじ... ではないらしい.
C コンパイラの Clang が有名ですね.

Flang

Fortran のコンパイラ.
LLVM の力を備えているらしい.

ビルドする

環境

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.5 LTS
Release:	22.04
Codename:	jammy
$ gfortran --version
GNU Fortran (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ifx --version
ifx (IFX) 2025.0.1 20241113
Copyright (C) 1985-2024 Intel Corporation. All rights reserved.
$ nvfortran --version

nvfortran 23.9-0 64-bit target on x86-64 Linux -tp ivybridge 
NVIDIA Compilers and Tools
Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.  All rights reserved.
$ flang --version
flang version 16.0.4 (https://github.com/flang-compiler/classic-flang-llvm-project.git 8d805dfcb66161beee81045a8ecd89051e919241)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/osd-yum/.local/bin
$ free -h
               total        used        free      shared  buff/cache   available
Mem:           7.6Gi       4.9Gi       307Mi       1.1Gi       2.4Gi       1.3Gi
Swap:           15Gi       5.1Gi        10Gi

メモリ8GBは今の時代は足りないので, もっと欲しいです.

ビルド

頻繁にバージョンが更新されるため, https://github.com/llvm/llvm-project/releases を確認しましょう.

ビルド方法は https://github.com/llvm/llvm-project/blob/main/flang/docs/GettingStarted.md です.
cmakeninja が必要です.

# Ubuntu なら
$ sudo apt install build-essential cmake ninja-build

llvm-project は 3GB くらいあるので, ストレージの容量には気をつけましょう.
また, 並列ビルドする際には, メモリが貧弱だと ninja が落ちます.
8GBメモリでは落ちるので, ninja -j 1 で1コアのビルドにしています.

$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.5/llvm-19.1.5.src.tar.xz
$ tar xvf llvm-19.1.5.src.tar.xz
$ cd llvm-19.1.5.src
$ mkdir _build
$ cd _build
$ sudo mkdir -p /opt/flang
$ INSTALLDIR="/opt/flang"
$ cmake \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=$INSTALLDIR \
  -DCMAKE_CXX_STANDARD=17 \
  -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
  -DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$LD_LIBRARY_PATH" \
  -DFLANG_ENABLE_WERROR=OFF \ # OFFにしないと `-Werror=dangling-reference` に引っ掛かってしまう...
  -DLLVM_ENABLE_ASSERTIONS=ON \
  -DLLVM_TARGETS_TO_BUILD=host \
  -DLLVM_LIT_ARGS=-v \
  -DLLVM_ENABLE_PROJECTS="clang;mlir;flang;openmp" \
  -DLLVM_ENABLE_RUNTIMES="compiler-rt" \
  ../llvm
$ ninja -j 1 # 長い
$ ninja flang-check -j 1 # しなくても良い?
$ sudo ninja install -j 1
  • cmakeオプションは一部変えてあります.
  • 何故か -DFLANG_ENABLE_WERROR=ON にすると -Werror=dangling-reference に引っかかりました.
    • まあ, WARNING なので(使用者は)無視しても良いでしょう.
  • メモリに余裕があるなら ninja -j (CPUの数を表す数字) に.
    • 並列にビルドされ, 速くなります.
    • 並列ビルドしない場合は14時間くらい掛かりました...
  • この設定なら, /opt/flang/bin に色々インストールされます.

バイナリをダウンロード

  • ビルドしない場合はバイナリを取りましょう.
$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.5/LLVM-19.1.5-Linux-X64.tar.xz
$ tar xvf LLVM-19.1.5-Linux-X64.tar.xz
$ sudo mkdir -p /opt/flang
$ sudo mv LLVM-19.1.5-Linux-X64 /opt/flang
$ export PATH="/opt/flang/LLVM-19.1.5-Linux-X64/bin:$PATH"
  • この設定では, /opt/flang/LLVM-19.1.5-Linux-X64/bin に色々インストールされます.

(追記) apt からインストール

(Louise さんより情報をいただきました. ありがとうございます)
こちらのQiita の記事によると, llvm の公式リポジトリ から apt でインストールできるそうです.

flang を試してみる

以下, ビルドしたものではなく, バイナリの flang-new でコンパイルしています.

出力してみた

test.f90
program test
  use, intrinsic :: iso_fortran_env
  implicit none
  integer(int64), parameter :: x = 10_int64 ** 10
  print*, x
  write(output_unit, '(a)') "Hello, World!"
end program
$ export PATH="/opt/flang/bin:$PATH"
$ flang-new test.f90 && ./a.out
 10000000000
Hello, World!
$ gfortran test.f90 && ./a.out
          10000000000
Hello, World!

うん? 何か gfortran と違いますね.
gfortran では整数のバイト数に依存する空白が出ます.

test2.f90
program hi
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int32) :: x
    integer(int64) :: x2
    x = 1; x2 = 1_int64
    print*, x, x2
    print*, x2, x
end program
$ flang-new test2.f90 && ./a.out
 1 1
 1 1
$ gfortran test2.f90 && ./a.out
           1                    1
                    1           1
$ ifx test2.f90 && ./a.out
           1                     1
                     1           1
$ nvfortran test2.f90 && ./a.out
            1                        1
                        1            1
$ flang test2.f90 && ./a.out
            1                        1
                        1            1

flang-new では整数のバイト数に依存する空白がないようです.
classic flangnvfortran と異なるようです.

test3.f90
program hi
    use, intrinsic :: iso_fortran_env
    implicit none
    integer(int64) :: x
    x = 1000000_int64
    print'(i0)', x
    print'(i4)', x
end program
$ flang-new test3.f90 && ./a.out
1000000
****
$ gfortran test3.f90 && ./a.out
1000000
****
$ ifx test3.f90 && ./a.out
1000000
****
$ nvfortran test3.f90 && ./a.out
1000000
****
$ flang test3.f90 && ./a.out
1000000
****

フォーマットを指定した場合はどれも同じです.

以前書いたやつをコンパイルしてみる.

$ find . -name '*f90' | xargs -I{} bash -c 'gfortran {} 2>/dev/null && echo {}' > success_compile.txt
$ wc -l success_compile.txt 
4427 success_compile.txt
$ cat success_compile.txt | xargs -I{} bash -c 'flang-new {} 2>> flang-errors.txt || echo {}' > failed_flang-new.txt
$ wc -l failed_flang-new.txt 
34 failed_flang-new.txt

gfortran でコンパイルできた 4427個(半分くらいは重複している)の .f90flang-new でコンパイルすると34個はコンパイルに失敗しているようです.
といっても, ほとんどが以下の関数の引数の順番でエラーが起こっているようです.

関数の引数

test_arg1.f90
test_arg1.f90
module test
  use, intrinsic :: iso_fortran_env
  implicit none
contains
  integer function f(arr, n) result(res)
    integer(int32), intent(in) :: arr(n)
    integer(int32), intent(in) :: n
    res = 0
  end function
end module
$ flang-new -c test_arg1.f90
$ gfortran -c test_arg1.f90
$ ifx -c test_arg1.f90
$ nvfortran -c test_arg1.f90
$ flang -c test_arg1.f90

関数の引数に配列があり, その配列のサイズを引数 n で決めている場合.
どのコンパイラでもうまくいきます.
... n の宣言が下にあっても...

test_arg2.f90
test_arg2.f90
module test
  use, intrinsic :: iso_fortran_env
  implicit none
contains
  integer function f(arr, n, u) result(res)
    integer(int32), intent(in) :: arr(n, u)
    integer(int32), intent(in) :: n, u
    res = 0
  end function
end module
$ flang-new -c test_arg2.f90 
error: Semantic errors in test_arg2.f90
./test_arg2.f90:5:30: error: No explicit type declared for 'u'
    integer function f(arr, n, u) result(res)
                               ^
$ gfortran -c test_arg2.f90 
$ ifx -c test_arg2.f90 
test_arg2.f90(7): error #6415: This name cannot be assigned this data type because it conflicts with prior uses of the name.   [U]
    integer(int32), intent(in) :: n, u
-------------------------------------^
compilation aborted for test_arg2.f90 (code 1)
$ nvfortran -c test_arg2.f90
$ flang -c test_arg2.f90 

2次元配列のサイズを下に書くと, flang-newifx はエラーとなってしまいます.

test_arg3.f90
test_arg3.f90
module test
  use, intrinsic :: iso_fortran_env
  implicit none
contains
  integer function f(arr, n, u) result(res)
    integer(int32), intent(in) :: u
    integer(int32), intent(in) :: arr(n, u)
    integer(int32), intent(in) :: n
    res = 0
  end function
end module
$ flang-new -c test_arg3.f90 
$ gfortran -c test_arg3.f90 
$ ifx -c test_arg3.f90 
$ nvfortran -c test_arg3.f90 
$ flang -c test_arg3.f90 

配列の上で宣言すればエラーは出ません...
Fortran の仕様まで踏み込まないと分からないかもしれません...

pure な関数の外の配列の要素を associate できない

test_associate.f90
test_associate.f90
program hi
  use, intrinsic :: iso_fortran_env
  implicit none
  integer(int32), allocatable :: g(:)
contains
  pure recursive subroutine dfs()
    associate(nv => g(1))
    end associate
  end subroutine dfs
end program hi
$ flang-new test_associate2.f90 
error: Semantic errors in test_associate2.f90
./test_associate2.f90:7:15: error: A pure subprogram may not have a variable with the SAVE attribute
      associate(nv => g(1))
                ^^
$ gfortran test_associate2.f90 

これが正しい挙動かどうかは分かりませんが, save 属性持っているわけではないので, エラーメッセージがおかしいかもしれません.

flang で fortran-stdlib(v0.7.0) をビルドしてみよう...と思いましたができません...

試しに fortran-stdlibv0.7.0 をビルドしてみます.
以下の方法では python3-joblibfyppfpm が必要です.
(cmake を使う方法もあります.)

$ wget https://github.com/fortran-lang/stdlib/archive/refs/tags/v0.7.0.tar.gz
$ tar xvf v0.7.0.tar.gz
$ cd stdlib-0.7.0
$ python3 config/fypp_deployment.py
$ fpm build --compiler="flang-new" --profile release
# (たくさん出力される)
./././src/temp/stdlib_specialfunctions_gamma.f90:384:49: error: Value of named constant 'pi' (acos(-1._16)) cannot be computed as a constant value
                               one = 1.0_qp, pi = acos(- one), sqpi = sqrt(pi)
                                                  ^^^^^^^^^^^
# (略)

どうやら, 4倍精度実数を扱うにはビルド時に指定する必要があるようです.
また, flang-new (19.1.5) の時点で assumed-rank-array (select rank) に対応していないのでいくつかのファイルはコンパイルできません.
ビルドではなく, fpm.tomldependencies に書く方法を使った方が良いかもしれません.

まとめ

モダンになった flang-new を使ってみました.
gfortran とは仕様が違いそうですが, どちらでもコンパイルできるようにしておくと良いかもしれません.
今回は flang-new の利点が見えませんでしたが, いつか, LLVM の力を見られるようなことをしてみたいですね.

参考

flang

LLVM

fortran-stdlib

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?