Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Expand const keyword usage to enable compile time enforcement of const semantics #744

Open
2 of 5 tasks
4creators opened this issue Jul 15, 2017 · 9 comments
Open
2 of 5 tasks

Comments

@4creators
Copy link

4creators commented Jul 15, 2017

Compile-time const parameter syntax

Rationale

In many situations it is necessary to create objects, parametrize types (generics) or execute functions using parameters passed as compile time constants. It directly relates to x86 and other ISA requirements for instruction encoding where one of the operands has to be compile time constant (in jitted code the definition of compile time constant is somehow blurred by the fact that one can in theory supply runtime value before jitting given method which could be used as a compile time constant for the lifetime of jitted code and later replaced with another runtime value used for rejitting the very same method).

Situations in which this syntax would be required are i.e.:

Vector<byte> v = new Vector<byte>(buffer, 0);
var z = v << 3;

// operator << is defined as follows
public static operator Vector<T> <<(Vector<T> x, int n);

where contract requirement is that int n passed to shift operator is a "compile time constant" or in some cases, depending on underlying ISA instruction, it could be an int variable. This situation arises in several cases when intrinsics based on Vector class could be used with some group of SIMD instructions i.e. PSLLD/PSLLQ xmm1, imm8 for SSE2 ISA extensions. For all sets of SSE and SSSE instructions there are no instructions equivalent to PSLLD/PSLLQ xmm1, imm8 which would accept xmm/m128 second operand but such instructions exists in AVX/AVX2/AVX512. C# syntax does not provide any methods to prevent passing non-constant int to shift operator in the above example.

Proposal

Extend usage of const keyword to method/constructor/property parameters while maintaining it's semantics - enforcement of compile time constant usage. const keyword should participate in overload resolution allowing for overloads containing identical types of parameters at the same position in the method signature differing only by const keyword

Examples

// Jit selects PSLLD xmm1, imm8 opcode
public static operator Vector<T> <<(Vector<T> x, const int n); 

// Jit selects VPSLLD xmm1, xmm2/m128 opcode
public static operator Vector<T> <<(Vector<T> x, int n); 

Vector<uint> v = new Vector<uint>(buffer, 0);

int x = 1;
int y = MethodCall();
var z = v << x;    // compile time error unless constexpr syntax supported ->Unknown6656 comment
var z = v << y;    // compile time error
var z = v << 1;    // OK

Alternatives

Usage of different indirect methods which do not fit very well to overall C# semantics. For details see issue # 16835 in corefx repo.

@svick
Copy link
Contributor

svick commented Jul 15, 2017

I think the two proposals (const method parameters and value generic parameters) are very different and should be separate issues, even if the use cases are related.

Especially considering that const parameters would probably just involve emitting an attribute and producing an error, while value generic parameters would likely be much more complicated.

@4creators
Copy link
Author

@svick Agree - i will edit my proposal and create a new one to reflect your remarks.

@Unknown6656
Copy link
Contributor

Unknown6656 commented Jul 15, 2017

slightly related: dotnet/roslyn#15079
which is about a C# equivalent of constexpr, meaning that in your example above the lines

int x = 1;
var z = v << x;

would be accepted, as x would be replaced by 1 in the second line, as the compiler recognises, that the value of x is deterministic and constant (in at least the first two lines).


The issue dotnet/roslyn#15079 is in fact an 'umbrella' issue for the following ones:
dotnet/roslyn#12238
dotnet/roslyn#14665
dotnet/roslyn#10506
dotnet/roslyn#11259
dotnet/roslyn#9627
dotnet/coreclr#3633
#504
(and a few more)

@4creators
Copy link
Author

Similar proposal but with scoped runtime const semantics is ref readonly feature which is currently in implementation phase.

@tannergooding
Copy link
Member

tannergooding commented Jul 15, 2017

IMO, the C# language should not be concerned with whether the underlying hardware requires (or is most performant) when passed a constant/literal value.

For some cases, the IL doesn't even expose a way for the compiler to guarantee a value is constant. The IL is almost entirely stack based (except for a few scenarios where it can take immediate operands). The shl instruction, for example, expects both value and shiftAmount to be on the stack and does not expose a version that takes an immediate value.

That being said, there is a proposal on CoreFX/CoreCLR to expose hardware intrinsics directly (https://github.com/dotnet/coreclr/issues/6906#issuecomment-307164495). If that were to happen, then the runtime would need to either:

  • Fail at runtime if the user did not pass in an immediate
    -or-
  • Provide some magic attribute the compiler recognized and enforced (RequiresLiteral or something to that affect).

If the latter were to happen, I believe it would be a compiler feature, rather than a language feature.

@svick
Copy link
Contributor

svick commented Jul 15, 2017

@tannergooding I think the most straightforward implementation of this proposal would be pretty much that magic attribute, except it would be exposed at the C# level as the const keyword.

The compiler would have to ensure that it produces IL that's recognized by the CLR as "constant", but that's probably mostly already the case. I don't see why the lack of support for immediate values in IL should be a problem.

If the latter were to happen, I believe it would be a compiler feature, rather than a language feature.

Why? I thought the C# language/compiler is generally against attributes that affect how the C# compiler behaves. (And I'm talking about C# attributes, not IL attributes.)

@tannergooding
Copy link
Member

@svick, What I'm trying to envision here is:

  • What benefits would a general feature like this provide
  • Where would it be used outside of a code path where a parameter was passed down to a hardware intrinsic function

I'm having trouble envisioning either of these. From my viewpoint, const support has three primary uses:

  1. Being able to cut-out various copy requirements when working pointers/references (ref readonly)
  2. Being able to ensure that a value qualifies for constexpr
  3. Being able to work with hardware intrinsics where immediate values are required

The first is already being provided for ref types. Further support for pointer types could be done (for better interop support, etc), but that could also be provided with attributes and an analyzer given that the code is 'unsafe' and will not be common in public surface area.

The second is likely its own feature with its own validation. I imagine parameter const would be implicit based on a method or field level const or constexpr declaration.

The third is a very limited scenario (the primary scenario raised by this) and is likely not worth a language keyword (IMO). Providing a magic attribute that compiles down to a modreq is likely sufficient and the few cases where it is required, users can manually list it.

@svick
Copy link
Contributor

svick commented Jul 15, 2017

@tannergooding Yeah, I think you're right. This feature has very limited use cases, so it makes sense to limit its cost and impact. And making it an attribute instead of a keyword does achieve that.

@4creators
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants