/// <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); }
/// <summary> /// Applies an intrinsic implementation transformation. /// </summary> protected override bool PerformTransformation( Method.Builder builder, IntrinsicImplementationProvider <TDelegate> . IRSpecializationPhase specializationPhase) { // Check whether we are currently processing an intrinsic method var scope = builder.CreateScope(); bool applied = false; // Analyze intrinsic nodes foreach (Value value in scope.Values) { if (value is MethodCall methodCall) { applied |= specializationPhase.RegisterIntrinsic(methodCall.Target); } else { applied |= specializationPhase.RegisterIntrinsic(value); } } return(applied); }
/// <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))); }
protected bool PerformTransformation( Method.Builder builder, Rewriter <TypeLowering <TType> > rewriter) { var scope = builder.CreateScope(); var typeConverter = CreateLoweringConverter(builder, scope); // Use a static rewriter phase bool canRewriteBody = rewriter.TryBeginRewrite( scope, builder, typeConverter, out var rewriting); // Update return type if (typeConverter.IsTypeDependent(builder.Method.ReturnType)) { builder.UpdateReturnType(typeConverter); } // Update parameter types builder.UpdateParameterTypes(typeConverter); // Apply the lowering logic return(canRewriteBody && rewriting.Rewrite()); }
/// <summary cref="UnorderedTransformation.PerformTransformation(Method.Builder)"/> protected override bool PerformTransformation(Method.Builder builder) { // Detect all array values and their associated operations var scope = builder.CreateScope(); var arrays = FindConvertibleArrays(scope); // Transform dynamic arrays that requires dynamic addresses // to allocation nodes using memory operations foreach (var arrayBinding in arrays) { var array = arrayBinding.Key; var arrayType = array.Type as ArrayType; var blockBuilder = builder[array.BasicBlock]; // Allocate a new raw allocation node blockBuilder.InsertPosition = 0; var arrayLength = blockBuilder.CreatePrimitiveValue(arrayType.Length); var rawArray = blockBuilder.CreateAlloca( arrayLength, arrayType.ElementType, MemoryAddressSpace.Local); blockBuilder.Remove(array); // Convert all operations to memory operations foreach (var operation in arrayBinding.Value) { var currentBlockBuilder = builder[operation.BasicBlock]; currentBlockBuilder.SetupInsertPosition(operation); var elementAddress = currentBlockBuilder.CreateLoadElementAddress(rawArray, operation.Index); if (operation is SetElement setElement) { currentBlockBuilder.CreateStore(elementAddress, setElement.Value); operation.Replace(rawArray); } else { var load = currentBlockBuilder.CreateLoad(elementAddress); operation.Replace(load); } currentBlockBuilder.Remove(operation); } } return(arrays.Count > 0); }
/// <summary cref="UnorderedTransformation.PerformTransformation(Method.Builder)"/> protected override bool PerformTransformation(Method.Builder builder) { var scope = builder.CreateScope(); var cfg = scope.CreateCFG(); bool result = false; var mergedNodes = new HashSet <CFG.Node>(); foreach (var cfgNode in cfg) { if (mergedNodes.Contains(cfgNode)) { continue; } result |= MergeChain(builder, cfgNode, mergedNodes); } return(result); }
/// <summary cref="UnorderedTransformation.PerformTransformation(Method.Builder)"/> protected override bool PerformTransformation(Method.Builder builder) { var scope = builder.CreateScope(); var liveValues = FindLiveValues(scope); bool result = false; foreach (Value value in scope.Values) { if (liveValues.Contains(value)) { continue; } Debug.Assert(!(value is MemoryValue), "Invalid memory value"); var blockBuilder = builder[value.BasicBlock]; blockBuilder.Remove(value); result = true; } return(result); }
/// <summary cref="UnorderedTransformation.PerformTransformation(Method.Builder)"/> protected override bool PerformTransformation(Method.Builder builder) { var scope = builder.CreateScope(); bool result = false; foreach (var block in scope) { var blockBuilder = builder[block]; foreach (var valueEntry in block) { if (valueEntry.Value is AddressSpaceCast cast && IsRedundant(cast)) { cast.Replace(cast.Value); blockBuilder.Remove(cast); result = true; } } } return(result); }
/// <summary cref="UnorderedTransformation.PerformTransformation(Method.Builder)"/> protected override bool PerformTransformation(Method.Builder builder) { // Create scope and try to find SSA-convertible alloca nodes var scope = builder.CreateScope(ScopeFlags.AddAlreadyVisitedNodes); var allocas = FindConvertibleAllocas(scope); if (allocas.Count < 1) { return(false); } // Perform SSA construction var cfg = scope.CreateCFG(); var ssaBuilder = SSABuilder <Value> .Create(builder, cfg); var convertedNodes = new Dictionary <Value, FieldRef>(); foreach (var block in scope) { if (!ssaBuilder.ProcessAndSeal(block)) { continue; } var blockBuilder = builder[block]; foreach (var valueEntry in blockBuilder) { // Move insert position to the current instruction blockBuilder.SetupInsertPosition(valueEntry); Value value = valueEntry; switch (value) { case Alloca alloca: if (allocas.Contains(alloca)) { Debug.Assert(!alloca.IsArrayAllocation, "Unsupported dynamic allocation"); ssaBuilder.SetValue( block, alloca, blockBuilder.CreateNull(alloca.AllocaType)); convertedNodes.Add(alloca, new FieldRef(alloca)); blockBuilder.Remove(alloca); } break; case Load load: if (convertedNodes.TryGetValue(load.Source, out FieldRef loadRef)) { var ssaValue = ssaBuilder.GetValue(block, loadRef.Source); ssaValue = blockBuilder.CreateGetField(ssaValue, loadRef.AccessChain); load.Replace(ssaValue); blockBuilder.Remove(load); } else if (!load.Uses.HasAny) { blockBuilder.Remove(load); } break; case Store store: if (convertedNodes.TryGetValue(store.Target, out FieldRef storeRef)) { var ssaValue = ssaBuilder.GetValue(block, storeRef.Source); ssaValue = blockBuilder.CreateSetField( ssaValue, storeRef.AccessChain, store.Value); ssaBuilder.SetValue(block, storeRef.Source, ssaValue); blockBuilder.Remove(store); } break; case LoadFieldAddress loadFieldAddress: if (convertedNodes.TryGetValue(loadFieldAddress.Source, out FieldRef fieldRef)) { convertedNodes.Add( loadFieldAddress, fieldRef.Access(loadFieldAddress.FieldIndex)); blockBuilder.Remove(loadFieldAddress); } break; case AddressSpaceCast addressSpaceCast: if (convertedNodes.TryGetValue(addressSpaceCast.Value, out FieldRef castRef)) { convertedNodes.Add( addressSpaceCast, castRef); blockBuilder.Remove(addressSpaceCast); } break; } } } return(true); }
/// <summary cref="UnorderedTransformation.PerformTransformation(Method.Builder)"/> protected override bool PerformTransformation(Method.Builder builder) { var scope = builder.CreateScope(); var cfg = scope.CreateCFG(); var ifInfos = IfInfos.Create(cfg); bool converted = false; foreach (IfInfo ifInfo in ifInfos) { // Check for an extremely simple if block to convert if (!ifInfo.IsSimpleIf()) { continue; } // Check size constraints int ifBlockSize = ifInfo.IfBlock.Count; int elseBlockSize = ifInfo.ElseBlock.Count; int blockSizeDiff = IntrinsicMath.Abs(ifBlockSize - elseBlockSize); if (ifBlockSize > MaxBlockSize || elseBlockSize > MaxBlockSize || blockSizeDiff > DefaultMaxSizeDifference) { continue; } // Check for side effects if (ifInfo.HasSideEffects()) { continue; } // Convert the current if block var variableInfo = ifInfo.ResolveVariableInfo(); var blockBuilder = builder[ifInfo.EntryBlock]; blockBuilder.MergeBlock(ifInfo.IfBlock); blockBuilder.MergeBlock(ifInfo.ElseBlock); blockBuilder.MergeBlock(ifInfo.ExitBlock); // Convert all phi values var condition = ifInfo.Condition; foreach (var variableEntry in variableInfo) { var variable = variableEntry.Value; blockBuilder.SetupInsertPosition(variableEntry.Key); var predicate = blockBuilder.CreatePredicate( condition, variable.TrueValue, variable.FalseValue); // Replace the phi node variableEntry.Key.Replace(predicate); blockBuilder.Remove(variableEntry.Key); } converted = true; } return(converted); }
/// <summary> /// Applies a DCE transformation. /// </summary> protected override bool PerformTransformation(Method.Builder builder) { var scope = builder.CreateScope(); var toProcess = new Stack <Value>(); // Mark all terminators and their values as non dead scope.ForEachTerminator <TerminatorValue>(terminator => { foreach (var node in terminator.Nodes) { toProcess.Push(node); } }); // Mark all memory values as non dead (except dead loads) scope.ForEachValue <MemoryValue>(value => { if (value.ValueKind != ValueKind.Load) { toProcess.Push(value); } }); // Mark all calls as non dead scope.ForEachValue <MethodCall>(call => toProcess.Push(call)); // 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.Push(node.Resolve()); } } // Remove all dead values bool updated = false; scope.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); }