p5
Version:
[](https://www.npmjs.com/package/p5)
131 lines (126 loc) • 4.99 kB
JavaScript
import { createBasicBlock, addEdge, pushBlock, popBlock, pushBlockForModification, recordInBasicBlock } from './ir_cfg.js';
import { getOrCreateNode } from './ir_dag.js';
import { BlockType, NodeType } from './ir_types.js';
import { c as createStrandsNode } from '../ir_builders-CMXkjMoV.js';
import { createPhiNode } from './strands_phi_utils.js';
import './strands_FES.js';
import './strands_builtins.js';
class StrandsConditional {
constructor(strandsContext, condition, branchCallback) {
// Condition must be a node...
this.branches = [{
condition,
branchCallback,
blockType: BlockType.IF_BODY
}];
this.ctx = strandsContext;
}
ElseIf(condition, branchCallback) {
this.branches.push({
condition,
branchCallback,
blockType: BlockType.IF_BODY
});
return this;
}
Else(branchCallback = () => ({})) {
this.branches.push({
condition: null,
branchCallback,
blockType: BlockType.IF_BODY
});
const phiNodes = buildConditional(this.ctx, this);
const assignments = {};
for (const [varName, phiNode] of Object.entries(phiNodes)) {
assignments[varName] = createStrandsNode(phiNode.id, phiNode.dimension, this.ctx);
}
return assignments;
}
}
function buildConditional(strandsContext, conditional) {
const cfg = strandsContext.cfg;
const branches = conditional.branches;
const mergeBlock = createBasicBlock(cfg, BlockType.MERGE);
const results = [];
const branchEndBlocks = [];
const mergedAssignments = {};
const phiBlockDependencies = {};
// Create a BRANCH block to handle phi node declarations
const branchBlock = createBasicBlock(cfg, BlockType.BRANCH);
addEdge(cfg, cfg.currentBlock, branchBlock);
addEdge(cfg, branchBlock, mergeBlock);
let previousBlock = branchBlock;
for (let i = 0; i < branches.length; i++) {
const { condition, branchCallback, blockType } = branches[i];
if (condition !== null) {
const conditionBlock = createBasicBlock(cfg, BlockType.IF_COND);
addEdge(cfg, previousBlock, conditionBlock);
pushBlock(cfg, conditionBlock);
cfg.blockConditions[conditionBlock] = condition.id;
previousBlock = conditionBlock;
popBlock(cfg);
} else {
const elseCondBlock = createBasicBlock(cfg, BlockType.ELSE_COND);
addEdge(cfg, previousBlock, elseCondBlock);
previousBlock = elseCondBlock;
}
const scopeStartBlock = createBasicBlock(cfg, BlockType.SCOPE_START);
addEdge(cfg, previousBlock, scopeStartBlock);
const branchContentBlock = createBasicBlock(cfg, blockType);
addEdge(cfg, scopeStartBlock, branchContentBlock);
pushBlock(cfg, branchContentBlock);
const branchResults = branchCallback();
for (const key in branchResults) {
branchResults[key] = strandsContext.p5.strandsNode(branchResults[key]);
}
for (const key in branchResults) {
if (!phiBlockDependencies[key]) {
phiBlockDependencies[key] = [{ value: branchResults[key], blockId: branchContentBlock }];
} else {
phiBlockDependencies[key].push({ value: branchResults[key], blockId: branchContentBlock });
}
}
results.push(branchResults);
// Create BRANCH_END block for phi assignments
const branchEndBlock = createBasicBlock(cfg, BlockType.DEFAULT);
addEdge(cfg, cfg.currentBlock, branchEndBlock);
branchEndBlocks.push(branchEndBlock);
popBlock(cfg);
const scopeEndBlock = createBasicBlock(cfg, BlockType.SCOPE_END);
addEdge(cfg, branchEndBlock, scopeEndBlock);
addEdge(cfg, scopeEndBlock, mergeBlock);
previousBlock = scopeStartBlock;
}
// Push the branch block for modification to avoid changing the ordering
pushBlockForModification(cfg, branchBlock);
for (const key in phiBlockDependencies) {
mergedAssignments[key] = createPhiNode(strandsContext, phiBlockDependencies[key], key);
}
popBlock(cfg);
for (let i = 0; i < results.length; i++) {
const branchResult = results[i];
const branchEndBlockID = branchEndBlocks[i];
pushBlockForModification(cfg, branchEndBlockID);
for (const key in branchResult) {
if (mergedAssignments[key]) {
// Create an assignment statement: phiNode = branchResult[key]
const phiNodeID = mergedAssignments[key].id;
const sourceNodeID = branchResult[key].id;
// Create an assignment operation node
// Use dependsOn[0] for phiNodeID and dependsOn[1] for sourceNodeID
// This represents: dependsOn[0] = dependsOn[1] (phiNode = sourceNode)
const assignmentNode = {
nodeType: NodeType.ASSIGNMENT,
dependsOn: [phiNodeID, sourceNodeID],
phiBlocks: []
};
const assignmentID = getOrCreateNode(strandsContext.dag, assignmentNode);
recordInBasicBlock(cfg, branchEndBlockID, assignmentID);
}
}
popBlock(cfg);
}
pushBlock(cfg, mergeBlock);
return mergedAssignments;
}
export { StrandsConditional };