1 điểm bởi GN⁺ 2024-04-07 | 1 bình luận | Chia sẻ qua WhatsApp
  • Để đưa mã số trị Fortran, một tài sản tính toán khoa học/kỹ thuật lâu đời, lên trình duyệt, cần có đường dẫn biên dịch WebAssembly; webR dùng LLVM flang-new đã được vá
  • f2c, LFortran, Dragonegg, Classic Flang và LLVM Flang đều có hạn chế riêng về hỗ trợ Fortran hiện đại, kiến trúc đích và khả năng bảo trì, nên hiện vẫn chưa có một giải pháp chuẩn đơn giản
  • LLVM Flang không hỗ trợ trực tiếp đích wasm32-unknown-emscripten, nên cần thêm TargetWasm32; khi liên kết runtime, khác biệt về kích thước long giữa host và target gây ra vấn đề
  • Kết hợp flang-new đã vá, Emscripten và thư viện tĩnh runtime Fortran cho phép gọi subroutine Fortran từ C hoặc JavaScript, đồng thời xử lý được cả đối số PRINT, ALLOCATE, CHARACTER
  • Đã build các triển khai tham chiếu BLAS 3.12.0 và LAPACK 3.12.0 thành thư viện tĩnh WebAssembly để chạy demo phân loại chữ số viết taynội suy đa thức trong trình duyệt

Đưa mã số trị Fortran hiện có lên trình duyệt

  • Fortran là một ngôn ngữ cũ xuất hiện từ năm 1957, nhưng đã được dùng trong thời gian dài cho tính toán khoa học/kỹ thuật, và Fortran hiện đại phần lớn đã thoát khỏi các ràng buộc fixed-form của Fortran 77
  • Mục tiêu là biên dịch các routine Fortran hiện đại sang WebAssembly để chạy trong trình duyệt, nhận các đối số số học, tính toán bằng các routine BLAS/LAPACK rồi trả kết quả hoặc in ra console
  • Cách tiếp cận này cho phép đưa các môi trường lập trình cấp cao phụ thuộc vào BLAS/LAPACK như SciPy hoặc R lên web
  • Có thể tận dụng các công cụ và thư viện dựa trên Fortran đã được kiểm chứng, thay vì viết lại các routine số trị bằng JavaScript hoặc Rust
  • Dự án webR biên dịch mã Fortran sang WebAssembly bằng trình biên dịch LLVM flang-new đã được vá
  • Cách làm hiện tại dựa vào các bản hack, và nếu không có sự trợ giúp của các nhà phát triển compiler giàu kinh nghiệm hơn thì khó đóng góp các thay đổi này ngược lại cho LLVM

