/// <summary> /// Realizes an array creation. /// </summary> /// <param name="elementType">The element type.</param> private void MakeNewArray(Type elementType) { // Setup length argument var arguments = InlineList <ValueReference> .Create( Builder.CreateConvertToInt32( Location, Block.PopInt(Location, ConvertFlags.None))); var array = Builder.CreateNewArray( Location, Builder.CreateType(elementType, MemoryAddressSpace.Generic), ref arguments); // Clear array data var callArguments = InlineList <ValueReference> .Create( Builder.CreateGetViewFromArray( Location, array)); CreateCall( LocalMemory.GetClearMethod(elementType), ref callArguments); // Push array instance Block.Push(array); }
/// <summary> /// Builds an assert implementation that calls a nested fail function based on /// a boolean condition (first parameter). /// </summary> protected static Method BuildDebugAssertImplementation( IRContext irContext, MethodBase debugAssertMethod, MethodBase assertFailedMethod) { // Create a call to the debug-implementation wrapper while taking the // current source location into account var method = irContext.Declare(debugAssertMethod, out bool created); if (!created) { return(method); } var location = Location.Nowhere; using var builder = method.CreateBuilder(); method.AddFlags(MethodFlags.Inline); // Create the entry, body and exit blocks var entryBlock = builder.EntryBlockBuilder; var bodyBlock = builder.CreateBasicBlock(location); var exitBlock = builder.CreateBasicBlock(location); // Initialize the parameters var sourceParameters = debugAssertMethod.GetParameters(); var parameters = InlineList <Parameter> .Create(sourceParameters.Length); foreach (var parameter in sourceParameters) { var paramType = entryBlock.CreateType(parameter.ParameterType); parameters.Add(builder.AddParameter(paramType, parameter.Name)); } // Check condition entryBlock.CreateIfBranch( location, parameters[0], exitBlock, bodyBlock); // Fill the body var assertFailed = bodyBlock.CreateCall( location, irContext.Declare(assertFailedMethod, out var _)); for (int i = 1; i < parameters.Count; ++i) { assertFailed.Add(parameters[i]); } assertFailed.Seal(); bodyBlock.CreateBranch(location, exitBlock); // Create return exitBlock.CreateReturn(location); return(method); }
/// <summary> /// Constructs a new basic block. /// </summary> /// <param name="method">The parent method.</param> /// <param name="location">The current location.</param> /// <param name="name">The name of the block (or null).</param> internal BasicBlock(Method method, Location location, string name) : base(location) { Method = method; Name = name ?? "BB"; predecessors = InlineList <BasicBlock> .Create(2); successors = InlineList <BasicBlock> .Create(2); }
/// <summary> /// Realizes an array creation. /// </summary> /// <param name="elementType">The element type.</param> private void MakeNewArray(Type elementType) { // Redirect call to the LocalMemory class to allocate an intialized array var allocateZeroMethod = LocalMemory.GetAllocateZeroMethod(elementType); // Setup length argument var arguments = InlineList <ValueReference> .Create( Builder.CreateConvertToInt64( Location, Block.PopInt(Location, ConvertFlags.None))); CreateCall(allocateZeroMethod, ref arguments); }
/// <summary cref="Accelerator.Synchronize"/> protected unsafe override void SynchronizeInternal() { // All the events to wait on. Each event represents the completion // of all operations queued prior to said event. var streamInstances = InlineList <CLStream> .Create(4); var streamEvents = InlineList <IntPtr> .Create(4); try { ForEachChildObject <CLStream>(stream => { // Ignore disposed command queues at this point if (stream.CommandQueue == IntPtr.Zero) { return; } // Low cost IntPtr* (cl_event*) allocation IntPtr *resultEvent = stackalloc IntPtr[1]; CLException.ThrowIfFailed( CurrentAPI.EnqueueBarrierWithWaitList( stream.CommandQueue, Array.Empty <IntPtr>(), resultEvent)); // Dereference the pointer so we can store it streamEvents.Add(*resultEvent); // Keep the stream instance alive to avoid automatic disposal streamInstances.Add(stream); }); // Wait for all the events to fire, which would mean all operations // queued on an accelerator prior to synchronization have finished if (streamEvents.Count > 0) { CLException.ThrowIfFailed( CurrentAPI.WaitForEvents(streamEvents)); } } finally { // Clean up the events we made foreach (var streamEvent in streamEvents) { CLException.ThrowIfFailed( CurrentAPI.ReleaseEvent(streamEvent)); } } }
private readonly ReadOnlySpan <BasicBlock> AdjustEntrySuccessors( ReadOnlySpan <BasicBlock> currentSuccessors) { var successors = InlineList <BasicBlock> .Create(currentSuccessors.Length); foreach (var successor in currentSuccessors) { if (Node.Headers.Contains(successor, new BasicBlock.Comparer())) { successors.Add(successor); } } return(successors); }
/// <summary> /// Creates an array element address load. /// </summary> /// <param name="elementType">The element type to load.</param> /// <param name="type">The IR element type to load.</param> /// <returns>The loaded array element address.</returns> private Value CreateLoadArrayElementAddress(Type elementType, out TypeNode type) { var index = Block.PopInt(Location, ConvertFlags.None); var array = Block.Pop(); type = Builder.CreateType(elementType); var indices = InlineList <ValueReference> .Create(index); var address = Builder.CreateGetArrayElementAddress( Location, array, ref indices); return(address); }
/// <summary> /// Applies the LICM transformation to the given loop. /// </summary> /// <param name="builder">The parent method builder.</param> /// <param name="loop">The current loop.</param> /// <returns>True, if the transformation could be applied.</returns> private static bool ApplyLICM(Method.Builder builder, Loop loop) { // Initialize the current loop invariance cache var invariance = new LoopInvariance(loop); // Ensure that all blocks are in the correct order BasicBlockCollection <ReversePostOrder, Forwards> blocks = loop.ComputeOrderedBlocks(0); // Get the initial entry builder to move all values to var entry = loop.Entries[0]; var toMove = InlineList <Value> .Create(blocks.Count << 1); // Traverse all blocks in reverse post order to move all values without // violating any SSA properties foreach (var block in blocks) { if (block == entry) { continue; } foreach (Value value in block) { // Move out of the loop if this value is loop invariant if (invariance.IsLoopInvariant(value)) { toMove.Add(value); } } } // Move values var entryBuilder = builder[entry]; foreach (var valueToMove in toMove) { entryBuilder.AddFromOtherBlock(valueToMove); } return(toMove.Count > 0); }
/// <summary> /// Constructs a new loop node. /// </summary> /// <param name="parent">The parent loop.</param> /// <param name="headerBlocks">All loop headers.</param> /// <param name="breakerBlocks">All blocks that can break the loop.</param> /// <param name="backEdgeBlocks">All blocks with back edges.</param> /// <param name="members">All blocks in the scope of this loop.</param> /// <param name="entries">All entry block that jump into this loop.</param> /// <param name="exits">All exit block that this loop can jump to.</param> internal Node( Node parent, ref InlineList <BasicBlock> headerBlocks, ref InlineList <BasicBlock> breakerBlocks, ref InlineList <BasicBlock> backEdgeBlocks, HashSet <BasicBlock> members, HashSet <BasicBlock> entries, HashSet <BasicBlock> exits) { Parent = parent; parent?.AddChild(this); headerBlocks.MoveTo(ref headers); breakerBlocks.MoveTo(ref breakers); backEdgeBlocks.MoveTo(ref backEdges); nodes = members; children = InlineList <Node> .Create(1); Entries = entries.ToImmutableArray(); Exits = exits.ToImmutableArray(); }
/// <summary> /// Initializes a new mover. /// </summary> /// <param name="numBlocks">The number of blocks of the parent loop.</param> public Mover(int numBlocks) { visited = new HashSet <Value>(); toMove = InlineList <Value> .Create(numBlocks << 1); }
/// <summary> /// Applies a DCE transformation. /// </summary> protected override bool PerformTransformation(Method.Builder builder) { var blocks = builder.SourceBlocks; var toProcess = InlineList <Value> .Create(blocks.Count << 2); // Mark all terminators and their values as non dead foreach (var block in blocks) { foreach (Value value in block) { // Mark all memory values as non dead (except dead loads) if (value is MemoryValue memoryValue && memoryValue.ValueKind != ValueKind.Load) { toProcess.Add(memoryValue); } } // Register all terminator value dependencies foreach (Value node in block.Terminator) { toProcess.Add(node); } } // Mark all nodes as live var liveValues = new HashSet <Value>(); while (toProcess.Count > 0) { var current = toProcess.Pop(); if (!liveValues.Add(current)) { continue; } foreach (var node in current.Nodes) { toProcess.Add(node.Resolve()); } } // Remove all dead values bool updated = false; blocks.ForEachValue <Value>(value => { if (liveValues.Contains(value)) { return; } Debug.Assert( !(value is MemoryValue) || value.ValueKind == ValueKind.Load, "Invalid memory value"); var blockBuilder = builder[value.BasicBlock]; blockBuilder.Remove(value); updated = true; }); return(updated); }