{"entries":[{"file_sha256":"bfc1e646e91fe0ba6d7d16e43994100b05c3b8ff79c2e07288e8955c43d9d79d","kind":"documentation_input","lines":"63-74","path":"docs/spec-compiler-part-2-scf.md","roles":["applicability","context"],"text":"The whole callable is the preferred exact CFG-to-SCF projection. When a local\nobstacle makes that projection inadmissible, raising may instead recover a\nmaximal dominance- and post-dominance-closed region with one external entry\nand one continuation. The boundary carries continuation arguments and every\nSSA value used outside the region; the rewrite is attempted on a detached\ncallable clone and is published only after the upstream transformation\nsucceeds. Any transient structured region used to establish that boundary is\ninlined before publication. Profile-bearing control, an unsupported\nterminator, or an unproved loop-hint association prevents only a region whose\nboundary contains that obstacle. A candidate with no common continuation or\nno exact live-out boundary remains in `cf` form without preventing independent\nregions in the same callable from being recovered.","why":"Sampled output obligation plus its governing context: whole-callable projection is preferred, a local obstacle (profile-bearing control, unsupported terminator, unproved loop-hint association) only prevents the region whose boundary contains it. Used to select which output callables the whole-callable assert applies to."},{"file_sha256":"bfc1e646e91fe0ba6d7d16e43994100b05c3b8ff79c2e07288e8955c43d9d79d","kind":"documentation_input","lines":"48-58","path":"docs/spec-compiler-part-2-scf.md","roles":["input_construction","input_well_formedness"],"text":"The final linked LLVM module enters S0 without replacing its LLVM callable\nenvelopes. The LLVM dialect operation remains the sole owner of linkage,\ncalling convention, COMDAT, personality, argument and result attributes,\nmemory effects, target features, floating-point environment, and every other\nLLVM ABI fact.\n\nMechanical CFG recovery operates on callable regions rather than requiring\nconversion to `func.func`. For an imported LLVM function, Loom converts LLVM\nbranch structure to exact `cf` structure where required, invokes the upstream\nregion-level CFG-to-SCF transformation, and uses an LLVM-compatible adapter\nfor return and unreachable behavior. Pass wrappers that participate in this","why":"Normative input shape: the linked module keeps its LLVM callable envelopes, and mechanical recovery runs on the callable region in exact `cf` form. The grammar therefore emits llvm.func callables whose bodies spell cf.br/cf.cond_br directly."},{"file_sha256":"bfc1e646e91fe0ba6d7d16e43994100b05c3b8ff79c2e07288e8955c43d9d79d","kind":"documentation_input","lines":"124-130","path":"docs/spec-compiler-part-2-scf.md","roles":["input_construction","input_well_formedness"],"text":"LLVM loop metadata has a loop owner only when its carrier terminator closes a\nbackedge to one exact dominating loop header. Mechanical structuring moves that\nhint to the recovered loop. Metadata on a terminator with no such backedge is\nan orphan under the LLVM loop contract: successful structuring removes the\norphan carrier, preserves the corresponding analysis fact as unknown, and does\nnot guess a loop owner. A carrier that can close backedges to multiple headers\nremains unstructured because its owner is ambiguous.","why":"Loop metadata has an owner only when its carrier closes a backedge to one exact dominating header, and an ambiguous carrier stays unstructured. The generator only attaches llvm.loop_annotation to a latch with a single dominating header, so sampled inputs carry no unproved hint association."},{"file_sha256":"cb2eccd216a4270d4b483cc2d2e246393bc3ba47dae1a0c7680d6ee9839015b9","kind":"implementation","lines":"39-64","path":"lib/Frontend/Raising/LiftCFToSCFPass.cpp","roles":["applicability","input_construction"],"text":"// A completely admissible callable is structured as one region. If an exact\n// local obstacle prevents that, maximal single-entry, single-continuation CFG\n// regions around the obstacle are considered independently. Each local region\n// is moved into a temporary scf.execute_region in a detached callable clone,\n// transformed with the same upstream utility, and immediately inlined. The\n// temporary operation is only an implementation boundary: it is never\n// published. An unprovable local region stays as `cf`, while independent local\n// regions in the same callable can still be recovered.\n//\n// A local region is excluded when:\n//\n// * a reachable branch carries weights -- `scf.if` and `scf.index_switch`\n// state no branch probability, so lifting would drop imported profile data;\n// * a reachable terminator with successors is not exactly cf.br, cf.cond_br,\n// or cf.switch -- the transformation erases a one-successor terminator it\n// does not recognize and splices its successor away, which would silently\n// restate a one-target llvm.indirectbr as an unconditional branch;\n// * a `cf.switch` selector or case value does not fit the structured\n// switch's index and 64-bit case carriers;\n// * a block owns llvm.blocktag, whose parent block identity may be observed\n// by a module-level llvm.blockaddress independently of SSA uses;\n// * an imported callable holds a value whose type LLVM cannot spell, since\n// the adapter would otherwise have to state an undefined value of that type\n// as the stronger `ub.poison`; or\n// * a loop annotation's owning loop is not exactly identifiable.\n//","why":"Enumerates exactly which local conditions exclude a region (weighted branch, unrecognized terminator such as llvm.indirectbr, wide cf.switch carrier, llvm.blocktag, LLVM-unspellable value type, unidentifiable loop owner). This fixes the obstacle guard used to select obstacle-free callables and the constructs the generator deliberately does or does not sample."},{"file_sha256":"cb2eccd216a4270d4b483cc2d2e246393bc3ba47dae1a0c7680d6ee9839015b9","kind":"implementation","lines":"65-87","path":"lib/Frontend/Raising/LiftCFToSCFPass.cpp","roles":["context"],"text":"// Every structuring traversal works on a detached clone of the callable op.\n// Unreachable components with no externally visible block identity are erased\n// from that clone, which is the one cleanup upstream's documented structural\n// preconditions require. An unreachable component containing llvm.blocktag is\n// instead retained because a module-level llvm.blockaddress can observe that\n// identity without an SSA or CFG use. The whole-callable path declines such a\n// clone. A local region may still structure when the retained component does\n// not enter its extraction boundary. Each clone is taken from the then-current\n// original and published back into its original callable op only after the\n// complete attempted rewrite succeeds. The walk is\n// post-order, so a nested callable is structured and published before its\n// enclosing callable: the ancestor is therefore cloned from an original that\n// already holds the structured descendant, and its clone carries that structure\n// through. A deferred publication would instead clone the ancestor from a\n// snapshot taken before the descendant published, so publishing that stale\n// ancestor clone would overwrite the descendant's structured body with the\n// unstructured copy the clone still held. Upstream's documented \"unspecified IR\n// on interface failure\" unwinds inside the clone, and an annotation the\n// completed clone could not place leaves that region preserved, so a clone that\n// declines is dropped without publishing. Publishing cannot fail: it preserves\n// the region's owning callable op and carries already-structured descendant\n// bodies through ancestor clones, leaving each imported callable in llvm.func\n// form as the sole ABI envelope of its body.","why":"Confirms the detached-clone/publish discipline of the obligation: each clone is published back into its original callable op only after the complete rewrite succeeds, and publishing preserves the owning callable op. Supports the callable-set publication assert."},{"file_sha256":"cb2eccd216a4270d4b483cc2d2e246393bc3ba47dae1a0c7680d6ee9839015b9","kind":"implementation","lines":"953-964","path":"lib/Frontend/Raising/LiftCFToSCFPass.cpp","roles":["context"],"text":"struct LiftCFToSCFPass\n : public ::mlir::PassWrapper> {\n MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(LiftCFToSCFPass)\n\n ::llvm::StringRef getArgument() const final { return \"loom-lift-cf-to-scf\"; }\n ::llvm::StringRef getDescription() const final {\n return \"Structure each maximal exactly provable cf-shaped region with \"\n \"the upstream CFG-to-SCF transformation, leaving an imported \"\n \"llvm.func as the callable and ABI owner of its body, retaining \"\n \"weighted or unsupported local control, and moving each imported \"\n \"loop annotation to the loop that owns its cycle.\";\n }","why":"Pass registration establishing that --loom-lift-cf-to-scf is the stage named by the claim; its description confirms the pass operates in place on callables and retains weighted or unsupported local control."},{"file_sha256":"292696bf5fab87a93df111d14e2e80fc8c172ce2b13fed973df96fbb4878bde5","kind":"implementation","lines":"174-187","path":"include/Frontend/Raising/Passes.h","roles":["context"],"text":"// Register all raising passes with the global pass registry. Lets\n// `mlir-opt` style drivers expose them via --loom-llvm-cf-to-cf,\n// --loom-lift-cf-to-scf, --loom-llvm-arith-to-arith.\nvoid registerRaisingPasses();\n\n// Append the standard Loom raising pipeline to the given pass manager:\n// loom-llvm-cf-to-cf\n// loom-lift-cf-to-scf\n// loom-llvm-arith-to-arith\n// loom-normalize-lifted-scf-exit\n// loom-deduplicate-scf-while-state\n// loom-scf-while-to-for\n// Selected SCF optimization decisions are outside this pipeline.\nvoid buildRaisingPipeline(::mlir::PassManager &pm);","why":"Documents the driver flag spelling and the ordered raising pipeline, evidencing that loom-lift-cf-to-scf can be invoked alone when the input is already in cf form (loom-llvm-cf-to-cf precedes it only to convert LLVM branch terminators)."},{"file_sha256":"5abba37ed266cb6a9b2a18dc28ff3e0f763b9c3d95d7fd13713d8cbe2c1515a1","kind":"test","lines":"1-12","path":"test/raise/cfg-structurization.mlir","roles":["context"],"text":"// RUN: split-file %s %t\n// RUN: %loom-raise %t/counted.ll | FileCheck %s --check-prefix=LOOP\n// RUN: %loom-raise %t/spin.ll | FileCheck %s --check-prefix=SPIN\n// RUN: %loom-raise %t/irreducible.ll | FileCheck %s --check-prefix=UNDEF --implicit-check-not=ub.poison\n// RUN: loom-raise-opt --loom-llvm-cf-to-cf --loom-lift-cf-to-scf %t/switch-carrier.mlir | FileCheck %s --check-prefix=SWITCH\n// RUN: loom-raise-opt --loom-lift-cf-to-scf %t/preserved.mlir | FileCheck %s --check-prefix=PRESERVE\n// RUN: loom-raise-opt --loom-lift-cf-to-scf %t/nested.mlir | FileCheck %s --check-prefix=NESTED --implicit-check-not=cf.cond_br\n// RUN: loom-raise-opt --loom-lift-cf-to-scf %t/orphan-loop-hint.mlir | FileCheck %s --check-prefix=ORPHAN --implicit-check-not=cf.cond_br\n// RUN: loom-raise-opt --loom-lift-cf-to-scf %t/numbered-default.mlir -o %t/numbered-default.out.mlir\n// RUN: loom-raise-opt %t/numbered-default.out.mlir | FileCheck %s --check-prefix=NUMBERED-DEFAULT\n// RUN: loom-raise-opt --loom-lift-cf-to-scf %t/local-regions.mlir -o %t/local-regions.out.mlir\n// RUN: loom-raise-opt --loom-lift-cf-to-scf %t/local-regions.out.mlir | FileCheck %s --check-prefix=LOCAL --implicit-check-not=scf.execute_region","why":"RUN lines showing the accepted invocations; cf-form inputs are run with --loom-lift-cf-to-scf alone, which is the invocation recorded in subject-command.json."},{"file_sha256":"5abba37ed266cb6a9b2a18dc28ff3e0f763b9c3d95d7fd13713d8cbe2c1515a1","kind":"test","lines":"349-470","path":"test/raise/cfg-structurization.mlir","roles":["input_construction","input_well_formedness"],"text":"//--- local-regions.mlir\n#local_loop = #llvm.loop_annotation\n\nmodule attributes {\n dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry>\n} {\nllvm.func @weighted_then_plain(%weighted: i1, %plain: i1, %a: i32, %b: i32) -> i32 {\n cf.cond_br %weighted weights([1, 9]), ^weighted_true, ^weighted_false\n^weighted_true:\n cf.br ^plain_entry(%a : i32)\n^weighted_false:\n cf.br ^plain_entry(%b : i32)\n^plain_entry(%seed: i32):\n cf.cond_br %plain, ^plain_true, ^plain_false\n^plain_true:\n cf.br ^exit(%seed : i32)\n^plain_false:\n cf.br ^exit(%seed : i32)\n^exit(%result: i32):\n llvm.return %result : i32\n}\n\nllvm.func @plain_then_weighted(%plain: i1, %weighted: i1, %a: i32, %b: i32) -> i32 {\n cf.cond_br %plain, ^plain_true, ^plain_false\n^plain_true:\n cf.br ^weighted_entry(%a : i32)\n^plain_false:\n cf.br ^weighted_entry(%b : i32)\n^weighted_entry(%seed: i32):\n cf.cond_br %weighted weights([2, 8]), ^weighted_true, ^weighted_false\n^weighted_true:\n cf.br ^exit(%seed : i32)\n^weighted_false:\n cf.br ^exit(%seed : i32)\n^exit(%result: i32):\n llvm.return %result : i32\n}\n\nllvm.func @nested_weighted_arm(%weighted: i1, %plain: i1, %a: i32, %b: i32) -> i32 {\n cf.cond_br %weighted weights([3, 7]), ^left, ^right\n^left:\n cf.cond_br %plain, ^left_true, ^left_false\n^left_true:\n cf.br ^exit(%a : i32)\n^left_false:\n cf.br ^exit(%b : i32)\n^right:\n cf.br ^exit(%b : i32)\n^exit(%result: i32):\n llvm.return %result : i32\n}\n\nllvm.func @unsupported_then_plain(%address: !llvm.ptr, %plain: i1, %a: i32, %b: i32) -> i32 {\n llvm.indirectbr %address : !llvm.ptr, [^target]\n^target:\n cf.cond_br %plain, ^yes, ^no\n^yes:\n cf.br ^exit(%a : i32)\n^no:\n cf.br ^exit(%b : i32)\n^exit(%result: i32):\n llvm.return %result : i32\n}\n\nllvm.func @weighted_then_loop(%weighted: i1, %limit: i32) -> i32 {\n %zero = arith.constant 0 : i32\n %one = arith.constant 1 : i32\n cf.cond_br %weighted weights([4, 6]), ^left, ^right\n^left:\n cf.br ^header(%zero : i32)\n^right:\n cf.br ^header(%one : i32)\n^header(%iv: i32):\n %done = arith.cmpi eq, %iv, %limit : i32\n cf.cond_br %done, ^exit, ^latch\n^latch:\n %next = arith.addi %iv, %one : i32\n cf.br ^header(%next : i32) {llvm.loop_annotation = #local_loop}\n^exit:\n llvm.return %iv : i32\n}\n\nllvm.func @local_wide_switch(%weighted: i1, %selector: i64, %plain: i1, %a: i32, %b: i32) -> i32 {\n cf.cond_br %weighted weights([5, 5]), ^left, ^right\n^left:\n cf.br ^switch_entry\n^right:\n cf.br ^switch_entry\n^switch_entry:\n cf.switch %selector : i64, [\n default: ^default,\n 0: ^case\n ]\n^case:\n cf.br ^plain_entry(%a : i32)\n^default:\n cf.br ^plain_entry(%b : i32)\n^plain_entry(%seed: i32):\n cf.cond_br %plain, ^plain_true, ^plain_false\n^plain_true:\n cf.br ^exit(%seed : i32)\n^plain_false:\n cf.br ^exit(%seed : i32)\n^exit(%result: i32):\n llvm.return %result : i32\n}\n\nllvm.func @direct_liveout(%weighted: i1, %plain: i1) -> i32 {\n cf.cond_br %weighted weights([6, 4]), ^left, ^right\n^left:\n cf.br ^plain_entry\n^right:\n cf.br ^plain_entry\n^plain_entry:\n %seven = arith.constant 7 : i32\n cf.cond_br %plain, ^yes, ^no\n^yes:\n cf.br ^exit\n^no:\n cf.br ^exit\n^exit:\n llvm.return %seven : i32","why":"Accepted concrete spellings of cf-form llvm.func callables with weighted cond_br, sequential and nested diamonds, and a latch-annotated cycle. The grammar's callable shapes follow these spellings (block-argument continuations, weights([a, b]) syntax, llvm.loop_annotation alias on the latch)."},{"file_sha256":"5abba37ed266cb6a9b2a18dc28ff3e0f763b9c3d95d7fd13713d8cbe2c1515a1","kind":"example","lines":"313-333","path":"test/raise/cfg-structurization.mlir","roles":["input_well_formedness"],"text":"//--- orphan-loop-hint.mlir\n#orphan_annotation = #llvm.loop_annotation\n\nllvm.func @orphan_loop_hint(%limit: i32, %skip: i1) -> i32 {\n %zero = arith.constant 0 : i32\n %one = arith.constant 1 : i32\n cf.br ^header(%zero : i32)\n^header(%iv: i32):\n cf.cond_br %skip, ^latch, ^body {\n llvm.loop_annotation = #orphan_annotation\n }\n^body:\n cf.br ^latch\n^latch:\n %next = arith.addi %iv, %one : i32\n %done = arith.cmpi eq, %next, %limit : i32\n cf.cond_br %done, ^exit, ^header(%next : i32)\n^exit:\n llvm.return %next : i32\n}","why":"Accepted orphan/latch loop-hint spelling and the #llvm.loop_annotation alias declaration plus its {llvm.loop_annotation = ...} placement on a cf branch, used verbatim by the generator preamble and latch hint."}],"primary_bundle_sha256":"f73a24e5313c93a2c025d93bf6ea31506b713068175c37610ab99428498b0ff3","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"b843419ef908c9a5f485cfa99c736cc30236445ab1544d6eab51ad892f55f870"}