Tình hình công cụ Fortran→WebAssembly

  • Tính đến năm 2024 có nhiều công cụ và toolchain, nhưng vẫn chưa có giải pháp đơn giản với đầy đủ tính năng
  • f2c

    • f2c chuyển Fortran 77 thành mã C, để Emscripten có thể biên dịch nó sang WebAssembly
    • Pyodide dùng cách này khi biên dịch các package Python có chứa mã Fortran
    • Ngay cả trong lộ trình của Pyodide, cách này cũng được đánh giá là “không hoạt động tốt”
    • Không phù hợp với mã Fortran hiện đại, và sau khi chuyển đổi vẫn cần vá rất rộng cùng các lỗi nghiêm trọng
  • LFortran

    • LFortran đã tăng đáng kể tính năng trong vài năm gần đây và có thể biên dịch trực tiếp sang WebAssembly
    • Các nhà phát triển cho biết vì vẫn đang ở giai đoạn alpha, có thể sẽ gặp vấn đề khi biên dịch mã thực tế
    • Một số dự án như MINPACK có thể biên dịch được, nhưng vì chưa hỗ trợ toàn bộ đặc tả Fortran nên các dự án lớn hơn có thể thất bại
    • Mục tiêu phát triển là hỗ trợ toàn bộ Fortran 2018, và một tính năng nổi bật là REPL Fortran tương tác giống Jupyter
  • Dragonegg

    • Dragonegg là plugin GCC dùng frontend GCC để xuất LLVM IR
    • Có thể tạo đầu ra WebAssembly bằng backend LLVM, và đây là cách webR dùng lúc đầu để biên dịch mã nguồn Fortran sang WebAssembly
    • Phiên bản mới nhất được hỗ trợ là gcc-4.8llvm-3.3, nên cần GCC/LLVM rất cũ
    • Phần lớn người dùng cần VM hoặc container Docker, và LLVM IR do Dragonegg xuất ra cũng phải qua bước hậu xử lý bổ sung để tạo đầu ra WebAssembly
    • Vào năm 2020, thực tế đây gần như là cách khả thi duy nhất để biên dịch mã Fortran sang WebAssembly
  • Classic Flang

    • Classic Flang là trình biên dịch Fortran nhắm LLVM, dựa trên PGI/NVIDIA pgfortran đã được mã nguồn mở
    • Không hỗ trợ đầu ra 32-bit nên không thể dùng cho target wasm32
    • Tại thời điểm viết, Firefox, Chrome và Node hỗ trợ wasm64, nhưng tính năng này bị khóa sau feature flag
    • Tài liệu dự án cũng lưu ý rằng chọn Classic Flang cho dự án mới có thể không phải là ý hay
  • LLVM Flang

    • LLVM Flang là dự án triển khai lại từ đầu frontend Fortran cho LLVM, và được đưa vào dự án LLVM từ LLVM 11
    • Dù chưa được xem là sẵn sàng cho production, phiên bản tiền production của flang-new đã khá dùng được để biên dịch mã Fortran thực tế
    • Ở trạng thái mặc định, nó không thể tạo đầu ra WebAssembly
    • Nhờ thiết kế mô-đun của LLVM, có thể dùng frontend Flang cùng backend WebAssembly của LLVM
    • Điều này cũng đã khả thi vào năm 2020, nhưng cần bản vá LLVM lớn hơn, chèn routine toán học tùy chỉnh và quy trình biên dịch nhiều bước
    • Hiện nay, nhờ sự phát triển của frontend flang-new, chỉ cần thay đổi nhỏ trong mã nguồn LLVM là có thể tạo compiler Fortran→WebAssembly

Build LLVM Flang cho WebAssembly

  • LLVM cài bằng package manager có thể không bao gồm binary flang-new
    • Ví dụ, trên LLVM v17.0.6 của macOS Homebrew không tìm thấy lệnh flang-new
  • Vì cần sửa mã nguồn LLVM Flang, tác giả tự build mã nguồn LLVM v18.1.1
  • Cấu hình CMake đặt target triple mặc định là wasm32-unknown-emscripten, đồng thời bật target WebAssembly và các project clang;flang;mlir
  • Sau khi build xong, có thể kiểm tra các thông tin sau bằng build/bin/flang-new --version
    • Phiên bản: flang-new version 18.1.1
    • Target: wasm32-unknown-emscripten
    • Thread model: posix

Vấn đề đầu tiên: target wasm32 chưa được triển khai

  • Khi biên dịch subroutine Fortran đơn giản foo.f08 bằng flang-new, lỗi sau xuất hiện
    • not yet implemented: target not implemented
  • Nguyên nhân là target triple wasm32-unknown-emscripten chưa được triển khai trong flang-new
  • Cách khắc phục là bản vá thêm đặc tính target TargetWasm32 vào flang/lib/Optimizer/CodeGen/Target.cpp
    • Đặt độ rộng mặc định là 32
    • Định nghĩa marshalling để chuyển đổi đối số số phức và kiểu trả về sang kiểu LLVM phía WebAssembly
    • Nối nhánh llvm::Triple::ArchType::wasm32 với TargetWasm32
  • Sau khi vá và build lại, mã nguồn Fortran được biên dịch thành object WebAssembly
    • Kết quả file foo.o: WebAssembly (wasm) binary module version 0x1 (MVP)
    • Có thể thấy symbol foo_ trong llvm-nm foo.o

