private void AddDebugInfoForAlloca(Alloca argSlot, IrFunction function, LocalVariableDeclaration localVar) { uint line = ( uint )localVar.Location.StartLine; uint col = ( uint )localVar.Location.StartColumn; // Keep compiler happy on null checks by asserting on expectations // The items were created in this file with all necessary info so // these properties should never be null. Debug.Assert(function.DISubProgram != null, "expected function with non-null DISubProgram"); Debug.Assert(function.DISubProgram.File != null, "expected function with non-null DISubProgram.File"); Debug.Assert(InstructionBuilder.InsertBlock != null, "expected Instruction builder with non-null insertion block"); DILocalVariable debugVar = Module.DIBuilder.CreateLocalVariable(scope: function.DISubProgram , name: localVar.Name , file: function.DISubProgram.File , line , type: DoubleType , alwaysPreserve: false , debugFlags: DebugInfoFlags.None ); Module.DIBuilder.InsertDeclare(storage: argSlot , varInfo: debugVar , location: new DILocation(Context, line, col, function.DISubProgram) , insertAtEnd: InstructionBuilder.InsertBlock ); }
/// <summary> /// Constructs new alloca information. /// </summary> /// <param name="index">The allocation index.</param> /// <param name="alloca">The alloca node.</param> internal AllocaInformation(int index, Alloca alloca) { Index = index; Alloca = alloca; if (alloca.IsArrayAllocation(out var length)) { ArraySize = length.Int32Value; } else if (alloca.IsSimpleAllocation) { ArraySize = 1; } else if (alloca.IsDynamicAllocation) { // Size determined at run-time. ArraySize = -1; } else { throw alloca.Location.GetNotSupportedException( ErrorMessages.NotSupportedDynamicAllocation, alloca.AllocaType); } }
public void Visit(Alloca alloca) { if (Get <Alloca>().AddressSpace != alloca.AddressSpace) { Fail(); } }
/// <summary> /// Constructs new alloca information. /// </summary> /// <param name="index">The allocation index.</param> /// <param name="alloca">The alloca node.</param> /// <param name="elementSize">The element size.</param> internal AllocaInformation( int index, Alloca alloca, int elementSize) { Index = index; Alloca = alloca; ElementSize = elementSize; var rawArrayLength = alloca.ArrayLength; var arrayLength = rawArrayLength.ResolveAs <PrimitiveValue>(); if (arrayLength != null) { ArraySize = arrayLength.Int32Value; } else { var dynamicArrayLength = rawArrayLength.ResolveAs <UndefinedValue>(); if (dynamicArrayLength != null) { ArraySize = -1; } else { throw new NotSupportedException( string.Format( ErrorMessages.NotSupportedDynamicAllocation, alloca.AddressSpace, rawArrayLength)); } } }
public override Value?Visit(BinaryOperatorExpression binaryOperator) { binaryOperator.ValidateNotNull(nameof(binaryOperator)); EmitLocation(binaryOperator); switch (binaryOperator.Op) { case BuiltInOperatorKind.Less: { var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan , binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) ).RegisterName("cmptmp"); return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType) .RegisterName("booltmp")); } case BuiltInOperatorKind.Pow: { var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power")); return(InstructionBuilder.Call(pow , binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) ).RegisterName("powtmp")); } case BuiltInOperatorKind.Add: return(InstructionBuilder.FAdd(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) ).RegisterName("addtmp")); case BuiltInOperatorKind.Subtract: return(InstructionBuilder.FSub(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) ).RegisterName("subtmp")); case BuiltInOperatorKind.Multiply: return(InstructionBuilder.FMul(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) ).RegisterName("multmp")); case BuiltInOperatorKind.Divide: return(InstructionBuilder.FDiv(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr) ).RegisterName("divtmp")); case BuiltInOperatorKind.Assign: Alloca target = LookupVariable((( VariableReferenceExpression )binaryOperator.Left).Name); Value value = binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr); InstructionBuilder.Store(value, target); return(value); default: throw new CodeGeneratorException($"ICE: Invalid binary operator {binaryOperator.Op}"); } }
/// <summary> /// Returns true if the given alloca is contained in this collection. /// </summary> /// <param name="alloca">The alloca.</param> /// <returns>True, if the given alloca is contained in this collection.</returns> public bool Contains(Alloca alloca) { foreach (var allocaInfo in Allocas) { if (allocaInfo.Alloca == alloca) { return(true); } } return(false); }
/// <summary> /// Constructs new alloca information. /// </summary> /// <param name="index">The allocation index.</param> /// <param name="alloca">The alloca node.</param> internal AllocaInformation(int index, Alloca alloca) { Index = index; Alloca = alloca; ArraySize = alloca.IsArrayAllocation(out var length) ? length.Int32Value : alloca.IsSimpleAllocation ? 1 : throw new NotSupportedException( ErrorMessages.NotSupportedDynamicAllocation); }
protected static void ConvertAlloca <TConstructionData>( SSARewriterContext <Value> context, TConstructionData data, Alloca alloca, Value initValue) where TConstructionData : IConstructionData { alloca.Assert(data.ContainsAlloca(alloca)); // Bind the init value and remove the allocation from the block context.SetValue(context.Block, alloca, initValue); data.AddConverted(alloca, new FieldRef(alloca)); context.Remove(alloca); }
/// <summary> /// Lowers alloca values into their appropriate counter parts. /// </summary> protected static void Lower( RewriterContext context, TypeLowering <TType> typeConverter, Alloca alloca) { // Compute the alloca type var newType = typeConverter.ConvertType(alloca); var newAlloca = context.Builder.CreateAlloca( alloca.Location, newType, alloca.AddressSpace); context.ReplaceAndRemove(alloca, newAlloca); }
/// <summary> /// Converts an alloca node to its initial SSA value. /// </summary> private static void Convert( SSARewriterContext <Value> context, ConstructionData data, Alloca alloca) { if (!data.ContainsAlloca(alloca)) { return; } var initValue = context.Builder.CreateNull( alloca.Location, alloca.AllocaType); ConvertAlloca(context, data, alloca, initValue); }
/// <summary> /// Converts an alloca node to its initial SSA value. /// </summary> private static void Convert <TConstructionData>( SSARewriterContext <Value> context, TConstructionData data, Alloca alloca) where TConstructionData : IConstructionData { if (!data.ContainsAlloca(alloca)) { return; } alloca.Assert(!alloca.IsSimpleAllocation); // Get the builder and the associated array length value var builder = context.Builder; var arrayLengthValue = alloca.ArrayLength.ResolveAs <PrimitiveValue>(); alloca.AssertNotNull(arrayLengthValue); int arrayLength = arrayLengthValue.Int32Value; // Create a structure with the appropriate number of fields that correspond // to the current array length var allocaTypeBuilder = builder.CreateStructureType(arrayLength + 1); // Append array length allocaTypeBuilder.Add(builder.GetPrimitiveType(BasicValueType.Int32)); // Append all virtual fields for (int i = 0; i < arrayLength; ++i) { allocaTypeBuilder.Add(alloca.AllocaType); } var allocationType = allocaTypeBuilder.Seal(); // Initialize the structure value var initValue = builder.CreateNull(alloca.Location, allocationType); // ... and set the array length initValue = builder.CreateSetField( alloca.Location, initValue, new FieldSpan(new FieldAccess(0)), builder.CreateConvertToInt32(alloca.Location, arrayLengthValue)); ConvertAlloca(context, data, alloca, initValue); }
/// <summary> /// Converts an alloca node to its initial SSA value. /// </summary> private static void Convert( SSARewriterContext <Value> context, ConstructionData data, Alloca alloca) { if (!data.ContainsAlloca(alloca)) { return; } var initValue = context.Builder.CreateNull( alloca.Location, alloca.AllocaType); context.SetValue(context.Block, alloca, initValue); data.AddConverted(alloca, new FieldRef(alloca)); context.Remove(alloca); }
private void AddDebugInfoForAlloca(Alloca argSlot, IrFunction function, LocalVariableDeclaration localVar) { uint line = ( uint )localVar.Location.StartLine; uint col = ( uint )localVar.Location.StartColumn; DILocalVariable debugVar = Module.DIBuilder.CreateLocalVariable(scope: function.DISubProgram , name: localVar.Name , file: function.DISubProgram.File , line , type: DoubleType , alwaysPreserve: false , debugFlags: DebugInfoFlags.None ); Module.DIBuilder.InsertDeclare(storage: argSlot , varInfo: debugVar , location: new DILocation(Context, line, col, function.DISubProgram) , insertAtEnd: InstructionBuilder.InsertBlock ); }
public override Value Visit(VarInExpression varInExpression) { using (NamedValues.EnterScope( )) { EmitBranchToNewBlock("VarInScope"); foreach (var localVar in varInExpression.LocalVariables) { Alloca alloca = LookupVariable(localVar.Name); Value initValue = Context.CreateConstant(0.0); if (localVar.Initializer != null) { initValue = localVar.Initializer.Accept(this); } InstructionBuilder.Store(initValue, alloca); } return(varInExpression.Body.Accept(this)); } }
public override Value?Visit(VarInExpression varInExpression) { varInExpression.ValidateNotNull(nameof(varInExpression)); using (NamedValues.EnterScope( )) { EmitBranchToNewBlock("VarInScope"); foreach (var localVar in varInExpression.LocalVariables) { Alloca alloca = LookupVariable(localVar.Name); Value initValue = Context.CreateConstant(0.0); if (localVar.Initializer != null) { initValue = localVar.Initializer.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr); } InstructionBuilder.Store(initValue, alloca); } return(varInExpression.Body.Accept(this)); } }
private void AddDebugInfoForAlloca(Alloca argSlot, IrFunction function, ParameterDeclaration param) { uint line = ( uint )param.Location.StartLine; uint col = ( uint )param.Location.StartColumn; DILocalVariable debugVar = Module.DIBuilder.CreateArgument(scope: function.DISubProgram , name: param.Name , file: function.DISubProgram.File , line , type: DoubleType , alwaysPreserve: true , debugFlags: DebugInfoFlags.None , argNo: checked (( ushort )(param.Index + 1)) // Debug index starts at 1! ); Module.DIBuilder.InsertDeclare(storage: argSlot , varInfo: debugVar , location: new DILocation(Context, line, col, function.DISubProgram) , insertAtEnd: InstructionBuilder.InsertBlock ); }
/// <summary cref="IValueVisitor.Visit(Alloca)"/> public void Visit(Alloca alloca) => CodeGenerator.GenerateCode(alloca);
/// <summary cref="IValueVisitor.Visit(Alloca)"/> public void Visit(Alloca alloca) { // Ignore alloca }
/// <summary cref="IBackendCodeGenerator.GenerateCode(Alloca)"/> public void GenerateCode(Alloca alloca) { // Ignore alloca }
/// <summary> /// Returns true if the given allocation is a simple allocation and does not /// require explicit addresses. /// </summary> protected override bool CanConvert(Method.Builder builder, Alloca alloca) => base.CanConvert(builder, alloca) && alloca.IsSimpleAllocation && !RequiresAddress(alloca);
/// <summary> /// Returns true if the given allocation is a simple allocation and does not /// require explicit addresses. /// </summary> protected override bool CanConvert(Method.Builder builder, Alloca alloca) => base.CanConvert(builder, alloca) && // Check whether we require an address or there are array accesses // that cannot be converted to statically known field index values. alloca.IsArrayAllocation(out var length) &&
/// <summary> /// Returns the alignment information determined and used for the given /// alloca. /// </summary> /// <param name="alloca"> /// The alloca to get the alignment information for. /// </param> /// <returns>The determined and used alignment in bytes.</returns> public readonly int GetAllocaAlignment(Alloca alloca) => GetAlignment( alloca, AllocaAlignments.GetInitialAlignment(alloca));
/// <summary> /// Returns true if the given allocation can be transformed. /// </summary> protected virtual bool CanConvert(Method.Builder builder, Alloca alloca) => alloca.AddressSpace == AddressSpace;
public override Value?Visit(ForInExpression forInExpression) { forInExpression.ValidateNotNull(nameof(forInExpression)); EmitLocation(forInExpression); var function = InstructionBuilder.InsertFunction; if (function is null) { throw new InternalCodeGeneratorException("ICE: Expected block attached to a function at this point"); } string varName = forInExpression.LoopVariable.Name; Alloca allocaVar = LookupVariable(varName); // Emit the start code first, without 'variable' in scope. Value?startVal; if (forInExpression.LoopVariable.Initializer != null) { startVal = forInExpression.LoopVariable.Initializer.Accept(this); if (startVal is null) { return(null); } } else { startVal = Context.CreateConstant(0.0); } // store the value into allocated location InstructionBuilder.Store(startVal, allocaVar); // Make the new basic block for the loop header. var loopBlock = function.AppendBasicBlock("loop"); // Insert an explicit fall through from the current block to the loopBlock. InstructionBuilder.Branch(loopBlock); // Start insertion in loopBlock. InstructionBuilder.PositionAtEnd(loopBlock); // Within the loop, the variable is defined equal to the PHI node. // So, push a new scope for it and any values the body might set using (NamedValues.EnterScope( )) { EmitBranchToNewBlock("ForInScope"); // Emit the body of the loop. This, like any other expression, can change the // current BB. Note that we ignore the value computed by the body, but don't // allow an error. if (forInExpression.Body.Accept(this) == null) { return(null); } Value?stepValue = forInExpression.Step.Accept(this); if (stepValue == null) { return(null); } // Compute the end condition. Value?endCondition = forInExpression.Condition.Accept(this); if (endCondition == null) { return(null); } // since the Alloca is created as a non-opaque pointer it is OK to just use the // ElementType. If full opaque pointer support was used, then the Lookup map // would need to include the type of the value allocated. var curVar = InstructionBuilder.Load(allocaVar.ElementType, allocaVar) .RegisterName(varName); var nextVar = InstructionBuilder.FAdd(curVar, stepValue) .RegisterName("nextvar"); InstructionBuilder.Store(nextVar, allocaVar); // Convert condition to a bool by comparing non-equal to 0.0. endCondition = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, endCondition, Context.CreateConstant(0.0)) .RegisterName("loopcond"); // Create the "after loop" block and insert it. var afterBlock = function.AppendBasicBlock("afterloop"); // Insert the conditional branch into the end of LoopEndBB. InstructionBuilder.Branch(endCondition, loopBlock, afterBlock); InstructionBuilder.PositionAtEnd(afterBlock); // for expression always returns 0.0 for consistency, there is no 'void' return(Context.DoubleType.GetNullValue( )); } }
/// <summary> /// Returns true if the given alloca should be converted. /// </summary> /// <param name="alloca">The alloca to check.</param> public bool ContainsAlloca(Alloca alloca) => Allocas.Contains(alloca);