@SuppressWarnings("unchecked")
	private void createBlockGraph(CodeBlock modelMSub, TaskMonitor monitor)
			throws CancelledException {

		g = new DirectedGraph();
		vertexAttributes = g.vertexAttributes();
		entAttribute = (IntegerAttribute<Vertex>) vertexAttributes.createAttribute(ENTRY_POINT_TAG,
			attributeType);

		Vertex fromVertex, targetVertex;
		Address targetAddr;

		// make list of entry points
		Address[] entPts = modelMSub.getStartAddresses();
		LinkedList<Address> entryAddrList = new LinkedList<>();
		for (Address entPt : entPts) {
			entryAddrList.addLast(entPt);
		}

		// get the simple blocks contained in the model-M subroutine
		CodeBlockModel blockModel = modelM.getBasicBlockModel();
		CodeBlockIterator blockIter = blockModel.getCodeBlocksContaining(modelMSub, monitor);

		// iterate over the blocks
		while (blockIter.hasNext()) {

			CodeBlock block = blockIter.next();

			// Get or create vertex (reuse a vertex if previously created for this block)
			Vertex[] verticesOfBlock = g.getVerticesHavingReferent(block);
			fromVertex = (verticesOfBlock.length != 0) ? verticesOfBlock[0] : new Vertex(block);

			// add vertex to graph and set entry point attribute if it's associated with an entry point
			g.add(fromVertex);
			Address[] entryPts = block.getStartAddresses();
			for (int i = 0; i < entryPts.length; i++) {
				if (entryAddrList.contains(entryPts[i])) {
					entAttribute.setValue(fromVertex, i); // tag block with entry point index offset
					break;
				}
			}

			// connect children of fromVertex
			CodeBlockReferenceIterator destinations = block.getDestinations(monitor);
			while (destinations.hasNext()) {
				CodeBlockReference destinationReference = destinations.next();

				// we don't want to flow out of fromVertex if call or terminal flow type
				//  This is unnecessary if calls don't end blocks in the simple block model
				//  But, since some implementations of block models allow for this, it's better
				//  to be safe than sorry!
				FlowType flowType = destinationReference.getFlowType(); // flow type from fromVertex to child
				if (flowType.isCall() || flowType.isTerminal()) {
					continue;
				}

				targetAddr = destinationReference.getDestinationAddress();
				CodeBlock targetBlock = blockModel.getFirstCodeBlockContaining(targetAddr, monitor);
				if (targetBlock != null) {
					entryPts = targetBlock.getStartAddresses();
					boolean connect = true;
					for (Address entryPt : entryPts) {
						if (entryAddrList.contains(entryPt)) { // don't connect to an existing entry point
							connect = false;
						}
					}
					if (connect) {
						verticesOfBlock = g.getVerticesHavingReferent(targetBlock);
						targetVertex = (verticesOfBlock.length != 0) ? verticesOfBlock[0]
								: new Vertex(targetBlock);
						Edge edge = new Edge(fromVertex, targetVertex);
						g.add(edge);
					}
				}
			}
		}
	}
Generate a graph of a Model-M subroutine.  This graph will facilitate the
Model-P algorythm as performed in the partitionGraph() method.

@param modelMSub a valid Model-M subroutine block.
@param monitor task monitor which allows user to cancel operation.
@throws CancelledException if the monitor cancels the operation.
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/block/PartitionCodeSubModel.java