Gọi subroutine Fortran từ C và JavaScript

  • Routine Fortran thường truyền đối số theo tham chiếu, và có thể khai báo cách dùng đối số bằng INTENT()
  • Subroutine Fortran ví dụ foo nhận các đối số số nguyên x, y, z và thực hiện z = x + y
  • Khi build native bằng gfortran -c foo.f08 -o foo.o, tên symbol có thể được thêm dấu gạch dưới ở cuối như foo_
  • Khi gọi từ C, khai báo symbol bên ngoài như extern void foo_(int*, int*, int*); và truyền địa chỉ của đối số
  • Trong WebAssembly, có thể dùng Emscripten để liên kết foo.o do flang-new tạo với mã C
    • emcc main.c foo.o -o main.js
    • Đầu ra node main.js: 1 + 1 = 2
  • Gọi trực tiếp từ JavaScript

    • Cũng có thể gọi trực tiếp subroutine Fortran từ JavaScript mà không cần mã C
    • Ở bước liên kết Emscripten, export _foo_, _malloc, _free
    • emcc foo.o -sEXPORTED_FUNCTIONS=_foo_,_malloc,_free -o foo.js
    • JavaScript cấp phát vùng lưu số nguyên bằng Module._malloc(), ghi giá trị vào Module.HEAPU32, rồi gọi Module._foo_(x, y, z)
    • Kết quả chạy như sau
    • x = 123
    • y = 456
    • x + y = 579
    • Trong trình duyệt, tải foo.jsstandalone.js từ HTML để thấy cùng kết quả trong JavaScript console

Vấn đề thứ hai: thư viện runtime Fortran

  • Khi build subroutine Fortran có chứa PRINT *, "Hello, World!", bước liên kết báo lỗi thiếu runtime symbol
    • _FortranAioBeginExternalListOutput
    • _FortranAioOutputAscii
    • _FortranAioEndIoStatement
  • Nguyên nhân là thư viện runtime LLVM Fortran chưa được biên dịch cho WebAssembly
  • Thư viện runtime được viết bằng C++ trong llvm-project/flang/runtime của cây mã nguồn LLVM
  • Nếu build mã nguồn runtime bằng em++emar của Emscripten, có thể tạo thư viện tĩnh build/flang/runtime/libFortranRuntime.a
  • Liên kết thư viện này giúp bản build Hello, World! tiếp tục, nhưng ban đầu phát sinh cảnh báo không khớp signature hàm

Vấn đề thứ ba: khác biệt kích thước long giữa host và target

  • Khi liên kết hello.o với thư viện runtime Fortran, xuất hiện cảnh báo không khớp signature của _FortranAioOutputAscii
    • Phía object Fortran kỳ vọng (i32, i32, i64) -> i32
    • Phía runtime build bằng Emscripten định nghĩa (i32, i32, i32) -> i32
  • WebAssembly yêu cầu kiểu đối số và kiểu trả về của các symbol được định nghĩa qua nhiều đơn vị biên dịch phải nhất quán
  • Vấn đề này không chỉ dừng ở cảnh báo; khi chạy bằng Node, nó thất bại với RuntimeError: unreachable
  • Trong RTBuilder.h của LLVM Flang có chú thích TODO rằng việc dùng sizeof giả định build == host == target
  • Trên các host Unix-like 64-bit hiện đại, sizeof(long) là 8 byte, nhưng trên target wasm32-unknown-emscripten nó phải là 4 byte
  • Khi truyền đối số kiểu CHARACTER của Fortran vào hàm hoặc subroutine, có thể có đối số ẩn bổ sung để truyền độ dài chuỗi
  • Trong thư viện runtime Fortran, đối số độ dài này được khai báo là size_t, và qua chuỗi typedef nó tương đương unsigned long
  • Khác biệt kích thước của đối số ẩn này gây ra sự không khớp i64i32

Bản vá tạm thời: ép giá trị 4 byte

  • Giải pháp lý tưởng là khi cross-compile, flang-new xuất i32 hoặc i64 phù hợp với kiến trúc đích và data model, độc lập với host
  • Hiện tại, tác giả dùng bản vá hard-code kích thước long là 4 byte cho wasm32 và Emscripten
  • Nội dung bản vá gồm hai hướng
    • Trong RTBuilder.h, ép kiểu mô hình của longunsigned long thành 8 * 4 thay vì 8 * sizeof(...)
    • Trong CodeGen.cpp, tạo đối số gọi malloc() dưới dạng số nguyên 32-bit thay vì 64-bit, và cast kích thước cấp phát sang i32
  • Thay đổi này cũng sửa được cấp phát động dựa trên ALLOCATE() được giới thiệu trong Fortran 90
  • Sau khi build lại, liên kết hello.f08hello.c với thư viện runtime không còn cảnh báo, và Node in ra
    • Hello, World!

