// Inputs for --loom-lower-for-to-graph: modules whose dataflow.thread // definitions own explicit loom.spatial_region publication boundaries. start: {new NTHREADS = random.randint(1, 2); new TID = 0; new GID = 0} 'module {\n' helper_callables host_container threads '}\n'; helper_callables: 'func.func @helper_double(%a: i32) -> i32 {\n' ' %d = arith.addi %a, %a : i32\n' ' return %d : i32\n' '}\n\n' 'llvm.func @extern_scale(i32) -> i32\n\n'; host_container: 'func.func @host_container(%target: memref<4xi32>, %value: i32) {\n' ' %hz = arith.constant 0 : index\n' ' %hn = arith.constant 4 : index\n' ' %hs = arith.constant 1 : index\n' ' scf.for %hi = %hz to %hn step %hs {\n' ' memref.store %value, %target[%hi] : memref<4xi32>\n' ' }\n' ' return\n' '}\n\n'; threads: (TID < NTHREADS) thread_def {TID += 1} threads | (TID == NTHREADS) ''; thread_def: 'dataflow.thread private @thread_' [str(TID)] ' domain(#dataflow.thread_domain)(%mem: memref<4xi32>, %val: i32, %flag: i1) ctrl (%start: none) {\n' ' %lo = arith.constant 0 : index\n' ' %hi = arith.constant 2 : index\n' ' %stp = arith.constant 1 : index\n' {new NSITES = random.randint(1, 2); new SID = 0; new ICALL = random.choice([0, 1])} instruction_core_call sites ' dataflow.thread.yield\n' '}\n\n'; // A non-inlined InstructionCore call whose callee body is graph-free may // remain in the thread body next to the publication boundary. instruction_core_call: (ICALL == 0) '' | (ICALL == 1) ' %icall = func.call @helper_double(%val) : (i32) -> i32\n'; sites: (SID < NSITES) site {SID += 1} sites | (SID == NSITES) ''; site: {new NEST = random.choice([0, 0, 1, 2])} nested_site; nested_site: (NEST == 0) region_site | (NEST == 1) ' scf.if %flag {\n' region_site ' }\n' | (NEST == 2) ' scf.for %iv = %lo to %hi step %stp {\n' region_site ' }\n'; // The selected-into-candidate call forms make the whole publication // transaction fail closed, so they are sampled at a lower rate than the // publishable forms. region_site: {new FORM = random.choice([0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4])} region_form {GID += 1}; region_form: (FORM == 0) region_value | (FORM == 1) region_memory | (FORM == 2) region_branch | (FORM == 3) region_freeze | (FORM == 4) region_loop | (FORM == 5) region_call; // Value-in / value-out candidate: pure arithmetic actors. region_value: ' %r' [str(GID)] ' = "loom.spatial_region"(%val)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%a: i32):\n' ' %s = arith.addi %a, %a : i32\n' ' %p = arith.muli %s, %a : i32\n' ' "loom.spatial_yield"(%p)\n' ' <{operandSegmentSizes = array}> : (i32) -> ()\n' ' }) {graph_name = "graph_' [str(GID)] '", source_maps = []} : (i32) -> i32\n'; // Value input plus memory input, storing into the imported memref. region_memory: ' "loom.spatial_region"(%val, %mem)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%payload: i32, %memory: memref<4xi32>):\n' ' %z = arith.constant 0 : index\n' ' memref.store %payload, %memory[%z] : memref<4xi32>\n' ' "loom.spatial_yield"()\n' ' <{operandSegmentSizes = array}> : () -> ()\n' ' }) {graph_name = "graph_' [str(GID)] '", source_maps = []} : (i32, memref<4xi32>) -> ()\n'; // Structured mutually exclusive sites inside one candidate. region_branch: ' %r' [str(GID)] ' = "loom.spatial_region"(%val, %flag)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%a: i32, %c: i1):\n' ' %sel = scf.if %c -> (i32) {\n' ' %t = arith.addi %a, %a : i32\n' ' scf.yield %t : i32\n' ' } else {\n' ' %e = arith.muli %a, %a : i32\n' ' scf.yield %e : i32\n' ' }\n' ' "loom.spatial_yield"(%sel)\n' ' <{operandSegmentSizes = array}> : (i32) -> ()\n' ' }) {graph_name = "graph_' [str(GID)] '", source_maps = []} : (i32, i1) -> i32\n'; region_freeze: ' %r' [str(GID)] ' = "loom.spatial_region"(%val)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%a: i32):\n' ' %stable = llvm.freeze %a : i32\n' ' "loom.spatial_yield"(%stable)\n' ' <{operandSegmentSizes = array}> : (i32) -> ()\n' ' }) {graph_name = "graph_' [str(GID)] '", source_maps = []} : (i32) -> i32\n'; // Enclosing loop inside the candidate repeatedly activates the same schedule. region_loop: ' %r' [str(GID)] ' = "loom.spatial_region"(%val)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%a: i32):\n' ' %z = arith.constant 0 : index\n' ' %n = arith.constant 2 : index\n' ' %o = arith.constant 1 : index\n' ' %acc = scf.for %i = %z to %n step %o iter_args(%carry = %a) -> (i32) {\n' ' %next = arith.addi %carry, %a : i32\n' ' scf.yield %next : i32\n' ' }\n' ' "loom.spatial_yield"(%acc)\n' ' <{operandSegmentSizes = array}> : (i32) -> ()\n' ' }) {graph_name = "graph_' [str(GID)] '", source_maps = []} : (i32) -> i32\n'; // Adversarial candidate: an InstructionCore call selected into the candidate. region_call: {new CALLEE = random.choice([0, 1])} region_call_body; region_call_body: (CALLEE == 0) region_func_call | (CALLEE == 1) region_llvm_call; region_func_call: ' %r' [str(GID)] ' = "loom.spatial_region"(%val)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%a: i32):\n' ' %called = func.call @helper_double(%a) : (i32) -> i32\n' ' "loom.spatial_yield"(%called)\n' ' <{operandSegmentSizes = array}> : (i32) -> ()\n' ' }) {graph_name = "graph_' [str(GID)] '", source_maps = []} : (i32) -> i32\n'; region_llvm_call: ' %r' [str(GID)] ' = "loom.spatial_region"(%val)\n' ' <{operandSegmentSizes = array,\n' ' resultSegmentSizes = array}> ({\n' ' ^bb0(%a: i32):\n' ' %called = llvm.call @extern_scale(%a) : (i32) -> i32\n' ' "loom.spatial_yield"(%called)\n' ' <{operandSegmentSizes = array}> : (i32) -> ()\n' ' }) {graph_name = "graph_' [str(GID)] '", source_maps = []} : (i32) -> i32\n';