Skip to content

Commit 8ab2ecf

Browse files
committed
Add CanCompareBits internal call for detect type fast-comparable
1 parent 1ca6181 commit 8ab2ecf

4 files changed

Lines changed: 108 additions & 72 deletions

File tree

il2cpp/Helper.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,31 @@ public static bool IsInstanceField(FieldDef fldDef)
541541
return !fldDef.IsStatic;
542542
}
543543

544+
public static bool IsBasicValueType(ElementType elemType)
545+
{
546+
switch (elemType)
547+
{
548+
case ElementType.Boolean:
549+
case ElementType.Char:
550+
case ElementType.I1:
551+
case ElementType.I2:
552+
case ElementType.I4:
553+
case ElementType.I8:
554+
case ElementType.U1:
555+
case ElementType.U2:
556+
case ElementType.U4:
557+
case ElementType.U8:
558+
case ElementType.R4:
559+
case ElementType.R8:
560+
case ElementType.I:
561+
case ElementType.U:
562+
case ElementType.Ptr:
563+
case ElementType.ByRef:
564+
return true;
565+
}
566+
return false;
567+
}
568+
544569
public static string IsBasicType(string fullName)
545570
{
546571
switch (fullName)

il2cpp/RuntimeInternals.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,24 @@ public static bool GenInternalMethod(MethodX metX, CodePrinter prt, GeneratorCon
6767

6868
return true;
6969
}
70+
else if (metName == "CanCompareBits")
71+
{
72+
var targetType = GetMethodGenType(metX, genContext);
73+
bool canCompareBits = true;
74+
foreach (var fldX in targetType.Fields)
75+
{
76+
if (!Helper.IsBasicValueType(fldX.FieldType.ElementType))
77+
{
78+
canCompareBits = false;
79+
break;
80+
}
81+
}
82+
83+
prt.AppendFormatLine("return {0};",
84+
canCompareBits ? "1" : "0");
85+
86+
return true;
87+
}
7088
else if (metName == "GetInternalTypeID")
7189
{
7290
var targetType = GetMethodGenType(metX, genContext);

il2cpp/TypeManager.cs

Lines changed: 54 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,8 +1154,8 @@ private void TryAddEquals(TypeX tyX)
11541154
Debug.Assert(metGetTyID != null);
11551155
var metRtGetTyID = rtHlpDef.FindMethod("GetInternalTypeID");
11561156
Debug.Assert(metRtGetTyID != null);
1157-
var metContainsRef = rtHlpDef.FindMethod("IsReferenceOrContainsReferences");
1158-
Debug.Assert(metContainsRef != null);
1157+
var metCanCmpBits = rtHlpDef.FindMethod("CanCompareBits");
1158+
Debug.Assert(metCanCmpBits != null);
11591159
var metFastCmp = rtHlpDef.FindMethod("FastCompareBits");
11601160
Debug.Assert(metFastCmp != null);
11611161

@@ -1185,8 +1185,8 @@ private void TryAddEquals(TypeX tyX)
11851185
insts.Add(OpCodes.Unbox_Any.ToInstruction(selfSig.ToTypeDefOrRef()));
11861186
insts.Add(OpCodes.Stloc_0.ToInstruction());
11871187

1188-
insts.Add(OpCodes.Call.ToInstruction(new MethodSpecUser(metContainsRef, new GenericInstMethodSig(selfSig))));
1189-
insts.Add(OpCodes.Brtrue.ToInstruction(labelLoopChk));
1188+
insts.Add(OpCodes.Call.ToInstruction(new MethodSpecUser(metCanCmpBits, new GenericInstMethodSig(selfSig))));
1189+
insts.Add(OpCodes.Brfalse.ToInstruction(labelLoopChk));
11901190

11911191
insts.Add(OpCodes.Ldarg_0.ToInstruction());
11921192
insts.Add(OpCodes.Ldloca.ToInstruction(body.Variables[0]));
@@ -1207,92 +1207,75 @@ private void TryAddEquals(TypeX tyX)
12071207
if (tyGenInstSig != null)
12081208
fldRef = new MemberRefUser(fldDef.Module, fldDef.Name, fldDef.FieldSig, new TypeSpecUser(tyGenInstSig));
12091209

1210-
switch (fldDef.FieldType.ElementType)
1210+
if (Helper.IsBasicValueType(fldDef.FieldType.ElementType))
12111211
{
1212-
case ElementType.Boolean:
1213-
case ElementType.Char:
1214-
case ElementType.I1:
1215-
case ElementType.I2:
1216-
case ElementType.I4:
1217-
case ElementType.I8:
1218-
case ElementType.U1:
1219-
case ElementType.U2:
1220-
case ElementType.U4:
1221-
case ElementType.U8:
1222-
case ElementType.R4:
1223-
case ElementType.R8:
1224-
case ElementType.I:
1225-
case ElementType.U:
1226-
case ElementType.Ptr:
1227-
case ElementType.ByRef:
1212+
insts.Add(OpCodes.Ldarg_0.ToInstruction());
1213+
if (fldRef != null)
1214+
insts.Add(OpCodes.Ldfld.ToInstruction(fldRef));
1215+
else
1216+
insts.Add(OpCodes.Ldfld.ToInstruction(fldDef));
1217+
insts.Add(OpCodes.Ldloc_0.ToInstruction());
1218+
if (fldRef != null)
1219+
insts.Add(OpCodes.Ldfld.ToInstruction(fldRef));
1220+
else
1221+
insts.Add(OpCodes.Ldfld.ToInstruction(fldDef));
1222+
insts.Add(OpCodes.Bne_Un.ToInstruction(labelRetFalse));
1223+
}
1224+
else
1225+
{
1226+
if (fldDef.FieldType.IsValueType ||
1227+
fldDef.FieldType.ElementType == ElementType.Var)
1228+
{
12281229
insts.Add(OpCodes.Ldarg_0.ToInstruction());
12291230
if (fldRef != null)
1230-
insts.Add(OpCodes.Ldfld.ToInstruction(fldRef));
1231+
insts.Add(OpCodes.Ldflda.ToInstruction(fldRef));
12311232
else
1232-
insts.Add(OpCodes.Ldfld.ToInstruction(fldDef));
1233+
insts.Add(OpCodes.Ldflda.ToInstruction(fldDef));
12331234
insts.Add(OpCodes.Ldloc_0.ToInstruction());
12341235
if (fldRef != null)
12351236
insts.Add(OpCodes.Ldfld.ToInstruction(fldRef));
12361237
else
12371238
insts.Add(OpCodes.Ldfld.ToInstruction(fldDef));
1238-
insts.Add(OpCodes.Bne_Un.ToInstruction(labelRetFalse));
1239-
break;
1240-
1241-
default:
1242-
if (fldDef.FieldType.IsValueType ||
1243-
fldDef.FieldType.ElementType == ElementType.Var)
1244-
{
1245-
insts.Add(OpCodes.Ldarg_0.ToInstruction());
1246-
if (fldRef != null)
1247-
insts.Add(OpCodes.Ldflda.ToInstruction(fldRef));
1248-
else
1249-
insts.Add(OpCodes.Ldflda.ToInstruction(fldDef));
1250-
insts.Add(OpCodes.Ldloc_0.ToInstruction());
1251-
if (fldRef != null)
1252-
insts.Add(OpCodes.Ldfld.ToInstruction(fldRef));
1253-
else
1254-
insts.Add(OpCodes.Ldfld.ToInstruction(fldDef));
12551239

1256-
var fldTyRef = fldDef.FieldType.ToTypeDefOrRef();
1257-
insts.Add(OpCodes.Box.ToInstruction(fldTyRef));
1240+
var fldTyRef = fldDef.FieldType.ToTypeDefOrRef();
1241+
insts.Add(OpCodes.Box.ToInstruction(fldTyRef));
12581242

1259-
insts.Add(OpCodes.Constrained.ToInstruction(fldTyRef));
1260-
insts.Add(OpCodes.Callvirt.ToInstruction(metEquals));
1261-
insts.Add(OpCodes.Brfalse.ToInstruction(labelRetFalse));
1262-
}
1243+
insts.Add(OpCodes.Constrained.ToInstruction(fldTyRef));
1244+
insts.Add(OpCodes.Callvirt.ToInstruction(metEquals));
1245+
insts.Add(OpCodes.Brfalse.ToInstruction(labelRetFalse));
1246+
}
1247+
else
1248+
{
1249+
Func<Instruction> genLdfld;
1250+
if (fldRef != null)
1251+
genLdfld = () => OpCodes.Ldfld.ToInstruction(fldRef);
12631252
else
1264-
{
1265-
Func<Instruction> genLdfld;
1266-
if (fldRef != null)
1267-
genLdfld = () => OpCodes.Ldfld.ToInstruction(fldRef);
1268-
else
1269-
genLdfld = () => OpCodes.Ldfld.ToInstruction(fldDef);
1253+
genLdfld = () => OpCodes.Ldfld.ToInstruction(fldDef);
12701254

1271-
var labelCheckRhs = OpCodes.Nop.ToInstruction();
1272-
var labelPassed = OpCodes.Nop.ToInstruction();
1255+
var labelCheckRhs = OpCodes.Nop.ToInstruction();
1256+
var labelPassed = OpCodes.Nop.ToInstruction();
12731257

1274-
insts.Add(OpCodes.Ldarg_0.ToInstruction());
1275-
insts.Add(genLdfld());
1276-
insts.Add(OpCodes.Brfalse.ToInstruction(labelCheckRhs));
1258+
insts.Add(OpCodes.Ldarg_0.ToInstruction());
1259+
insts.Add(genLdfld());
1260+
insts.Add(OpCodes.Brfalse.ToInstruction(labelCheckRhs));
12771261

1278-
insts.Add(OpCodes.Ldarg_0.ToInstruction());
1279-
insts.Add(genLdfld());
1262+
insts.Add(OpCodes.Ldarg_0.ToInstruction());
1263+
insts.Add(genLdfld());
12801264

1281-
insts.Add(OpCodes.Ldloc_0.ToInstruction());
1282-
insts.Add(genLdfld());
1265+
insts.Add(OpCodes.Ldloc_0.ToInstruction());
1266+
insts.Add(genLdfld());
12831267

1284-
insts.Add(OpCodes.Callvirt.ToInstruction(metEquals));
1285-
insts.Add(OpCodes.Brfalse.ToInstruction(labelRetFalse));
1286-
insts.Add(OpCodes.Br.ToInstruction(labelPassed));
1268+
insts.Add(OpCodes.Callvirt.ToInstruction(metEquals));
1269+
insts.Add(OpCodes.Brfalse.ToInstruction(labelRetFalse));
1270+
insts.Add(OpCodes.Br.ToInstruction(labelPassed));
12871271

1288-
insts.Add(labelCheckRhs);
1289-
insts.Add(OpCodes.Ldloc_0.ToInstruction());
1290-
insts.Add(genLdfld());
1291-
insts.Add(OpCodes.Brtrue.ToInstruction(labelRetFalse));
1272+
insts.Add(labelCheckRhs);
1273+
insts.Add(OpCodes.Ldloc_0.ToInstruction());
1274+
insts.Add(genLdfld());
1275+
insts.Add(OpCodes.Brtrue.ToInstruction(labelRetFalse));
12921276

1293-
insts.Add(labelPassed);
1294-
}
1295-
break;
1277+
insts.Add(labelPassed);
1278+
}
12961279
}
12971280
}
12981281

test/testcase/CodeGenTests.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,12 @@ public override bool Equals(object obj)
668668
}
669669
}
670670

671+
struct StruNeq2
672+
{
673+
public int fld;
674+
public StruNeq n;
675+
}
676+
671677
struct StruCmp
672678
{
673679
public int aa;
@@ -834,6 +840,10 @@ public static int Entry()
834840
if (!scmp.Equals(scmp2))
835841
return 28;
836842

843+
StruNeq2 sneq2 = new StruNeq2();
844+
if (sneq2.Equals(sneq2))
845+
return 29;
846+
837847
return 0;
838848
}
839849
}
@@ -3505,7 +3515,7 @@ private static void Main()
35053515
var tw = new Stopwatch();
35063516
tw.Start();
35073517

3508-
var result = TestContainer2.Entry();
3518+
var result = TestValueType.Entry();
35093519

35103520
tw.Stop();
35113521
Console.WriteLine("Result: {0}, Elapsed: {1}ms", result, tw.ElapsedMilliseconds);

0 commit comments

Comments
 (0)