Build BLAS sang WebAssembly

  • BLAS là tập hợp các routine cấp thấp thực hiện các phép toán tuyến tính phổ biến như nhân ma trận/vector
  • Các routine BLAS ban đầu được công bố năm 1979 và là chuẩn de facto trong lĩnh vực tính toán số trị
  • Triển khai tham chiếu BLAS 3.12.0 được viết bằng Fortran 90 và có thể tải từ netlib
  • Build bằng cách chỉ định các công cụ sau trong make.inc
    • FC = ../build/bin/flang-new
    • FFLAGS = -O2
    • AR = emar
    • RANLIB = emranlib
  • Kết quả build tạo thư viện tĩnh blas_LINUX.a
  • Routine Fortran ví dụ bar gọi routine BLAS level 2 ZGEMV()
  • ZGEMV() thực hiện phép toán ma trận-vector số phức, và ví dụ dùng đối số COMPLEX(KIND=8) cùng đối số thiết lập CHARACTER'N'
  • Chương trình C tạo mảng số phức, truyền cho routine Fortran rồi in kết quả
  • Kết quả chạy Node như sau
    • Y[0]: 23.000000 + 6.000000i
    • Y[1]: 18.000000 + 10.000000i
    • Y[2]: 6.000000 + 16.000000i
  • Kết quả này xác nhận BLAS biên dịch từ mã nguồn Fortran 90 chạy được dưới WebAssembly

Ví dụ trình duyệt: bộ phân loại chữ số viết tay

  • Demo phân loại chữ số 0–9 vẽ tay bằng mạng nơ-ron nhân tạo perceptron đa tầng (MLP)
  • Người dùng có thể vẽ chữ số bằng chuột hoặc màn hình cảm ứng, và xác suất tương đối do mạng dự đoán được hiển thị trong biểu đồ bên phải
  • Trọng số mô hình được huấn luyện trước bằng Python, nhưng việc phân loại được thực hiện trong trình duyệt lúc chạy bằng JavaScript và WebAssembly
  • Quy trình phân loại MLP về bản chất là lặp lại các phép cộng và nhân ma trận-vector
  • Phần tính toán nặng được xử lý bởi một subroutine Fortran dùng routine BLAS level 2 DGEMV()

Build LAPACK sang WebAssembly

  • LAPACK là thư viện phần mềm giải số trị các bài toán đại số tuyến tính, được xây dựng trên BLAS
  • Triển khai tham chiếu LAPACK 3.12.0 do netlib cung cấp và được phân phối theo giấy phép BSD sửa đổi
  • Sau khi copy make.inc.example thành make.inc, thay đổi các thiết lập sau
    • Đặt FC là đường dẫn đầy đủ tới flang-new đã build
    • FFLAGS = -O2
    • AR = emar
    • RANLIB = emranlib
    • TIMER = INT_CPU_TIME
  • Lệnh make lib tạo thư viện tĩnh WebAssembly liblapack.a
  • Sau đó, có thể gọi các routine LAPACK theo cách tương tự ví dụ BLAS

Ví dụ trình duyệt: nội suy đa thức bằng đại số tuyến tính

  • Demo tìm đa thức nội suy cho một tập điểm, cho thấy routine LAPACK chạy trong trình duyệt
  • Khi người dùng bấm vào plot để thêm điểm mới, nó tìm đa thức nội suy đi qua tất cả các điểm
  • Phương pháp dùng phương pháp Vandermonde
  • Hệ phương trình đại số tuyến tính thu được bằng cách này được giải số trị bằng routine DGELS() của LAPACK
  • Luôn có thể tìm được đa thức bậc n-1 chứa chính xác n điểm dữ liệu
  • Khi n lớn, đa thức có thể dao động mạnh giữa các điểm dữ liệu liên tiếp, tạo hiện tượng Runge; có thể tránh bằng nội suy spline

Những việc còn lại và công cụ được cung cấp

  • Với LLVM Flang đã vá, có thể biên dịch mã Fortran hiện đại thành object WebAssembly
  • Ưu điểm của cách này là có thể dùng các công cụ và thư viện Fortran hiện có, thay vì viết mới thuật toán số trị cho web bằng JavaScript
  • Nếu flang-new chính thức hỗ trợ WebAssembly, gánh nặng duy trì fork LLVM cho webR và các package R sẽ giảm
  • Hiện vẫn cần một hướng tốt hơn để sửa đúng các vấn đề của LLVM Flang và cross-compilation trên mọi target
  • Với người dùng khó hoặc không muốn tự build LLVM Flang, GitHub Container Registry cung cấp container Docker chứa binary LLVM Flang đã vá

