But it adds .tail prefix before every callvirt instruction and this breaks some JIT optimizations. E.g. generic type specialization 'if(typeof(T) == typeof(...))' breaks, I had to dig into compiler source code to find out that it doesn't add .tail before ctors, used a struct wrapper and called a method in the struct ctor to avoid .tail prefix, but it adds its own overhead.
Also, most simple tail calls are rewritten by a compiler to a loop, but if you look at the generated IL, there are multiple temp variables, locals, needless assignments. Maybe JIT is able to eliminate those, or maybe not... In C# I could get IL that reflects what I write, without surprises.