| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| module mlir_forge_kernels |
| use iso_c_binding |
| use bob_kinds |
| implicit none |
|
|
| public :: mlir_forge_pipeline |
| public :: inject_quantum_adapters |
| public :: build_pass_pipeline |
|
|
| |
| |
| |
|
|
| |
| type, bind(C) :: mlir_forge_backend_t |
| type(c_ptr) :: ctx |
| type(c_ptr) :: mod |
| end type mlir_forge_backend_t |
|
|
| |
| interface |
| subroutine mlir_context_create(ctx) bind(C, name="mlir_context_create") |
| use iso_c_binding |
| type(c_ptr), intent(out) :: ctx |
| end subroutine |
| end interface |
|
|
| |
| interface |
| function mlir_module_load_from_bytes(ctx, bytes, nbytes) result(mod) & |
| bind(C, name="mlir_module_load_from_bytes") |
| use iso_c_binding |
| type(c_ptr), value :: ctx |
| type(c_ptr), value :: bytes |
| integer(c_int), value :: nbytes |
| type(c_ptr) :: mod |
| end function |
| end interface |
|
|
| |
| interface |
| function mlir_opt_apply_passes(mod, pass_pipeline) result(success) & |
| bind(C, name="mlir_opt_apply_passes") |
| use iso_c_binding |
| type(c_ptr), value :: mod |
| character(kind=c_char), intent(in) :: pass_pipeline(*) |
| integer(c_int) :: success |
| end function |
| end interface |
|
|
| |
| interface |
| function mlir_module_dump_to_bytes(mod, out_bytes, out_nbytes) result(success) & |
| bind(C, name="mlir_module_dump_to_bytes") |
| use iso_c_binding |
| type(c_ptr), value :: mod |
| type(c_ptr), intent(out) :: out_bytes |
| integer(c_int), intent(out) :: out_nbytes |
| integer(c_int) :: success |
| end function |
| end interface |
|
|
| |
| interface |
| subroutine mlir_context_destroy(ctx) bind(C, name="mlir_context_destroy") |
| use iso_c_binding |
| type(c_ptr), value :: ctx |
| end subroutine |
| end interface |
|
|
| contains |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| subroutine mlir_forge_pipeline(pipeline_ir_bytes, ir_nbytes, target_triple, constraints, & |
| quantum_available, optimized_ir_bytes, opt_nbytes) |
| implicit none |
|
|
| |
| integer, intent(in) :: ir_nbytes, quantum_available |
| integer(c_int8_t), dimension(ir_nbytes), intent(in), target :: pipeline_ir_bytes |
| integer, intent(out) :: opt_nbytes |
|
|
| |
| character(len=*), intent(in) :: target_triple |
| real(kind=wp), dimension(4), intent(in) :: constraints |
|
|
| |
| integer(c_int8_t), dimension(:), allocatable, intent(out) :: optimized_ir_bytes |
|
|
| |
| type(c_ptr) :: ctx, mod, out_ptr |
| integer(c_int) :: success, c_nbytes |
| character(len=512) :: pass_pipeline |
| character(len=:), allocatable :: c_triple |
|
|
| |
| |
| |
| call mlir_context_create(ctx) |
| if (.not. c_associated(ctx)) then |
| print '(A)', "[FORGE] ERROR: Failed to create MLIR context" |
| opt_nbytes = 0 |
| return |
| end if |
|
|
| |
| |
| |
| mod = mlir_module_load_from_bytes(ctx, c_loc(pipeline_ir_bytes(1)), ir_nbytes) |
| if (.not. c_associated(mod)) then |
| print '(A)', "[FORGE] ERROR: Failed to load MLIR module" |
| call mlir_context_destroy(ctx) |
| opt_nbytes = 0 |
| return |
| end if |
|
|
| |
| |
| |
| call build_pass_pipeline(target_triple, constraints, quantum_available, pass_pipeline) |
| print '(A,A)', "[FORGE] Pass pipeline: ", trim(pass_pipeline) |
|
|
| |
| |
| |
| success = mlir_opt_apply_passes(mod, trim(pass_pipeline) // c_null_char) |
| if (success /= 0) then |
| print '(A)', "[FORGE] ERROR: MLIR optimization failed" |
| call mlir_context_destroy(ctx) |
| opt_nbytes = 0 |
| return |
| end if |
| print '(A)', "[FORGE] Optimization complete" |
|
|
| |
| |
| |
| success = mlir_module_dump_to_bytes(mod, out_ptr, c_nbytes) |
| if (success /= 0 .or. .not. c_associated(out_ptr)) then |
| print '(A)', "[FORGE] ERROR: Failed to dump MLIR module" |
| call mlir_context_destroy(ctx) |
| opt_nbytes = 0 |
| return |
| end if |
|
|
| |
| |
| |
| allocate(optimized_ir_bytes(c_nbytes)) |
| block |
| integer(c_int8_t), pointer :: c_ptr_arr(:) |
| call c_f_pointer(out_ptr, c_ptr_arr, [c_nbytes]) |
| optimized_ir_bytes(:) = c_ptr_arr(:) |
| end block |
|
|
| opt_nbytes = c_nbytes |
| print '(A,I0)', "[FORGE] Output IR size: ", opt_nbytes |
|
|
| |
| call mlir_context_destroy(ctx) |
|
|
| end subroutine mlir_forge_pipeline |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| subroutine inject_quantum_adapters(ir_bytes, ir_nbytes, quantum_available, & |
| adapted_ir_bytes, adapted_nbytes) |
| implicit none |
|
|
| integer, intent(in) :: ir_nbytes, quantum_available |
| integer(c_int8_t), dimension(ir_nbytes), intent(in), target :: ir_bytes |
| integer, intent(out) :: adapted_nbytes |
| integer(c_int8_t), dimension(:), allocatable, intent(out) :: adapted_ir_bytes |
|
|
| if (quantum_available == 0) then |
| |
| allocate(adapted_ir_bytes(ir_nbytes)) |
| adapted_ir_bytes(:) = ir_bytes(:) |
| adapted_nbytes = ir_nbytes |
| return |
| end if |
|
|
| |
| |
| |
| allocate(adapted_ir_bytes(ir_nbytes)) |
| adapted_ir_bytes(:) = ir_bytes(:) |
| adapted_nbytes = ir_nbytes |
|
|
| print '(A)', "[FORGE] Quantum adapter injection (Phase 2)" |
|
|
| end subroutine inject_quantum_adapters |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| subroutine build_pass_pipeline(target_triple, constraints, quantum_available, pipeline_str) |
| implicit none |
|
|
| character(len=*), intent(in) :: target_triple |
| real(kind=wp), dimension(4), intent(in) :: constraints |
| integer, intent(in) :: quantum_available |
| character(len=512), intent(out) :: pipeline_str |
|
|
| real(kind=wp) :: latency_ms, memory_mb, power_w, quantum_budget |
| character(len=128) :: tile_sizes |
|
|
| latency_ms = constraints(1) |
| memory_mb = constraints(2) |
| power_w = constraints(3) |
| quantum_budget = constraints(4) |
|
|
| |
| pipeline_str = "builtin.module(func.func(" |
|
|
| |
| pipeline_str = trim(pipeline_str) // "affine-loop-fusion," |
|
|
| |
| if (latency_ms < 1.0_wp) then |
| |
| tile_sizes = "4,4" |
| else if (memory_mb < 512.0_wp) then |
| |
| tile_sizes = "32,32" |
| else |
| |
| tile_sizes = "16,16" |
| end if |
| pipeline_str = trim(pipeline_str) // "linalg-tile{tile-sizes=" // trim(tile_sizes) // "}," |
|
|
| |
| if (power_w < 10.0_wp) then |
| |
| pipeline_str = trim(pipeline_str) // "vectorize{vectorize-vector-width=128}," |
| else |
| |
| pipeline_str = trim(pipeline_str) // "vectorize," |
| end if |
|
|
| |
| if (index(target_triple, "aarch64") > 0) then |
| |
| pipeline_str = trim(pipeline_str) // "canonicalize-for-sve2," |
| else if (index(target_triple, "x86_64") > 0) then |
| |
| pipeline_str = trim(pipeline_str) // "canonicalize-for-avx512," |
| else if (index(target_triple, "nvptx") > 0) then |
| |
| pipeline_str = trim(pipeline_str) // "gpu-kernel-outlining," |
| pipeline_str = trim(pipeline_str) // "gpu-module-to-binary," |
| end if |
|
|
| |
| if (quantum_available /= 0 .and. quantum_budget > 0.0_wp) then |
| |
| pipeline_str = trim(pipeline_str) // "convert-linalg-to-quantum," |
| end if |
|
|
| |
| pipeline_str = trim(pipeline_str) // & |
| "convert-linalg-to-loops,convert-vector-to-scf,convert-scf-to-llvm,convert-func-to-llvm))" |
|
|
| end subroutine build_pass_pipeline |
|
|
| end module mlir_forge_kernels |
|
|