/// <summary cref="IBackendCodeGenerator.GenerateCode(TernaryArithmeticValue)"/> public void GenerateCode(TernaryArithmeticValue value) { if (!CLInstructions.TryGetArithmeticOperation( value.Kind, value.BasicValueType.IsFloat(), out string operation)) { throw new InvalidCodeGenerationException(); } var first = Load(value.First); var second = Load(value.Second); var third = Load(value.Third); var target = Allocate(value, value.ArithmeticBasicValueType); using var statement = BeginStatement(target); statement.AppendCast(value.ArithmeticBasicValueType); statement.AppendCommand(operation); statement.BeginArguments(); statement.AppendArgument(); statement.AppendCast(value.ArithmeticBasicValueType); statement.Append(first); statement.AppendArgument(); statement.AppendCast(value.ArithmeticBasicValueType); statement.Append(second); statement.AppendArgument(); statement.AppendCast(value.ArithmeticBasicValueType); statement.Append(third); statement.EndArguments(); }
/// <summary cref="IValueVisitor.Visit(GenericAtomic)"/> public void Visit(GenericAtomic atomic) { var target = LoadIntrinsic(atomic.Target); var value = LoadIntrinsic(atomic.Value); var atomicOperation = CLInstructions.GetAtomicOperation(atomic.Kind); StatementEmitter statement; if (atomic.Kind == AtomicKind.Exchange) { var result = AllocateIntrinsic(atomic); statement = BeginStatement(result, atomicOperation); } else { statement = BeginStatement(atomicOperation); } statement.BeginArguments(); statement.AppendAtomicCast(atomic.ArithmeticBasicValueType); statement.AppendArgument(target); statement.AppendArgument(value); statement.EndArguments(); statement.Dispose(); }
public string GetVariableType(Variable variable) { switch (variable) { case PrimitiveVariable primitiveVariable: return(CLTypeGenerator.GetBasicValueType(primitiveVariable.BasicValueType)); case PointerVariable pointerType: { var addressSpacePrefix = CLInstructions.GetAddressSpacePrefix(pointerType.AddressSpace); var elementTypeName = TypeGenerator[pointerType.ElementType]; if (!string.IsNullOrEmpty(addressSpacePrefix)) { elementTypeName = addressSpacePrefix + " " + elementTypeName; } return(elementTypeName + CLInstructions.DereferenceOperation); } case ObjectVariable objectVariable: return(TypeGenerator[objectVariable.Type]); default: throw new NotSupportedException(); } }
/// <summary> /// Generate all forward type declarations. /// </summary> /// <param name="builder">The target builder.</param> public void GenerateTypeDeclarations(StringBuilder builder) { foreach (var entry in mapping) { switch (entry.Key) { case PointerType pointerType: builder.Append( CLInstructions.TypeDefStatement); builder.Append(' '); builder.Append( CLInstructions.GetAddressSpacePrefix( pointerType.AddressSpace)); builder.Append(' '); builder.Append(mapping[pointerType.ElementType]); builder.Append(CLInstructions.DereferenceOperation); builder.Append(' '); builder.Append(entry.Value); builder.AppendLine(";"); break; case StructureType _: builder.Append(entry.Value); builder.AppendLine(";"); break; } } builder.AppendLine(); }
/// <summary cref="IBackendCodeGenerator.GenerateCode(UnaryArithmeticValue)"/> public void GenerateCode(UnaryArithmeticValue value) { var argument = Load(value.Value); var target = Allocate( value, value.BasicValueType == BasicValueType.Int1 ? ArithmeticBasicValueType.UInt1 : value.ArithmeticBasicValueType); using var statement = BeginStatement(target); if (value.BasicValueType != BasicValueType.Int1) { statement.AppendCast(value.ArithmeticBasicValueType); } var operation = CLInstructions.GetArithmeticOperation( value.Kind, value.ArithmeticBasicValueType, out bool isFunction); if (isFunction) { statement.AppendCommand(operation); } statement.BeginArguments(); if (!isFunction) { statement.AppendCommand(operation); } statement.AppendCast(value.ArithmeticBasicValueType); statement.AppendArgument(argument); statement.EndArguments(); }
/// <summary cref="IValueVisitor.Visit(UnaryArithmeticValue)"/> public void Visit(UnaryArithmeticValue value) { var argument = Load(value.Value); var target = Allocate(value, value.ArithmeticBasicValueType); using (var statement = BeginStatement(target)) { statement.AppendCast(value.ArithmeticBasicValueType); var operation = CLInstructions.GetArithmeticOperation( value.Kind, value.BasicValueType.IsFloat(), out bool isFunction); if (isFunction) { statement.AppendCommand(operation); } statement.BeginArguments(); if (!isFunction) { statement.AppendCommand(operation); } statement.AppendCast(value.ArithmeticBasicValueType); statement.AppendArgument(argument); statement.EndArguments(); } }
/// <summary cref="IValueVisitor.Visit(WarpShuffle)"/> public void Visit(WarpShuffle shuffle) { if (!CLInstructions.TryGetShuffleOperation( Backend.Vendor, shuffle.Kind, out string operation)) { throw new InvalidCodeGenerationException(); } var source = Load(shuffle.Variable); var origin = Load(shuffle.Origin); var target = Allocate(shuffle); using (var statement = BeginStatement(target)) { statement.AppendCommand(operation); statement.BeginArguments(); statement.AppendArgument(source); // TODO: create a generic version that does not need this switch switch (shuffle.Kind) { case ShuffleKind.Down: case ShuffleKind.Up: statement.AppendArgument(source); break; } statement.AppendArgument(origin); statement.EndArguments(); } }
/// <summary cref="IBackendCodeGenerator.GenerateCode(AddressSpaceCast)"/> public void GenerateCode(AddressSpaceCast value) { var targetType = value.TargetType as AddressSpaceType; var source = Load(value.Value); var target = Allocate(value); bool isOperation = CLInstructions.TryGetAddressSpaceCast( value.TargetAddressSpace, out string operation); void GeneratePointerCast(StatementEmitter statement) { if (isOperation) { // There is a specific cast operation statement.AppendCommand(operation); statement.BeginArguments(); statement.Append(source); } else { statement.AppendPointerCast(TypeGenerator[targetType.ElementType]); } statement.Append(source); } using (var statement = BeginStatement(target)) { GeneratePointerCast(statement); if (isOperation) { statement.EndArguments(); } } }
/// <summary cref="IBackendCodeGenerator.GenerateCode(Barrier)"/> public void GenerateCode(Barrier barrier) { using var statement = BeginStatement( CLInstructions.GetBarrier(barrier.Kind)); statement.BeginArguments(); statement.AppendCommand( CLInstructions.GetMemoryFenceFlags(true)); statement.EndArguments(); }
/// <summary cref="IBackendCodeGenerator.GenerateCode(DynamicMemoryLengthValue)"/> public void GenerateCode(DynamicMemoryLengthValue value) { if (value.AddressSpace != MemoryAddressSpace.Shared) { throw new InvalidCodeGenerationException(); } // Resolve the name of the global variable containing the length of the // shared dynamic memory buffer. var dynamicView = value.GetFirstUseNode().ResolveAs <Alloca>(); var lengthVariableName = GetSharedMemoryAllocationLengthName(dynamicView); // Load the dynamic memory size (in bytes) from the dynamic length variable // and divide by the size in bytes of the array element. var target = Allocate(value); using var statement = BeginStatement(target); statement.AppendCast(value.Type); var operation = CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Div, value.BasicValueType.IsFloat(), out bool isFunction); if (isFunction) { statement.AppendCommand(operation); statement.BeginArguments(); } else { statement.OpenParen(); } statement.AppendCast(dynamicView.ArrayLength.Type); statement.AppendCommand(lengthVariableName); if (!isFunction) { statement.AppendCommand(operation); } statement.AppendArgument(); statement.AppendCast(value.ElementType.BasicValueType); statement.AppendConstant(value.ElementType.Size); if (isFunction) { statement.EndArguments(); } else { statement.CloseParen(); } }
/// <summary cref="ITypeNodeVisitor.Visit(ViewType)"/> public void Visit(ViewType type) { BeginStruct(type); Builder.Append('\t'); Builder.Append(CLInstructions.GetAddressSpacePrefix(type.AddressSpace)); Builder.Append(' '); Builder.Append(TypeGenerator[type.ElementType]); Builder.AppendLine("* ptr;"); Builder.AppendLine("\tint length;"); EndStruct(); }
/// <summary cref="IValueVisitor.Visit(AddressSpaceCast)"/> public void Visit(AddressSpaceCast value) { var targetType = value.TargetType as AddressSpaceType; var target = AllocatePointerType(targetType.ElementType, value.TargetAddressSpace); PointerVariable address; if (value.IsPointerCast) { address = LoadAs <PointerVariable>(value.Value); Bind(value, target); } else { var viewSource = LoadAs <ViewVariable>(value.Value); address = viewSource.Pointer; var viewTarget = new ViewVariable( value.Type as ViewType, target, viewSource.Length); Bind(value, viewTarget); } if (CLInstructions.TryGetAddressSpaceCast( value.TargetAddressSpace, out string operation)) { // There is a specific cast operation using (var statement = BeginStatement(target)) { statement.AppendCommand(operation); statement.BeginArguments(); statement.AppendArgument(address); statement.EndArguments(); } } else { // Use an unspecific generic pointer cast using (var statement = BeginStatement(target)) { statement.AppendCast( TypeGenerator[targetType.ElementType] + CLInstructions.DereferenceOperation); statement.Append(address); } } }
/// <summary cref="IBackendCodeGenerator.GenerateCode(GenericAtomic)"/> public void GenerateCode(GenericAtomic atomic) { var target = Load(atomic.Target); var value = Load(atomic.Value); var result = Allocate(atomic); var atomicOperation = CLInstructions.GetAtomicOperation(atomic.Kind); using var statement = BeginStatement(result, atomicOperation); statement.BeginArguments(); statement.AppendAtomicCast(atomic.ArithmeticBasicValueType); statement.AppendArgument(target); statement.AppendArgument(value); statement.EndArguments(); }
/// <summary cref="IBackendCodeGenerator.GenerateCode(Broadcast)"/> public void GenerateCode(Broadcast broadcast) { var source = Load(broadcast.Variable); var origin = Load(broadcast.Origin); var target = Allocate(broadcast); using var statement = BeginStatement(target); statement.AppendCommand( CLInstructions.GetBroadcastOperation( broadcast.Kind)); statement.BeginArguments(); statement.AppendArgument(source); statement.AppendArgument(origin); statement.EndArguments(); }
/// <summary> /// Defines a pointer type in OpenCL (if applicable). /// </summary> /// <param name="typeNode">The type to define.</param> private void DefinePointerType(TypeNode typeNode) { if (!(typeNode is PointerType pointerType)) { return; } Builder.Append("typedef "); Builder.Append(CLInstructions.GetAddressSpacePrefix(pointerType.AddressSpace)); Builder.Append(' '); Builder.Append(this[pointerType.ElementType]); Builder.Append("* "); Builder.Append(this[pointerType]); Builder.AppendLine(";"); }
/// <summary cref="IBackendCodeGenerator.GenerateCode(CompareValue)"/> public void GenerateCode(CompareValue value) { var left = Load(value.Left); var right = Load(value.Right); var target = Allocate(value); using var statement = BeginStatement(target); statement.AppendCast(value.CompareType); statement.AppendArgument(left); statement.AppendCommand( CLInstructions.GetCompareOperation( value.Kind)); statement.AppendCast(value.CompareType); statement.AppendArgument(right); }
/// <summary cref="IValueVisitor.Visit(CompareValue)"/> public void Visit(CompareValue value) { var left = LoadIntrinsic(value.Left); var right = LoadIntrinsic(value.Right); var targetRegister = AllocateIntrinsic(value); using (var statement = BeginStatement(targetRegister)) { statement.AppendArgument(left); statement.AppendCommand( CLInstructions.GetCompareOperation( value.Kind)); statement.AppendArgument(right); } }
/// <summary cref="IValueVisitor.Visit(BinaryArithmeticValue)"/> public void Visit(BinaryArithmeticValue value) { var left = Load(value.Left); var right = Load(value.Right); var target = Allocate(value, value.ArithmeticBasicValueType); using (var statement = BeginStatement(target)) { statement.AppendCast(value.ArithmeticBasicValueType); var operation = CLInstructions.GetArithmeticOperation( value.Kind, value.BasicValueType.IsFloat(), out bool isFunction); if (isFunction) { statement.AppendCommand(operation); statement.BeginArguments(); } else { statement.OpenParen(); } statement.AppendCast(value.ArithmeticBasicValueType); statement.AppendArgument(left); if (!isFunction) { statement.AppendCommand(operation); } statement.AppendArgument(); statement.AppendCast(value.ArithmeticBasicValueType); statement.Append(right); if (isFunction) { statement.EndArguments(); } else { statement.CloseParen(); } } }
/// <summary cref="IValueVisitor.Visit(Broadcast)"/> public void Visit(Broadcast broadcast) { var source = LoadIntrinsic(broadcast.Variable); var origin = LoadIntrinsic(broadcast.Origin); var target = AllocateIntrinsic(broadcast); using (var statement = BeginStatement(target)) { statement.AppendCommand( CLInstructions.GetBroadcastOperation( broadcast.Kind)); statement.BeginArguments(); statement.AppendArgument(source); statement.AppendArgument(origin); statement.EndArguments(); } }
/// <summary cref="IBackendCodeGenerator.GenerateCode(MemoryBarrier)"/> public void GenerateCode(MemoryBarrier barrier) { var fenceFlags = CLInstructions.GetMemoryFenceFlags(true); var command = CLInstructions.GetMemoryBarrier( barrier.Kind, out string memoryScope); using var statement = BeginStatement(command); statement.BeginArguments(); statement.AppendArgument(); statement.AppendCommand(fenceFlags); statement.AppendArgument(); statement.AppendCommand(memoryScope); statement.EndArguments(); }
/// <summary cref="IBackendCodeGenerator.GenerateCode(PredicateBarrier)"/> public void GenerateCode(PredicateBarrier barrier) { var sourcePredicate = Load(barrier.Predicate); var target = Allocate(barrier); if (!CLInstructions.TryGetPredicateBarrier( barrier.Kind, out string operation)) { throw new InvalidCodeGenerationException(); } using var statement = BeginStatement(target); statement.AppendCast(BasicValueType.Int1); statement.AppendCommand(operation); statement.BeginArguments(); statement.AppendCast(BasicValueType.Int32); statement.AppendArgument(sourcePredicate); statement.EndArguments(); }
/// <summary cref="IValueVisitor.Visit(ViewCast)"/> public void Visit(ViewCast value) { var target = AllocateView(value); var source = LoadView(value.Value); // Declare view Declare(target); using (var statement = BeginStatement(target, target.PointerFieldIndex)) { statement.AppendPointerCast(TypeGenerator[target.ElementType]); statement.Append(source); statement.AppendField(source.PointerFieldIndex); } var sourceElementSize = ABI.GetSizeOf(value.SourceElementType); var targetElementSize = ABI.GetSizeOf(value.TargetElementType); // var newLength = length * sourceElementSize / targetElementSize; using (var statement = BeginStatement(target, target.LengthFieldIndex)) { statement.OpenParen(); statement.Append(source); statement.AppendField(source.LengthFieldIndex); statement.AppendOperation( CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Mul, false, out bool _)); statement.AppendConstant(sourceElementSize); statement.CloseParen(); statement.AppendOperation( CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Div, false, out bool _)); statement.AppendConstant(targetElementSize); } }
/// <summary cref="IValueVisitor.Visit(AtomicCAS)"/> public void Visit(AtomicCAS atomicCAS) { var target = Load(atomicCAS.Target); var value = Load(atomicCAS.Value); var compare = Load(atomicCAS.CompareValue); var tempVariable = AllocateType(BasicValueType.Int1) as PrimitiveVariable; var targetVariable = Allocate(atomicCAS); using (var statement = BeginStatement(tempVariable)) { statement.AppendCommand(CLInstructions.AtomicCASOperation); statement.BeginArguments(); statement.AppendAtomicCast(atomicCAS.ArithmeticBasicValueType); statement.AppendArgument(target); statement.AppendArgumentAddressWithCast(value, $"{CLInstructions.GetAddressSpacePrefix(MemoryAddressSpace.Generic)} {CLTypeGenerator.GetBasicValueType(atomicCAS.ArithmeticBasicValueType)} {CLInstructions.DereferenceOperation}"); statement.AppendArgument(compare); statement.EndArguments(); } // The OpenCL way is not compatible with the internal CAS semantic // We should adapt to the more general way of returning a bool in the future // For now, check the result of the operation and emit an atomic load // in the case of a failure. using (var statement = BeginStatement(targetVariable)) { statement.Append(tempVariable); statement.AppendCommand(CLInstructions.SelectOperation1); statement.Append(value); statement.AppendCommand(CLInstructions.SelectOperation2); statement.AppendCommand(CLInstructions.AtomicLoadOperation); statement.BeginArguments(); statement.AppendAtomicCast(atomicCAS.ArithmeticBasicValueType); statement.AppendArgument(target); statement.EndArguments(); } }
/// <summary cref="IValueVisitor.Visit(ViewCast)"/> public void Visit(ViewCast value) { var source = LoadAs <ViewVariable>(value.Value); var pointer = source.Pointer; var length = source.Length; var sourceElementSize = ABI.GetSizeOf(value.SourceElementType); var targetElementSize = ABI.GetSizeOf(value.TargetElementType); // var newLength = length * sourceElementSize / targetElementSize; var newLength = AllocateType(BasicValueType.Int32) as PrimitiveVariable; using (var statement = BeginStatement(newLength)) { statement.OpenParen(); statement.Append(length); statement.AppendOperation( CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Mul, false, out bool _)); statement.AppendConstant(sourceElementSize); statement.CloseParen(); statement.AppendOperation( CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Div, false, out bool _)); statement.AppendConstant(targetElementSize); } var newView = new ViewVariable( value.Type as ViewType, pointer, newLength); Bind(value, newView); }
/// <summary cref="IValueVisitor.Visit(AddressSpaceCast)"/> public void Visit(AddressSpaceCast value) { var targetType = value.TargetType as AddressSpaceType; var source = Load(value.Value); var target = Allocate(value); bool isOperation = CLInstructions.TryGetAddressSpaceCast( value.TargetAddressSpace, out string operation); void GeneratePointerCast(StatementEmitter statement) { if (isOperation) { // There is a specific cast operation statement.AppendCommand(operation); statement.BeginArguments(); statement.Append(source); } else { statement.AppendPointerCast(TypeGenerator[targetType.ElementType]); } statement.Append(source); } if (value.IsPointerCast) { using (var statement = BeginStatement(target)) { GeneratePointerCast(statement); if (isOperation) { statement.EndArguments(); } } } else { var targetView = target as ViewImplementationVariable; Declare(target); // Assign pointer using (var statement = BeginStatement(target, targetView.PointerFieldIndex)) { GeneratePointerCast(statement); statement.AppendField(targetView.PointerFieldIndex); if (isOperation) { statement.EndArguments(); } } // Assign length using (var statement = BeginStatement(target, targetView.LengthFieldIndex)) { statement.Append(source); statement.AppendField(targetView.LengthFieldIndex); } } }
/// <summary cref="IValueVisitor.Visit(Barrier)"/> public void Visit(Barrier barrier) { using (var statement = BeginStatement( CLInstructions.GetBarrier(barrier.Kind))) { } }
/// <summary cref="IBackendCodeGenerator.GenerateCode(AlignTo)"/> public void GenerateCode(AlignTo value) { // Load the base view pointer var source = Load(value.Source); var target = Allocate(value); var alignmentVariable = Load(value.AlignmentInBytes); var arithmeticBasicValueType = value.Source.BasicValueType.GetArithmeticBasicValueType(true); // var baseOffset = (int)ptr & (alignmentInBytes - 1); var baseOffset = AllocateType(arithmeticBasicValueType); using (var statement = BeginStatement(baseOffset)) { statement.AppendCast(arithmeticBasicValueType); statement.AppendArgument(source); statement.AppendCommand(CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.And, isFloat: false, out bool _)); // Optimize for the case in which the alignment is a constant value if (value.TryGetAlignmentConstant(out int alignment)) { statement.AppendConstant(alignment - 1); } else { statement.AppendCommand('('); statement.AppendArgument(alignmentVariable); statement.AppendCommand(CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Sub, isFloat: false, out bool _)); statement.AppendConstant(1); statement.AppendCommand(')'); } } // if (baseOffset == 0) { 0 } else { alignment - baseOffset } var adjustment = AllocateType(arithmeticBasicValueType); using (var selectStatement = BeginStatement(adjustment)) { selectStatement.AppendArgument(baseOffset); selectStatement.AppendCommand(" == 0 ? 0 : ("); if (value.TryGetAlignmentConstant(out int alignmentConstant)) { selectStatement.AppendConstant(alignmentConstant); } else { selectStatement.AppendArgument(alignmentVariable); } selectStatement.AppendCommand(CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Sub, isFloat: false, out bool _)); selectStatement.AppendArgument(baseOffset); selectStatement.AppendCommand(')'); } // Adjust the given pointer using var command = BeginStatement(target); command.AppendCast(value.Type); command.AppendCommand('('); command.AppendCast(arithmeticBasicValueType); command.AppendArgument(source); command.AppendCommand(CLInstructions.GetArithmeticOperation( BinaryArithmeticKind.Add, isFloat: false, out bool _)); command.AppendArgument(adjustment); command.AppendCommand(')'); }