break;
}
- if (op1->AsOp()->gtOp2->IsIntCnsFitsInI32() &&
- FitsIn<INT32>(cns + op1->AsOp()->gtOp2->AsIntCon()->gtIconVal))
+ if (op1->AsOp()->gtOp2->IsIntCnsFitsInI32())
{
- cns += op1->AsOp()->gtOp2->AsIntCon()->gtIconVal;
- op1 = op1->AsOp()->gtOp1;
+ GenTreeIntCon* addConst = op1->AsOp()->gtOp2->AsIntCon();
- goto AGAIN;
- }
+ if (addConst->ImmedValCanBeFolded(compiler, GT_ADD) && FitsIn<INT32>(cns + addConst->IconValue()))
+ {
+ cns += addConst->IconValue();
+ op1 = op1->AsOp()->gtOp1;
+ goto AGAIN;
+ }
+ }
break;
case GT_MUL:
break;
}
- if (op2->AsOp()->gtOp2->IsIntCnsFitsInI32() &&
- FitsIn<INT32>(cns + op2->AsOp()->gtOp2->AsIntCon()->gtIconVal))
+ if (op2->AsOp()->gtOp2->IsIntCnsFitsInI32())
{
- cns += op2->AsOp()->gtOp2->AsIntCon()->gtIconVal;
- op2 = op2->AsOp()->gtOp1;
+ GenTreeIntCon* addConst = op2->AsOp()->gtOp2->AsIntCon();
+
+ if (addConst->ImmedValCanBeFolded(compiler, GT_ADD) && FitsIn<INT32>(cns + addConst->IconValue()))
+ {
+ cns += addConst->IconValue();
+ op2 = op2->AsOp()->gtOp1;
+ }
goto AGAIN;
}
-
break;
case GT_MUL:
op1 = op1->gtEffectiveVal();
// Now we look for op1's with non-overflow GT_ADDs [of constants]
- while ((op1->gtOper == GT_ADD) && (!op1->gtOverflow()) && (!constOnly || (op1->AsOp()->gtOp2->IsCnsIntOrI())))
+ while (op1->OperIs(GT_ADD) && !op1->gtOverflow())
{
+ GenTreeOp* add = op1->AsOp();
+ GenTree* addOp1 = add->gtGetOp1();
+ GenTree* addOp2 = add->gtGetOp2();
+
+ if (constOnly && (!addOp2->IsCnsIntOrI() || !addOp2->AsIntCon()->ImmedValCanBeFolded(this, GT_ADD)))
+ {
+ break;
+ }
+
// mark it with GTF_ADDRMODE_NO_CSE
- op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
+ add->gtFlags |= GTF_ADDRMODE_NO_CSE;
if (!constOnly)
{
- op2 = op1->AsOp()->gtOp2;
+ op2 = addOp2;
}
- op1 = op1->AsOp()->gtOp1;
+ op1 = addOp1;
// If op1 is a GT_NOP then swap op1 and op2.
// (Why? Also, presumably op2 is not a GT_NOP in this case?)
- if (op1->gtOper == GT_NOP)
+ if (op1->OperIs(GT_NOP))
{
- GenTree* tmp;
-
- tmp = op1;
- op1 = op2;
- op2 = tmp;
+ std::swap(op1, op2);
}
- if (!constOnly && ((op2 == base) || (!op2->IsCnsIntOrI())))
+ if (!constOnly && ((op2 == base) || !op2->IsCnsIntOrI() || !op2->AsIntCon()->ImmedValCanBeFolded(this, GT_ADD)))
{
break;
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+.assembly HandlesInAddrModes { }
+.assembly extern System.Runtime { }
+
+.class HandlesInAddrModes
+{
+ .method public static int32 Main()
+ {
+ .entrypoint
+
+ ldc.i4 0
+ conv.i
+ call char .this::Problem(native int)
+ ldc.i4 120 // 'x'
+ ceq
+ ldc.i4 100
+ mul
+ ret
+ }
+
+ .method private static char Problem(native int idx) noinlining
+ {
+ ldstr "xyz"
+ call instance char& modreq([System.Runtime]System.Runtime.InteropServices.InAttribute) string::GetPinnableReference()
+ ldarg idx
+ ldc.i4 2
+ conv.i
+ mul
+ add
+ ldind.u2
+ ret
+ }
+}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk.IL">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>PdbOnly</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).il" />
+ </ItemGroup>
+</Project>
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
public class FoldingExtendsInt32On64BitHostsTest
{
// On 64 bit hosts, 32 bit constants are stored as 64 bit signed values.