// Structured Program Candidate inputs for loom-lower-scf-to-dfg. // A module holds ownership-neutral llvm.func / func.func callables plus // module-scope dataflow.thread definitions. A selected SpatialCore candidate // is already materialized as an explicit loom.spatial_region inside exactly // one thread; its body is fixed-domain semantic SCF with arbitrary nesting of // scf.if, source-sequential scf.for, scf.while, and fixed-width graph-owned // scf.parallel / effect-form scf.forall. start: {new V = 0; new T = 0; new N_THREADS = random.randint(1, 2); new WITH_CALLABLES = random.choice([0, 1])} callables threads; // Imported Host / InstructionCore code stays in its llvm.func envelope; // genuinely native func.func callables may coexist. Both are // ownership-neutral and must not authorize graph creation. callables: (WITH_CALLABLES == 0) '' | (WITH_CALLABLES == 1) 'llvm.func @imported_callable(i64) -> i64\n' 'func.func private @native_callable(%arg_a: i32) -> i32 {\n' ' return %arg_a : i32\n' '}\n'; threads: (T < N_THREADS) thread {T += 1} threads | (T == N_THREADS) ''; thread: {new SPATIAL = random.choice([0, 1, 1, 1])} 'dataflow.thread private @' thread_name ' domain(#dataflow.thread_domain)(\n' ' %limit: index, %memory: memref) ctrl (%ctrl: none) {\n' thread_body ' dataflow.thread.yield\n' '}\n'; thread_name: ['thread_' + str(T)]; graph_name: ['g_thread_' + str(T)]; thread_body: (SPATIAL == 0) instruction_body | (SPATIAL == 1) spatial_body; // InstructionCore-resident thread body code outside any spatial boundary. instruction_body: ' %izero = arith.constant 0 : index\n' ' %ione = arith.constant 1 : index\n' ' memref.store %ione, %memory[%izero] : memref\n'; // The explicit selected SpatialCore candidate. loom.spatial_region is // IsolatedFromAbove, so every value used inside comes from its entry block // arguments or from constants defined in the body. spatial_body: {new DEPTH = random.randint(1, 3); new IDX = '%zero'} ' "loom.spatial_region"(%limit, %memory)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%lim: index, %target: memref):\n' ' %zero = arith.constant 0 : index\n' ' %one = arith.constant 1 : index\n' ' %two = arith.constant 2 : index\n' ' %flag = arith.cmpi ult, %zero, %two : index\n' block ' "loom.spatial_yield"()\n' ' <{operandSegmentSizes = array}> : () -> ()\n' ' }) {graph_name = "' graph_name '", source_maps = []} :\n' ' (index, memref) -> ()\n'; block: {new STMT_N = random.randint(1, 2); new K = 0} stmts; stmts: (K < STMT_N) stmt {K += 1} stmts | (K == STMT_N) ''; stmt: (DEPTH > 0) for_stmt | (DEPTH > 0) if_stmt | (DEPTH > 0) parallel_stmt | (DEPTH > 0) forall_stmt | (DEPTH > 0) while_stmt | leaf_stmt; name_id: [str(ID)]; // Source-sequential scf.for with compile-time constant trip domain. for_stmt: {new DEPTH = DEPTH - 1; new ID = V; V += 1} ' scf.for %iv' name_id ' = %zero to %two step %one {\n' block ' }\n'; if_stmt: {new DEPTH = DEPTH - 1; new ID = V; V += 1; new HAS_ELSE = random.choice([0, 1])} if_body; if_body: (HAS_ELSE == 0) ' scf.if %flag {\n' block ' }\n' | (HAS_ELSE == 1) ' scf.if %flag {\n' block ' } else {\n' block ' }\n'; // Fixed-width graph-owned scf.parallel in effect form (no reduction results). // Each lane derives a lane-disjoint element index from the enclosing index // expression so cross-lane legality is established in the candidate itself. parallel_stmt: {new DEPTH = DEPTH - 1; new ID = V; V += 1} ' scf.parallel (%iv' name_id ') = (%zero) to (%two) step (%one) {\n' lane_index parallel_block ' scf.reduce\n' ' }\n'; // Fixed-domain effect-form scf.forall (no shared_outs, no results). forall_stmt: {new DEPTH = DEPTH - 1; new ID = V; V += 1} ' scf.forall (%iv' name_id ') in (2) {\n' lane_index parallel_block ' }\n'; lane_index: ' %mx' name_id ' = arith.muli ' idx_name ', %two : index\n' ' %ix' name_id ' = arith.addi %mx' name_id ', %iv' name_id ' : index\n'; idx_name: [IDX]; parallel_block: {new IDX = '%ix' + str(ID)} block; while_stmt: {new DEPTH = DEPTH - 1; new ID = V; V += 1} ' %wr' name_id ' = scf.while (%wa' name_id ' = %zero) : (index) -> index {\n' ' %wc' name_id ' = arith.cmpi ult, %wa' name_id ', %two : index\n' ' scf.condition(%wc' name_id ') %wa' name_id ' : index\n' ' } do {\n' ' ^bb0(%wb' name_id ': index):\n' block ' %wn' name_id ' = arith.addi %wb' name_id ', %one : index\n' ' scf.yield %wn' name_id ' : index\n' ' }\n'; leaf_stmt: {new ID = V; V += 1; new LEAF_KIND = random.choice([0, 1])} leaf_body; leaf_body: (LEAF_KIND == 0) ' memref.store %one, %target[' idx_name '] : memref\n' | (LEAF_KIND == 1) ' %ld' name_id ' = memref.load %target[' idx_name '] : memref\n' ' %ad' name_id ' = arith.addi %ld' name_id ', %one : index\n' ' memref.store %ad' name_id ', %target[' idx_name '] : memref\n';