/// <summary> /// Keeps the IO operation. /// </summary> protected override void Implement( IRContext context, Method.Builder methodBuilder, BasicBlock.Builder builder, WriteToOutput writeToOutput) { }
/// <summary> /// Constructs a new array type lowering. /// </summary> /// <param name="builder">The parent builder.</param> /// <param name="targetAddressSpace">The target address spacce.</param> public ArrayTypeLowering( Method.Builder builder, MemoryAddressSpace targetAddressSpace) : base(builder) { TargetAddressSpace = targetAddressSpace; }
/// <summary> /// Applies the SSA construction transformation. /// </summary> protected override bool PerformTransformation(Method.Builder builder) { // Create scope and try to find SSA-convertible alloca nodes var scope = builder.CreateScope(ScopeFlags.AddAlreadyVisitedNodes); // Search for convertible allocas var allocas = new HashSet <Alloca>(); scope.ForEachValue <Alloca>(alloca => { if (!alloca.IsSimpleAllocation || alloca.AddressSpace != MemoryAddressSpace.Local || RequiresAddress(alloca)) { return; } allocas.Add(alloca); }); if (allocas.Count < 1) { return(false); } // Perform SSA construction var ssaBuilder = SSABuilder <Value> .Create(builder, scope); return(Rewriter.Rewrite(ssaBuilder, new ConstructionData(allocas))); }
/// <summary> /// Keeps the debug assertion operation. /// </summary> protected override void Implement( IRContext context, Method.Builder methodBuilder, BasicBlock.Builder builder, DebugAssertOperation debugAssert) { }
/// <summary> /// Performs the internal SSA construction transformation. /// </summary> /// <param name="builder">The parent meethod builder.</param> /// <param name="rewriter">The SSA rewriter to use.</param> /// <returns>True, if the transformation could be applied.</returns> protected bool PerformTransformation( Method.Builder builder, SSARewriter <Value, ConstructionData> rewriter) { // Search for convertible allocas var allocas = new HashSet <Alloca>(); builder.SourceBlocks.ForEachValue <Alloca>(alloca => { if (!CanConvert(builder, alloca)) { return; } allocas.Add(alloca); }); if (allocas.Count < 1) { return(false); } // Perform SSA construction var ssaBuilder = SSABuilder <Value> .Create(builder); return(rewriter.Rewrite(ssaBuilder, new ConstructionData(allocas))); }
/// <summary> /// Applies the SSA construction transformation. /// </summary> protected override bool PerformTransformation(Method.Builder builder) { // Search for convertible allocas var allocas = new HashSet <Alloca>(); builder.SourceBlocks.ForEachValue <Alloca>(alloca => { if (!alloca.IsSimpleAllocation || alloca.AddressSpace != MemoryAddressSpace.Local || RequiresAddress(alloca)) { return; } allocas.Add(alloca); }); if (allocas.Count < 1) { return(false); } // Perform SSA construction var ssaBuilder = SSABuilder <Value> .Create(builder); return(Rewriter.Rewrite(ssaBuilder, new ConstructionData(allocas))); }
/// <summary> /// Maps internal <see cref="WriteToOutput"/> values to /// <see cref="PrintF(string, void*)"/> method calls. /// </summary> protected override void Implement( IRContext context, Method.Builder methodBuilder, BasicBlock.Builder builder, WriteToOutput writeToOutput) { var location = writeToOutput.Location; // Convert to format string constant var expressionString = writeToOutput.ToPrintFExpression(); var expression = builder.CreatePrimitiveValue( location, expressionString, Encoding.ASCII); // Create an argument structure that can be passed via local memory var argumentBuilder = builder.CreateDynamicStructure( location, writeToOutput.Count); foreach (Value argument in writeToOutput.Arguments) { var converted = WriteToOutput.ConvertToPrintFArgument( builder, location, argument); argumentBuilder.Add(converted); } var argumentStructure = argumentBuilder.Seal(); // Create local alloca to store all data var alloca = builder.CreateAlloca( location, argumentStructure.Type, MemoryAddressSpace.Local); // Store structure into chunk of local memory builder.CreateStore(location, alloca, argumentStructure); // Cast alloca to the generic address space to satisfy the requirements of // of the printf method alloca = builder.CreateAddressSpaceCast( location, alloca, MemoryAddressSpace.Generic); // Create a call to the native printf var printFMethod = context.Declare(PrintFMethod, out bool _); var callBuilder = builder.CreateCall(location, printFMethod); callBuilder.Add(expression); callBuilder.Add(alloca); // Replace the write node with the call callBuilder.Seal(); builder.Remove(writeToOutput); }
/// <summary> /// Updates all return types of all affected methods. /// </summary> /// <param name="builder">The current builder.</param> protected sealed override void PrePerformTransformation(Method.Builder builder) { var typeConverter = CreateLoweringConverter(builder); // Update return type if (typeConverter.IsTypeDependent(builder.Method.ReturnType)) { builder.UpdateReturnType(typeConverter); } }
/// <summary> /// Maps internal debug assertions to <see cref="AssertFailed(string, string, /// int, string, int)"/> method calls. /// </summary> protected override void Implement( IRContext context, Method.Builder methodBuilder, BasicBlock.Builder builder, DebugAssertOperation debugAssert) { var location = debugAssert.Location; // Create a call to the debug-implementation wrapper while taking the // current source location into account var nextBlock = builder.SplitBlock(debugAssert); var innerBlock = methodBuilder.CreateBasicBlock( location, nameof(AssertFailed)); builder.CreateIfBranch( location, debugAssert.Condition, nextBlock, innerBlock); // Create a call to the assert implementation var innerBuilder = methodBuilder[innerBlock]; var assertFailed = innerBuilder.CreateCall( location, context.Declare(AssertFailedMethod, out var _)); // Move the debug assertion to this block var sourceMessage = debugAssert.Message.ResolveAs <StringValue>(); var message = innerBuilder.CreatePrimitiveValue( location, sourceMessage.String, sourceMessage.Encoding); assertFailed.Add(message); // Append source location information var debugLocation = debugAssert.GetLocationInfo(); assertFailed.Add( innerBuilder.CreatePrimitiveValue(location, debugLocation.FileName)); assertFailed.Add( innerBuilder.CreatePrimitiveValue(location, debugLocation.Line)); assertFailed.Add( innerBuilder.CreatePrimitiveValue(location, debugLocation.Method)); assertFailed.Add( innerBuilder.CreatePrimitiveValue(location, 1)); // Finish the actual assertion call and branch assertFailed.Seal(); innerBuilder.CreateBranch(location, nextBlock); // Remove the debug assertion value debugAssert.Replace(builder.CreateUndefined()); }
/// <summary> /// Applies the UCE transformation. /// </summary> protected override bool PerformTransformation(Method.Builder builder) { var scope = builder.CreateScope(); // Fold branch targets (if possible) bool updated = false; foreach (var block in scope) { // Get the conditional terminator var terminator = block.GetTerminatorAs <ConditionalBranch>(); if (terminator == null || !terminator.CanFold) { continue; } // Fold branch var blockBuilder = builder[block]; terminator.Fold(blockBuilder); updated = true; } // Check for changes if (!updated) { return(false); } // Find all unreachable blocks var updatedScope = builder.CreateScope(); foreach (var block in scope) { if (!updatedScope.Contains(block)) { // Block is unreachable -> remove all operations var blockBuilder = builder[block]; blockBuilder.Clear(); } } // Update all phi values Rewriter.Rewrite( updatedScope, builder, new PhiArgumentRemapper(updatedScope)); return(true); }
internal RewriterProcess( Rewriter <TContext, TContextProvider, TContextData, T> rewriter, Scope scope, Method.Builder builder, TContextData contextData, T data, HashSet <Value> toConvert) { Rewriter = rewriter; Scope = scope; Builder = builder; ContextData = contextData; Data = data; ToConvert = toConvert; }
/// <summary> /// Maps internal <see cref="AsAligned"/> values to a debug assertion while /// preserving the <see cref="AsAligned"/> value. /// </summary> protected override void Implement( IRContext context, Method.Builder methodBuilder, BasicBlock.Builder builder, AsAligned asAligned) { // Preserve the asAligned operation if (!EnableAssertions) { return; } // Check the actual pointer alignment var location = asAligned.Location; var comparison = builder.CreateCompare( location, builder.CreateArithmetic( location, builder.CreatePointerAsIntCast( location, asAligned.Source, IntPointerType.BasicValueType), builder.CreateConvert( location, asAligned.AlignmentInBytes, IntPointerType.BasicValueType), BinaryArithmeticKind.Rem), builder.CreatePrimitiveValue( location, IntPointerType.BasicValueType, 0L), CompareKind.Equal); // Create the debug assertion Value assert = builder.CreateDebugAssert( location, comparison, builder.CreatePrimitiveValue( location, RuntimeErrorMessages.InvalidlyAssumedPointerOrViewAlignment)); if (assert is DebugAssertOperation assertOperation) { Implement(context, methodBuilder, builder, assertOperation); } }
internal CFGBuilder( CodeGenerator codeGenerator, Method.Builder methodBuilder) { CodeGenerator = codeGenerator; Builder = methodBuilder; var mainEntry = methodBuilder.EntryBlockBuilder; EntryBlock = new Block( codeGenerator, mainEntry) { InstructionCount = 0 }; basicBlockMapping.Add(EntryBlock.BasicBlock, EntryBlock); // Create a temporary entry block to ensure that we have a single entry // block without any predecessors in all cases var internalEntryBlock = new Block( codeGenerator, methodBuilder.CreateBasicBlock( mainEntry.BasicBlock.Location, mainEntry.BasicBlock.Name)); blockMapping.Add(0, internalEntryBlock); basicBlockMapping.Add(internalEntryBlock.BasicBlock, internalEntryBlock); BuildBasicBlocks(); var visited = new HashSet <Block>(); SetupBasicBlocks(visited, internalEntryBlock, 0); WireBlocks(); // Wire the main entry block with the actual entry block mainEntry.CreateBranch( mainEntry.BasicBlock.Location, internalEntryBlock.BasicBlock); // Update control-flow structure to refresh all successor/predecessor // edge relations Blocks = methodBuilder.UpdateControlFlow(); }