-
Notifications
You must be signed in to change notification settings - Fork 2.7k
CoreFX #24343 Vector Ctor using Span #16733
Conversation
@@ -2,9 +2,11 @@ | |||
// The .NET Foundation licenses this file to you under the MIT license. | |||
// See the LICENSE file in the project root for more information. | |||
|
|||
using Internal.Runtime.CompilerServices; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be under ifdef. Otherwise, it won't build once mirrored to CoreFX used to build the portable Vector version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mirroring as in, is there going to be an attempt later sometime to single-instance the copies of shared code base between CoreClr and CoreFx repos? In that case do you want me to add #ifdef netcoreapp
in here with appropriate definition of netcoreapp
in the csproj?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This single instancing is in place already. Once this PR is merged, there will be PR with your change created in corefx automatically: https://github.com/dotnet/coreclr/blob/master/src/mscorlib/shared/README.md
We use #if !netstandard
in other similar places: https://github.com/dotnet/coreclr/blob/master/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs#L11 . I would try to stick with that unless if does not work for some reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In CoreFx, we include this file when building for netfx
and netstandard
. So I'm guessing !netstandard
isn't going to be enough.
Also - the whole new constructor should probably be under the ifdef
, so it doesn't exist in the netfx
and netstandard
versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eerhardt I again went through the csproj for CoreFx project and in there Vector.cs is included if not targetting netcoreapp
. I am thoroughly confused when it comes to nomenclature such as netstandard
vs netfx
, netcoreapp
, etc. So do you mean to say that I should put the using
statement and entire new constructor under #if (!netfx && !netstandard)
. And then the two (corefx csproj condition vs the conditional compilation in this repo) appear to conflict.
I am not able to understand how this #if
compares to the conditional compilation in the CoreFx csproj. Hence please help with what I should actually use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thoroughly confused when it comes to nomenclature such as netstandard vs netfx, netcoreapp, etc.
netcoreapp
means .NET Core
.
netfx
means .NET Framework
.
Both the .NET Core
and .NET Framework
are concrete implementations of a runtime that executes .NET code. This means you can actually run code on them. The .NET Framework
ships as part of Windows and only runs on Windows. .NET Core
runs on Windows, Linux and OSX.
You can think of netstandard
as an abstraction a developer can target that will allow their code to run on any concrete runtime: .NET Core
, .NET Framework
, Mono
, etc. netstandard
isn't a runtime itself, but it is a contract that the concrete runtimes implement.
So do you mean to say that I should put the using statement and entire new constructor under #if (!netfx && !netstandard).
I think it should actually be under #if CORECLR
(which is the DefineConstant used by coreclr to mean "this is netcoreapp
").
When building this code in dotnet/corefx for netfx
and netstandard
that DefineConstant won't be defined, so this code won't be compiled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When building this code in dotnet/corefx for netfx and netstandard that DefineConstant won't be defined, so this code won't be compiled.
Thanks @eerhardt for the explanation. Actually what confused is me that if netstandard
is the standard and netfx
is implementation then why was I supposed to use both in that #if
. And just when I thought I had reconfirmed my understanding by reading your above reply, I again got stuck at the last line in which you have mentioned netfx
and netstandard
in same line :-) . I thought netstandard
includes netfx
(standard and implementation relationship). So did you want to mention netcoreapp
instead of netstandard
...? In other words is it necessary to explicitly say netfx
when I say netstandard
... Hope I am not creating more confusion.
As for the PR, I am replacing it iwth CORECLR
as you have mentioned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iwth CORECLR as you have mentioned.
That will not compile on CoreRT and ProjectN. It would need to be more combined with more conditions there. I think #if netcoreapp
and defining netcoreapp when building S.P.CoreLib as you have proposed originally is probably the best choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkotas Thank you. I have pushed a commit that defines netcoreapp
and uses in the .cs file.
[Intrinsic] | ||
public unsafe Vector(Span<T> values) | ||
: this() | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs bounds check to verify that there is enough elements in the Span, similar to constructors that take arrays.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Add test for it to your CoreFX PR too.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working on this. I plan to model the new exception on lines of the ask in issue dotnet/corefx#25344. Whatever is done here will have to be replicated in fix for dotnet/corefx#25344. (Would like to work on that after this.)
public unsafe Vector(Span<T> values) | ||
: this() | ||
{ | ||
this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to validate that T is valid vector type here, similar how array constructors validate it?
Otherwise, I will be able to do things like:
Span<string> s = new string[] { "a", ... };
Vector<string> v = new Vector<string>(s);
that is going bad things to happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Vector definition is as follows. So will that exclude the above cases...?
public struct Vector<T> : IEquatable<Vector<T>>, IFormattable where T : struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right that will exclude my example with string, but it won't exclude other structs, e.g.:
Span<Guid> s =
Vector<Guid> v = new Vector<Guid>(s);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Earlier I missed the importance of supportedTypes
defined in the GenerationConfig.ttinclude file; which is used in the T[]
constructor already. I will use the same construct here.
BTW: Many existing methods can be optimized using Unsafe in similar way: |
Agreed, So should I take this up as part of this PR or we want to open another issue? I would like to work on that. |
Up to you. Separate PR may be better (smaller PRs are easier to get through). |
/// <summary> | ||
/// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements. | ||
/// </summary> | ||
[Intrinsic] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this attribute? Vector<T>
intrinsics are not recognized by the new-style intrinsic system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, this new constructor is just a software implementation rather than intrinsic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed...
{ | ||
if (values.Length < Count) | ||
{ | ||
throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector<T>.Count, nameof(values))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may help users if this exception told them values.Length
as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had thought about this and was ok for this instance. But there is another instance for T[]
based constructor which I reintroduced just now as per review this comment by @4creators. In that case, the statement becomes complex when an array and an index is mentioned. In that case it is not simply the number of elements in value
but the relative number of elements in value
with respect to the index.
I was trying to have consistency in the exception being thrown across the three usages and with few other exceptions in the resources file e.g.
- Arg_ElementsInSourceIsGreaterThanDestination - Number of elements in source vector is greater than the destination array
- Argument_InsufficientSpaceToCopyCollection - The specified space is not sufficient to copy the elements from this Collection.
And anyways, the user would know the number of elements that (s)he is sending...
/// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements. | ||
/// </summary> | ||
[Intrinsic] | ||
public unsafe Vector(Span<T> values) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this method still unsafe
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing it. It is left over from the earlier implementation in CoreFx code base that was on lines of constructor taking arrays, i.e. one which used pointers.
/// <summary> | ||
/// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements. | ||
/// </summary> | ||
[Intrinsic] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure the [Intrinsic]
attribute is necessary/correct here. I thought it only applied to members that the JIT needed to know about. I don't think we need JIT interception here, do we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method should have performance on par with the method that takes arrays. If the one that takes array needs to be treated as JIT intrinsic to get good performance, the one that takes Span needs to be treated as JIT intrinsic as well; and vice versa.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. I was too fast to remove the attribute and push a commit :-) Sorry. I think I will wait till the discussions are over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from this discussion there was another similar review comment by @fiigii at this place. I'm not sure whether or not to retain the [Intrinsic] attribute. Appreciate inputs please.
{ | ||
StringBuilder sbuilder = new StringBuilder(); | ||
var arrAllTypes = allTypes.ToArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need to call ToArray
here. Instead, you can just enumerate allTypes
and keep track if this is the first time through the loop.
bool firstTime = true;
foreach (Type type in allTypes)
{
if (firstTime)
{
sbuilder.Append("if (").Append(MakeTypeComparisonCondition(type));
firstTime = false;
}
else
{
sbuilder.AppendLine().Append(" || ").Append(MakeTypeComparisonCondition(type));
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done this one.
I was just following the style in the existing implementations which are using ToArray in each function call... perhaps a boolean could have been passed there instead of passing entire array and checking if the type is 0th element in the array...
I think all this can be cleaned up (although this is just a template processing code), in the other issue that I have opened dotnet/coreclr#16745
@@ -390,7 +390,7 @@ public unsafe Vector(T[] values, int index) | |||
} | |||
if (index < 0 || (values.Length - index) < Count) | |||
{ | |||
throw new IndexOutOfRangeException(); | |||
throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector<T>.Count, nameof(values))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reintroduced this as per comment here from @4creators in one of the previous commits...
dotnet/corefx#24343
dotnet/corefx#24343
@@ -34,6 +34,7 @@ | |||
<SignAssembly>true</SignAssembly> | |||
<DelaySign>true</DelaySign> | |||
<DefineConstants>$(DefineConstants);CORECLR;_USE_NLS_PLUS_TABLE;RESOURCE_SATELLITE_CONFIG;CODE_ANALYSIS_BASELINE</DefineConstants> | |||
<DefineConstants Condition="'$(TargetGroup)'=='netcoreapp' OR '$(TargetGroup)'=='uap' OR '$(TargetGroup)'=='uapaot'">$(DefineConstants);netcoreapp</DefineConstants> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can defined unconditionally here. The condition is not necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
dotnet/corefx#24343
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks @WinCPP !
OSX is failing everywhere. Not blocking on it. Merging. |
* CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
* CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
* CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
* CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
@@ -33,7 +33,7 @@ | |||
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute> | |||
<SignAssembly>true</SignAssembly> | |||
<DelaySign>true</DelaySign> | |||
<DefineConstants>$(DefineConstants);CORECLR;_USE_NLS_PLUS_TABLE;RESOURCE_SATELLITE_CONFIG;CODE_ANALYSIS_BASELINE</DefineConstants> | |||
<DefineConstants>$(DefineConstants);CORECLR;_USE_NLS_PLUS_TABLE;RESOURCE_SATELLITE_CONFIG;CODE_ANALYSIS_BASELINE;netcoreapp</DefineConstants> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for the late review.
I don't think we should define this constant. It shouldn't be necessary.
cc @jkotas
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #16733 (comment)
Basically, this code is compiled here for netcoreap
, and in CoreFX for netfx
and netstandard
. So just !netstandard
isn't going to be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for linking to the previous discussion. I had missed it. Can we instead define netcoreapp on the corefx side instead? Having an #if netcoreapp
within coreclr seems weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it only seems weird until you realize that this file is "shared" outside of coreclr.
The other way to make it work is to say:
#if !netfx and !netstandard
And then define netfx
and netstandard
in CoreFX.
But then it would seem just as weird that you'd have #if !netfx
. This is coreclr - we shouldn't have any "netfx" code in it....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then it would seem just as weird that you'd have
#if !netfx
. This is coreclr - we shouldn't have any "netfx" code in it....
Agreed. I retract my concern :)
@@ -2,9 +2,13 @@ | |||
// The .NET Foundation licenses this file to you under the MIT license. | |||
// See the LICENSE file in the project root for more information. | |||
|
|||
#if netcoreapp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we use the existing netstandard constant here (for instance just like https://github.com/dotnet/coreclr/blob/master/src/mscorlib/shared/System/MemoryExtensions.cs#L9).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed that here: #16733 (comment)
@@ -2,9 +2,13 @@ | |||
// The .NET Foundation licenses this file to you under the MIT license. | |||
// See the LICENSE file in the project root for more information. | |||
|
|||
#if netcoreapp | |||
using Internal.Runtime.CompilerServices; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: put this after all the System.* using directives
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we sort them alphabetically...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but for ones other than System (like internal), we group them separately (with system first). At least that is what I have seen (and followed) elsewhere.
So, something like:
using System.X;
using System.Y;
using System.Z;
using Internal.A;
using Internal.B;
using Internal.C;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Between, this PR is already merged and closed. So perhaps we can do all this in the optimization issue along with other clean up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course. That would be great.
|
||
#if netcoreapp | ||
/// <summary> | ||
/// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: use proper xml formatting (see
https://github.com/dotnet/coreclr/blob/master/src/mscorlib/shared/System/Buffers/OwnedMemory.cs#L16 / https://github.com/dotnet/coreclr/blob/master/src/mscorlib/shared/System/Span.cs#L90).
The span must contain at least Vector<typeparamref name="T"/>.Count elements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. But I kept it same like other instances in the file for consistency. E.g. here i.e. below code,
/// Constructs a vector from the given array. The size of the given array must be at least Vector'T.Count.
/// </summary>
[Intrinsic]
public unsafe Vector(T[] values) : this(values, 0) { }
Do we want to fix this as part of the optimization issue #16745?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be addressed separately and we can make the changes to the whole file at the same time. Good point about consistency with other places in the file.
public Vector(Span<T> values) | ||
: this() | ||
{ | ||
if ((typeof(T) == typeof(Byte)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about T == char?
Also, nit, can you use, byte/sbyte,short/long/etc, instead (to be consistent with the default formatting VS suggests)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vector doesn't support char
because it isn't a number type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vector doesn't support
char
because it isn't a number type.
Ah I see. Tyvm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type names Byte
etc. come from existing template generation code here. I did see VS suggesting me to use byte
, etc. instead, but then I didn't purposely do that cleanup as it is not really a part of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. It doesn't follow our coding guidelines, but like you mentioned, this should be fixed separately. Thanks!
* CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 * CoreFX #24343 Vector using Span dotnet/corefx#24343 Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
This PR is for new constructor for
System.Numercis.Vector
in librarySystem.Private.CoreLib
that accepts aSpan
for the issue dotnet/corefx#24343.dotnet/corefx#26499 is dependent on merging of this PR for successful compilation.
@eerhardt Kindly review.