Description
#1157 introduced a jit optimization to optimize typeof(X).IsValueType
to true/false. However, it seems this optimization doesn't work with inlining (same for IsAssignableFrom
), e.g.:
bool Test() => Foo(typeof(int));
bool Foo(Type t1) => t1.IsValueType;
Codegen for Test
(with Foo
inlined):
G_M31255_IG01:
4883EC28 sub rsp, 40
G_M31255_IG02:
48B9A09BC9ECF87F0000 mov rcx, 0x7FF8ECC99BA0
E82D238D5F call CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
488BC8 mov rcx, rax
48B8D8A8BEECF87F0000 mov rax, 0x7FF8ECBEA8D8
488B00 mov rax, qword ptr [rax]
3909 cmp dword ptr [rcx], ecx
G_M31255_IG03:
4883C428 add rsp, 40
48FFE0 rex.jmp rax
Expected codegen:
mov eax, 1 ;; return true
ret
the problem here is the fact that when we inline Foo we save typeof(int)
into a temp variable (GT_LCL_VAR) and then importer is not able to optimize get_IsValueType
because it expects input to be typeof(X)
(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
) rather than an unknown local, here is the IR after inlining:
# var tmp = typeof(x);
* ASG ref
+--* LCL_VAR ref V02 tmp1
\--* CALL help ref HELPER.CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
\--* CNS_INT(h) long 0x7ff8ecc99ba0 class
# return tmp.IsValueType;
* CALL void System.RuntimeType.IsValueTypeImpl
\--* LCL_VAR ref V02 tmp1
if we could, instead of saving typeof(x)
into a temp propogate it by value during inlining I believe we'd get:
* CALL void System.RuntimeType.IsValueTypeImpl
\--* CALL help ref HELPER.CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
\--* CNS_INT(h) long 0x7ff8ecc99ba0 class
Other options: early CSE ? or when I import get_IsValueType
and see LCL_VAR
arg with lvSingleDef
flag - can I quickly get its assignment node?
PS: the same issue prevents the new API Type.IsAssignableTo to be typeof(X)
friendly since it uses IsAssignableFrom
under the hood.
/cc @dotnet/jit-contrib
category:cq
theme:inlining
skill-level:expert
cost:large