{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/11475","repository_url":"https://api.github.com/repos/dotnet/roslyn","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/11475/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/11475/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/11475/events","html_url":"https://github.com/dotnet/roslyn/issues/11475","id":156075180,"number":11475,"title":"Proposal: Compiler intrinsics","user":{"login":"tmat","id":41759,"avatar_url":"https://avatars.githubusercontent.com/u/41759?v=3","gravatar_id":"","url":"https://api.github.com/users/tmat","html_url":"https://github.com/tmat","followers_url":"https://api.github.com/users/tmat/followers","following_url":"https://api.github.com/users/tmat/following{/other_user}","gists_url":"https://api.github.com/users/tmat/gists{/gist_id}","starred_url":"https://api.github.com/users/tmat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tmat/subscriptions","organizations_url":"https://api.github.com/users/tmat/orgs","repos_url":"https://api.github.com/users/tmat/repos","events_url":"https://api.github.com/users/tmat/events{/privacy}","received_events_url":"https://api.github.com/users/tmat/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-05-21T00:54:47Z","updated_at":"2016-05-21T01:27:28Z","closed_at":null,"body":"# Background\r\n\r\nC# and VB languages aren't able to express certain IL instructions and patterns (e.g. ldtoken, calli, ldftn, etc.). That's ok, it's not the job of a language to express all possible patterns of the underlying VM. However, there are scenarios where these patterns are very useful. In these cases users are currently left with options that are painful to use, break debugging, break IDE experience (refactorings etc.) are hard to maintain. These include various forms of IL rewriting, writing code in plain IL and compiling it to a separate assembly, runtime code generation, etc. \r\n\r\nA few examples of such scenarios:\r\n- the CLR's tool for generating native interop stubs (MCG) would greatly benefit from the ability to emit IL instructions like ```calli```, ```ldftn```, etc. \r\n- ```infoof``` feature could be implemented as a library method if it was possible to directly emit ```ldtoken``` instruction\r\n- @joeduffy's implementation of slices currently needs some [IL helpers]( https://github.com/joeduffy/slice.net/blob/master/src/PtrUtils.il) compiled into a separate library.\r\n\r\nIf only Roslyn compilers could provide a way to emit these commonly needed IL patterns without changing the language specification ...\r\n\r\n# Proposal\r\nA _compiler intrinsic_ is a ```static extern``` method declared in compilation source code that is marked with ```CompilerIntrinsicAttribute``` and its name is well-known to the compiler.\r\n\r\nEach intrinsic provides a way to emit certain IL instruction or pattern that otherwise can’t be expressed in the C# language, using *existing syntax* and *preserving standard evaluation stack behavior*. These intrinsics can thus be used in the middle of ordinary statements and expressions with no adverse effect on debugging, EnC, IntelliSense, refactorings, etc. Intrinsics have well-known names that determine the IL instruction pattern to emit and imply a signature pattern. The specific signature declared by the user along with the call-site arguments provide the compiler all the information it needs to emit the requested IL. \r\n\r\nThe declaration of an intrinsic won't be emitted to metadata. It can't be, as the type loader would not be able to load the containing type due to missing implementation for the intrinsics.\r\n\r\nAdditional constraints might need to be enforced on intrinsic call-sites and corresponding errors reported during binding phase. One of the constraints is that some arguments passed to the call-site of an intrinsic method must evaluate to a compile-time constant. This constraint is needed when the generated IL depends on the value of such arguments (e.g. calling convention in ```LoadFunctionPointer``` intrinsic below).\r\n \r\nThe compiler can define any number of intrinsics and add more as needed. The following example demonstrates what would be possible. The exact set of intrinsics to introduce is up for a debate. \r\n\r\nNote that the following code compiles and works in the current version of C# compiler and IDE services. It just doesn't compile to the desired IL.\r\n\r\n```C#\r\nnamespace System.Runtime.CompilerServices\r\n{\r\n    [AttributeUsage(AttributeTargets.Method)]\r\n    internal class CompilerIntrinsicAttribute : Attribute { }\r\n}\r\n \r\nclass Program\r\n{\r\n    [CompilerIntrinsic]\r\n    static unsafe extern int CallIndirect(\r\n         CallingConvention unmanagedConvention, int arg0, void* functionPointer);\r\n \r\n    [CompilerIntrinsic]\r\n    static unsafe extern int CallIndirect(\r\n         CallingConventions managedConvention, string arg0, bool arg1, void* functionPointer);\r\n \r\n    [CompilerIntrinsic]\r\n    static unsafe extern int TailCallIndirect(\r\n          CallingConvention unmanagedConvention, string arg0, bool arg1, void* functionPointer);\r\n \r\n    [CompilerIntrinsic]\r\n    static unsafe extern void TailCallIndirect(\r\n          CallingConventions managedConvention, void* functionPointer);\r\n \r\n    [CompilerIntrinsic]\r\n    static unsafe extern void* LoadFunctionPointer(Func<string, bool, int> target);\r\n \r\n    [CompilerIntrinsic]\r\n    static unsafe extern void* LoadFunctionPointer(Action target);\r\n \r\n    [CompilerIntrinsic]\r\n    static unsafe extern void* LoadVirtualFunctionPointer(Func<int, int> target);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern RuntimeTypeHandle LoadTypeToken<T>();\r\n \r\n    [CompilerIntrinsic]\r\n    static extern RuntimeMethodHandle LoadMethodToken(Func<int, int> target);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern RuntimeMethodHandle LoadGetterToken<T>(T targetProperty);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern RuntimeMethodHandle LoadSetterToken<T>(T targetProperty);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern RuntimeFieldHandle LoadFieldToken<T>(T targetField);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern int LoadTypeTokenInt32<T>();\r\n \r\n    [CompilerIntrinsic]\r\n    static extern int LoadMethodTokenInt32(Func<int, int> target);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern int LoadFieldTokenInt32<T>(T targetField);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern int LoadGetterTokenInt32<T>(T targetProperty);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern int LoadSetterTokenInt32<T>(T targetProperty);\r\n \r\n    [CompilerIntrinsic]\r\n    static extern string LoadMvidString();\r\n \r\n \r\n    abstract class C<T>\r\n    {\r\n        public C(int a) { }\r\n        public abstract int F(int a);\r\n    }\r\n \r\n    public void F() { }\r\n    public static T G<T>(T a) => default(T);\r\n    public static int H(string s, bool b) => 1;\r\n \r\n    public static string fld;\r\n \r\n    public static int P { get; set; }\r\n \r\n    private unsafe void* GetAddressOfNativeFunction() => null;\r\n \r\n    void IL()\r\n    {\r\n        // ldvirtftn C<string>.F\r\n        // pop\r\n        unsafe { LoadVirtualFunctionPointer(default(C<string>).F); }\r\n \r\n        // ldstr \"str\"\r\n        // ldc.i4.1\r\n        // ldftn H\r\n        // calli int(string, bool)\r\n        // box\r\n        // call Console.WriteLine(object)\r\n        unsafe \r\n        {\r\n            Console.WriteLine(CallIndirect(\r\n               CallingConventions.Standard, \"str\", true, LoadFunctionPointer(H))); \r\n         }\r\n \r\n        // ldc.i4 123\r\n        // call GetAddressOfNativeFunction()\r\n        // calli int(int)\r\n        // box\r\n        // call Console.WriteLine(object)\r\n        unsafe \r\n        {\r\n            Console.WriteLine(CallIndirect(\r\n               CallingConvention.FastCall, 123, GetAddressOfNativeFunction())); \r\n        }\r\n \r\n        LoadTypeToken<Program>();                 // ldtoken Program\r\n        LoadMethodToken(default(C<bool>).F);      // ldtoken C<bool>.F\r\n        LoadMethodToken(G<int>);                  // ldtoken G<int>\r\n        LoadFieldToken(fld);                      // ldtoken fld\r\n        LoadGetterToken(P);                       // ldtoken get_P\r\n        LoadSetterToken(P);                       // ldtoken set_P\r\n \r\n        LoadTypeTokenInt32<Program>();            // ldc.i4 <token of Program>\r\n        LoadMethodTokenInt32(default(C<bool>).F); // ldc.i4 <token of C<bool>.F>\r\n        LoadFieldTokenInt32(fld);                 // ldc.i4 <token of fld>\r\n        LoadGetterTokenInt32(P);                  // ldc.i4 <token of get_P>\r\n        LoadSetterTokenInt32(P);                  // ldc.i4 <token of set_P>\r\n        LoadMvidString();                         // ldstr \"<containing module mvid>\"\r\n \r\n        // ldarg.0\r\n        // ldftn F\r\n        // tail.calli void()\r\n        unsafe\r\n        {\r\n           TailCallIndirect(CallingConventions.HasThis, LoadFunctionPointer(F)); \r\n         }\r\n    }\r\n}\r\n```\r\n\r\n# Local Instrinsics\r\n\r\nProvided that C# 7 allows _local functions_ to be declared as ```extern``` and custom attributes applied to them it would be possible to declare intrinsics \"inline\", for example:\r\n\r\n```C#\r\nunsafe void IL()\r\n{\r\n    [CompilerIntrinsic]\r\n    extern int CallIndirect(\r\n         CallingConvention unmanagedConvention, int arg0, void* functionPointer);\r\n \r\n    Console.WriteLine(\r\n         CallIndirect(CallingConvention.FastCall, 123, GetAddressOfNativeFunction()));\r\n}\r\n\r\n```\r\n\r\n```"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/220751091","html_url":"https://github.com/dotnet/roslyn/issues/11475#issuecomment-220751091","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/11475","id":220751091,"user":{"login":"mjsabby","id":1930559,"avatar_url":"https://avatars.githubusercontent.com/u/1930559?v=3","gravatar_id":"","url":"https://api.github.com/users/mjsabby","html_url":"https://github.com/mjsabby","followers_url":"https://api.github.com/users/mjsabby/followers","following_url":"https://api.github.com/users/mjsabby/following{/other_user}","gists_url":"https://api.github.com/users/mjsabby/gists{/gist_id}","starred_url":"https://api.github.com/users/mjsabby/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mjsabby/subscriptions","organizations_url":"https://api.github.com/users/mjsabby/orgs","repos_url":"https://api.github.com/users/mjsabby/repos","events_url":"https://api.github.com/users/mjsabby/events{/privacy}","received_events_url":"https://api.github.com/users/mjsabby/received_events","type":"User","site_admin":false},"created_at":"2016-05-21T01:27:28Z","updated_at":"2016-05-21T01:27:28Z","body":"How do we feel about not taking a dependency on CoreFX defining the CompilerIntrinsic attribute, instead allowing the compiler to make a decision about which attribute to look for via an argument, or (and this may be heavy handed) making a keyword out of this.\r\n\r\nI'd hate for this feature to be gated on your need to upgrade the compiler AND your standard library."}}
{"actor":{"display_login":"mjsabby"}}