1 bình luận

 
GN⁺ 2024-04-07
Các ý kiến trên Hacker News
  • Bổ sung một chút bối cảnh, cuộc khám phá Fortran này là một phần trong công việc WebR rất tuyệt mà George đang thực hiện để chạy R trong trình duyệt
    Trong mã nguồn R có khá nhiều mã Fortran, và theo tôi biết, WebR ban đầu dùng f2c để biên dịch Fortran sang C trước, rồi biên dịch C đó sang wasm
    Nhờ bản vá LLVM Flang, giờ có thể build WebR bằng một trình biên dịch Fortran thật sự
    George không nói trực tiếp trong bài blog, nhưng từng nói rằng anh ấy hy vọng Flang sẽ chấp nhận bản vá này hoặc triển khai theo cách tốt hơn
    Khi đó sẽ không cần duy trì bản vá riêng nữa, và Flang không chỉnh sửa cũng có thể biên dịch sang wasm, mang lại lợi ích cho các dự án khác dùng Fortran
    https://docs.r-wasm.org/webr/latest/

    • Pull request luôn được hoan nghênh (https://github.com/llvm/llvm-project), và nếu cần trợ giúp thì có thể liên hệ cộng đồng phát triển LLVM Fortran (https://discourse.llvm.org/c/subprojects/flang/33)
      Tuy nhiên tôi đang tập trung vào những việc cần thiết để hoàn tất phát triển sản phẩm Fortran của Nvidia, nên không còn thời gian dành cho công việc kiểu này
    • Việc chuyển F77 sang JavaScript bằng chuyển đổi mã nguồn sang mã nguồn cũng đã khá ổn, nhưng WASM thì tốt hơn
  • 20 năm trước tôi từng làm việc về biên dịch FORTRAN tại Xilinx, và điều duy nhất tôi nhớ là trong file header f2c.h có định nghĩa barf
    /* f2c.h -- Standard Fortran to C header file /
    /* barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed."
    (https://www.netlib.org/clapack/f2c.h)

    • Việc tôi viết FORTRAN toàn chữ hoa có nói lên điều gì về tôi không nhỉ? Với mắt tôi thì Fortran trông hơi lạ
  • Tôi rất thích cách giải thích bằng ví dụ không tầm thường đơn giản nhất
    Bài viết dựa trên một vấn đề cụ thể là “gọi hàm BLAS từ JavaScript”, nên tôi có cảm giác học được rất nhiều; đúng là một bài viết hay

  • Tôi không biết nên thán phục hay kinh hãi, và có lẽ là cả hai
    Khi build f18, tôi khuyên nên dùng mã nguồn mới nhất của llvm-project/main
    Dự án đang thay đổi nhanh, nên sẽ rất lãng phí thời gian nếu debug những vấn đề đã được sửa hoặc bỏ lỡ những tính năng đã được triển khai

    • Tôi không hiểu đủ về mã nguồn LLVM nên khó nắm được ý chính
      Có phải là họ đang làm bản port WebAssembly để đi đến điểm mà mã trung gian hoạt động được tới tận Fortran không?
  • Tôi không rành về phát triển WebAssembly
    Từ góc nhìn người dùng, WebAssembly hiện tại có đem lại gì ngay lúc này không? Hay nó giống công việc đặt nền móng cho một tương lai nơi chương trình trở nên thật sự di động hơn?
    Tôi có nghe nói thiết bị WebAssembly giúp áp đặt hạn chế truy cập như mạng hay file dễ hơn, nhưng không rõ đó là lý thuyết hay đã được triển khai rồi

    • Về cơ bản, Wasm là một máy ảo, và ở khía cạnh tính di động thì rất giống JVM
      Khác biệt cốt lõi là bản thân Wasm không có thư viện chuẩn và cũng không phơi bày hàm nhập/xuất nào
      Vì vậy host, tức là VM, có thể được bạn tự tạo và phơi bày các hàm để binary Wasm sử dụng; binary Wasm chỉ có thể truy cập thế giới bên ngoài thông qua đúng các hàm đó
      Một ưu điểm nữa là định dạng binary không độc quyền và có đặc tả, nên bất kỳ ai cũng có thể triển khai một VM Wasm
      Tuy nhiên hiện giờ chưa thể nói là đã ở trạng thái tốt; vẫn còn quá sớm, có nhiều tính năng mới đang được chuẩn hóa bởi các nhóm kiểu như W3C, và quy trình thì rất chậm
    • Nếu bạn là nhà phát triển hoặc đang phân phối sản phẩm và muốn sandboxing vững chắc, WASM gần như là lựa chọn tốt nhất có thể dùng hiện nay
      Cũng có cách để triển khai hoặc cross-compile cho hầu hết các mục tiêu
    • Nếu được triển khai đúng, khách hàng không nên nhận ra điều đó
      Nó giống như việc người ta thường không biết và cũng không bận tâm lắm CPU máy tính là ARM hay x86
      Vì vậy nếu không quan tâm đến các chi tiết như mã chạy native hay chạy trên VM như JVM, .NET, WASM, thì khó nói nó cung cấp thêm điều gì so với các giải pháp khác
      Thường thì chỉ các trường hợp tệ mới nổi bật, rồi chúng biến thành meme kiểu “mọi chương trình Electron đều là quái vật phình to ngốn tài nguyên, còn mọi ứng dụng native thì tự động là kỳ quan kỹ nghệ phần mềm hiệu quả”
  • Tiếc là nếu tôi còn giữ mã Fortran 78 viết hồi 1981/82 thì đã có thể thử xem nó có chạy ở đây không
    Đó là formatter mã nguồn cho ngôn ngữ lập trình Jovial, và thật ra không phải việc nên làm bằng Fortran, nhưng lúc đó chỉ có lựa chọn ấy

    • Có phải bạn từng làm ở Hughes tại Orange County không?
  • Có hệ sinh thái đại số tuyến tính ở mức tương đối sẵn sàng cho production nào dùng được từ JavaScript không?
    Khi tìm kiếm thì thường chỉ thấy các bản port JavaScript của những thư viện quen thuộc đã khoảng 10 năm tuổi, chẳng hạn port qua emscripten; tôi tự hỏi liệu mình có bỏ sót gì không

    • Có thứ nào tương đương BLAS trên WebGPU hoặc WebNN không?
  • Thật lạ là bài không đi sâu hơn vào LFortran
    Cũng có một ví dụ WASM tuyệt vời và đáng kinh ngạc chạy trực tuyến
    https://dev.lfortran.org/

    • Bài viết nói rằng trình biên dịch LFortran đã tiến bộ đáng kể trong vài năm qua
      Năm 2020, nó còn thiếu nhiều tính năng và chỉ hỗ trợ một tập con rất nhỏ của Fortran, nhưng hiện nay đã hỗ trợ phạm vi tính năng ngôn ngữ rộng hơn nhiều và có thể biên dịch khá nhiều mã Fortran
      Cũng có thể biên dịch native sang WebAssembly
      Tuy nhiên, các nhà phát triển cho biết LFortran vẫn còn những chỗ chưa hoàn thiện khi sử dụng, dự án hiện được xem là ở giai đoạn alpha và có thể gặp vấn đề khi biên dịch mã thực tế
      Một số dự án như MINPACK có thể biên dịch thành công, nhưng vì chưa hỗ trợ toàn bộ đặc tả Fortran nên khá nhiều dự án lớn hơn vẫn chưa thể biên dịch
      Các nhà phát triển LFortran đặt mục tiêu hỗ trợ đầy đủ Fortran 2018, và một tính năng đáng chú ý là REPL Fortran tương tác kiểu Jupyter
      Sau vài năm phát triển nữa, nó được kỳ vọng sẽ trở thành một lựa chọn tuyệt vời để biên dịch mã Fortran cho WebAssembly
      Ngoài ra, bài cũng bảo hãy xem demo LFortran tại https://dev.lfortran.org; rất ấn tượng, nhưng thao tác đầu tiên tôi thử là đổi x * 2 thành x * 3 thì bộ sinh mã hiện chưa hỗ trợ
  • Cũng có Fortran trên .NET và Java
    https://www.silverfrost.com/14/ftn95/ftn95_fortran_95_for_microsoft_dotnet_features.aspx
    https://dl.acm.org/doi/10.1145/376656.376833

  • Khi làm https://medium.com/@tomasreimers/compiling-tensorflow-for-the-browser-f3387b8e1e1c, tôi đã nghĩ thật may là TensorFlow dùng Eigen chứ không phải BLAS/Lapack, thư viện toán học phổ biến viết bằng Fortran
    Nếu không thì khối lượng công việc đã lớn hơn nhiều