From 5f12506e065db8b538a0f5df1991b152fec21a61 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 12:49:13 -0800 Subject: [PATCH 01/28] Fixed improper peephole zero-extension removal when cdq/cdqe/cwde instructions are involved --- src/coreclr/jit/emitinl.h | 6 +++ src/coreclr/jit/emitpub.h | 1 + src/coreclr/jit/emitxarch.cpp | 10 +++++ src/tests/JIT/opt/Regressions/Regression6.cs | 37 +++++++++++++++++++ .../JIT/opt/Regressions/Regression6.csproj | 12 ++++++ 5 files changed, 66 insertions(+) create mode 100644 src/tests/JIT/opt/Regressions/Regression6.cs create mode 100644 src/tests/JIT/opt/Regressions/Regression6.csproj diff --git a/src/coreclr/jit/emitinl.h b/src/coreclr/jit/emitinl.h index 125c1ddd0fbd3f..fe179e395e8ed6 100644 --- a/src/coreclr/jit/emitinl.h +++ b/src/coreclr/jit/emitinl.h @@ -33,6 +33,12 @@ inline bool emitter::instrHasImplicitRegPairDest(instruction ins) return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv); } +/* static */ +inline bool emitter::instrHasImplicitRegSingleDest(instruction ins) +{ + return (ins == INS_cdq || ins == INS_cwde); +} + // Because we don't actually have support for encoding these 3-op // multiplies we fake it with special opcodes. Make sure they are // contiguous. diff --git a/src/coreclr/jit/emitpub.h b/src/coreclr/jit/emitpub.h index 0133fb19f0212d..265254aea09690 100644 --- a/src/coreclr/jit/emitpub.h +++ b/src/coreclr/jit/emitpub.h @@ -102,6 +102,7 @@ UNATIVE_OFFSET emitDataSize(); static bool instrIs3opImul(instruction ins); static bool instrIsExtendedReg3opImul(instruction ins); static bool instrHasImplicitRegPairDest(instruction ins); +static bool instrHasImplicitRegSingleDest(instruction ins); static void check3opImulValues(); static regNumber inst3opImulReg(instruction ins); static instruction inst3opImulForReg(regNumber reg); diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index b08aa2fdab39d9..c20e61ac96e73f 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -526,6 +526,16 @@ bool emitter::AreUpper32BitsZero(regNumber reg) } } + // This is a special case for cdq/cdqe/cwde. + // They always write to and sign-extend RAX. + if (instrHasImplicitRegSingleDest(id->idIns())) + { + if (reg == REG_RAX) + { + return PEEPHOLE_ABORT; + } + } + switch (id->idInsFmt()) { case IF_RWR: diff --git a/src/tests/JIT/opt/Regressions/Regression6.cs b/src/tests/JIT/opt/Regressions/Regression6.cs new file mode 100644 index 00000000000000..62d9e96bb7948d --- /dev/null +++ b/src/tests/JIT/opt/Regressions/Regression6.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Generated by Fuzzlyn v1.5 on 2023-02-26 16:54:59 +// Run on X64 Linux +// Seed: 15812590312404596729 +// Reduced from 254.7 KiB to 0.5 KiB in 00:04:05 +// Debug: Outputs 18446744069414584320 +// Release: Outputs 0 +public class C0 +{ + public ulong F2; + public C0(ulong f2) + { + F2 = f2; + } +} + +public class Program +{ + public static ushort s_2; + public static C0 s_7; + public static void Main() + { + for (int vr0 = 0; vr0 < 2; vr0++) + { + s_7 = M5(); + ulong vr1 = s_7.F2; + System.Console.WriteLine(vr1); + } + } + + public static C0 M5() + { + return new C0(~(ulong)(4294967295U & (-(1 % (s_2-- | 1))))); + } +} \ No newline at end of file diff --git a/src/tests/JIT/opt/Regressions/Regression6.csproj b/src/tests/JIT/opt/Regressions/Regression6.csproj new file mode 100644 index 00000000000000..f3e1cbd44b4041 --- /dev/null +++ b/src/tests/JIT/opt/Regressions/Regression6.csproj @@ -0,0 +1,12 @@ + + + Exe + + + None + True + + + + + From cf0bdf2a2903fd442b200ca09fa3a0361195e458 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 12:53:47 -0800 Subject: [PATCH 02/28] Update regression test --- src/tests/JIT/opt/Regressions/Regression6.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tests/JIT/opt/Regressions/Regression6.cs b/src/tests/JIT/opt/Regressions/Regression6.cs index 62d9e96bb7948d..582b8cd5eb3acf 100644 --- a/src/tests/JIT/opt/Regressions/Regression6.cs +++ b/src/tests/JIT/opt/Regressions/Regression6.cs @@ -4,9 +4,6 @@ // Generated by Fuzzlyn v1.5 on 2023-02-26 16:54:59 // Run on X64 Linux // Seed: 15812590312404596729 -// Reduced from 254.7 KiB to 0.5 KiB in 00:04:05 -// Debug: Outputs 18446744069414584320 -// Release: Outputs 0 public class C0 { public ulong F2; @@ -20,14 +17,20 @@ public class Program { public static ushort s_2; public static C0 s_7; - public static void Main() + public static int Main() { + ulong result = 1234; for (int vr0 = 0; vr0 < 2; vr0++) { s_7 = M5(); ulong vr1 = s_7.F2; - System.Console.WriteLine(vr1); + result = vr1; } + + if (result != 18446744069414584320) + return 0; + + return 100; } public static C0 M5() From 697dfdc6e4372436d60f89da52aaf7be6e642e79 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 12:54:48 -0800 Subject: [PATCH 03/28] Formatting --- src/coreclr/jit/emitinl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitinl.h b/src/coreclr/jit/emitinl.h index fe179e395e8ed6..7863db230d19dc 100644 --- a/src/coreclr/jit/emitinl.h +++ b/src/coreclr/jit/emitinl.h @@ -36,7 +36,7 @@ inline bool emitter::instrHasImplicitRegPairDest(instruction ins) /* static */ inline bool emitter::instrHasImplicitRegSingleDest(instruction ins) { - return (ins == INS_cdq || ins == INS_cwde); + return (ins == INS_cdq) || (ins == INS_cwde); } // Because we don't actually have support for encoding these 3-op From f78c28d0a945f817328335fe518cb019549df374 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 13:12:06 -0800 Subject: [PATCH 04/28] Handle cdq differently --- src/coreclr/jit/emitxarch.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index c20e61ac96e73f..8457d3132beb8b 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -526,13 +526,30 @@ bool emitter::AreUpper32BitsZero(regNumber reg) } } - // This is a special case for cdq/cdqe/cwde. + // This is a special case for cdq/cwde. // They always write to and sign-extend RAX. if (instrHasImplicitRegSingleDest(id->idIns())) { - if (reg == REG_RAX) + switch (id->idIns()) { - return PEEPHOLE_ABORT; + case INS_cwde: + { + if (reg == REG_RAX) + { + return PEEPHOLE_ABORT; + } + } + + case INS_cdq: + { + if (reg == REG_RDX) + { + return PEEPHOLE_ABORT; + } + } + + default: + break; } } From b6467cb8a1fce7cebbbda63295b3209cc4a97c4d Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 13:12:21 -0800 Subject: [PATCH 05/28] Handle cdq differently --- src/coreclr/jit/emitxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 8457d3132beb8b..a91c1fa8853b2b 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -527,7 +527,7 @@ bool emitter::AreUpper32BitsZero(regNumber reg) } // This is a special case for cdq/cwde. - // They always write to and sign-extend RAX. + // They always write to and sign-extend. if (instrHasImplicitRegSingleDest(id->idIns())) { switch (id->idIns()) From 334fc46370ace79daeca235eab92964ab765cf4b Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 13:13:30 -0800 Subject: [PATCH 06/28] Handle cdq differently --- src/coreclr/jit/emitxarch.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index a91c1fa8853b2b..590b320636bdee 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -538,6 +538,7 @@ bool emitter::AreUpper32BitsZero(regNumber reg) { return PEEPHOLE_ABORT; } + break; } case INS_cdq: @@ -546,6 +547,7 @@ bool emitter::AreUpper32BitsZero(regNumber reg) { return PEEPHOLE_ABORT; } + break; } default: From 47eb762a4acd4c9b132a6e0de8616f9d0716f153 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 17:53:57 -0800 Subject: [PATCH 07/28] Initial commit to eliminate redundant 'cmp' instructions --- src/coreclr/jit/codegenxarch.cpp | 10 ++- src/coreclr/jit/emitxarch.cpp | 110 +++++++++++++++++++++++++++++++ src/coreclr/jit/emitxarch.h | 2 + 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index c6abbde39ed537..428aea8b9e3e78 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -6747,7 +6747,15 @@ void CodeGen::genCompareInt(GenTree* treeNode) targetType = TYP_BOOL; // just a tip for inst_SETCC that movzx is not needed } } - emit->emitInsBinary(ins, emitTypeSize(type), op1, op2); + + emitAttr size = emitTypeSize(type); + bool canSkip = compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && !op1->isUsedFromMemory() && + !op2->isUsedFromMemory() && emit->IsRedundantCmp(size, op1->GetRegNum(), op2->GetRegNum()); + + if (!canSkip) + { + emit->emitInsBinary(ins, size, op1, op2); + } } // Are we evaluating this into a register? diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index b08aa2fdab39d9..ffac87294f7107 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -677,6 +677,116 @@ bool emitter::AreUpper32BitsSignExtended(regNumber reg) } #endif // TARGET_64BIT +bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) +{ + // Only allow GPRs. + // If not a valid register, then return false. + if (!genIsValidIntReg(reg1)) + return false; + + if (!genIsValidIntReg(reg2)) + return false; + + // Only consider if safe + // + if (!emitCanPeepholeLastIns()) + { + return false; + } + + bool result = false; + + //instInfo + emitPeepholeIterateLastInstrs([&](instrDesc* id) { + switch (id->idIns()) + { + case INS_seta: + case INS_setae: + case INS_setb: + case INS_setbe: + case INS_sete: + case INS_setg: + case INS_setge: + case INS_setl: + case INS_setle: + case INS_setne: + case INS_setno: + case INS_setnp: + case INS_setns: + case INS_seto: + case INS_setp: + case INS_sets: + + case INS_tail_i_jmp: + case INS_i_jmp: + case INS_jmp: + case INS_jo: + case INS_jno: + case INS_jb: + case INS_jae: + case INS_je: + case INS_jne: + case INS_jbe: + case INS_ja: + case INS_js: + case INS_jns: + case INS_jp: + case INS_jnp: + case INS_jl: + case INS_jge: + case INS_jle: + case INS_jg: + + case INS_l_jmp: + case INS_l_jo: + case INS_l_jno: + case INS_l_jb: + case INS_l_jae: + case INS_l_je: + case INS_l_jne: + case INS_l_jbe: + case INS_l_ja: + case INS_l_js: + case INS_l_jns: + case INS_l_jp: + case INS_l_jnp: + case INS_l_jl: + case INS_l_jge: + case INS_l_jle: + case INS_l_jg: + return PEEPHOLE_CONTINUE; + + case INS_mov: + case INS_movsx: + case INS_movzx: + { + if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) + { + return PEEPHOLE_ABORT; + } + + return PEEPHOLE_CONTINUE; + } + + case INS_cmp: + { + if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) + { + result = (size == id->idOpSize()); + return PEEPHOLE_ABORT; + } + + return PEEPHOLE_ABORT; + } + + default: + return PEEPHOLE_ABORT; + } + }); + + return result; +} + //------------------------------------------------------------------------ // AreFlagsSetToZeroCmp: Checks if the previous instruction set the SZ, and optionally OC, flags to // the same values as if there were a compare to 0 diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h index b6759b9ae1a934..69b0e78ff4c4fb 100644 --- a/src/coreclr/jit/emitxarch.h +++ b/src/coreclr/jit/emitxarch.h @@ -132,6 +132,8 @@ bool AreUpper32BitsZero(regNumber reg); bool AreUpper32BitsSignExtended(regNumber reg); #endif // TARGET_64BIT +bool IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2); + bool AreFlagsSetToZeroCmp(regNumber reg, emitAttr opSize, GenCondition cond); bool AreFlagsSetForSignJumpOpt(regNumber reg, emitAttr opSize, GenCondition cond); From ef8688b110151de79295b585a1d5b302cfe83eb4 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 17:59:40 -0800 Subject: [PATCH 08/28] Take into account cmpxchg --- src/coreclr/jit/emitinl.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitinl.h b/src/coreclr/jit/emitinl.h index 7863db230d19dc..a2e760f075afb0 100644 --- a/src/coreclr/jit/emitinl.h +++ b/src/coreclr/jit/emitinl.h @@ -30,12 +30,15 @@ inline bool emitter::instrIsExtendedReg3opImul(instruction ins) /* static */ inline bool emitter::instrHasImplicitRegPairDest(instruction ins) { - return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv); + // These instructions use RAX and RDX. + return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv) || (ins == INS_cmpxchg); } /* static */ inline bool emitter::instrHasImplicitRegSingleDest(instruction ins) { + // 'cdq' uses RDX. + // 'cwde' uses RAX. return (ins == INS_cdq) || (ins == INS_cwde); } From 2184607cca7264a737361b229d59b29dbd469bd0 Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 18:06:30 -0800 Subject: [PATCH 09/28] Take into account cmpxchg --- src/coreclr/jit/emitinl.h | 10 +++++----- src/coreclr/jit/emitxarch.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/emitinl.h b/src/coreclr/jit/emitinl.h index a2e760f075afb0..b4ec3f4eb36cad 100644 --- a/src/coreclr/jit/emitinl.h +++ b/src/coreclr/jit/emitinl.h @@ -30,16 +30,16 @@ inline bool emitter::instrIsExtendedReg3opImul(instruction ins) /* static */ inline bool emitter::instrHasImplicitRegPairDest(instruction ins) { - // These instructions use RAX and RDX. - return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv) || (ins == INS_cmpxchg); + // These instructions write to RAX and RDX. + return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv); } /* static */ inline bool emitter::instrHasImplicitRegSingleDest(instruction ins) { - // 'cdq' uses RDX. - // 'cwde' uses RAX. - return (ins == INS_cdq) || (ins == INS_cwde); + // 'cdq' writes to RDX. + // 'cwde' and 'cmpxchg' writes to RAX. + return (ins == INS_cdq) || (ins == INS_cwde) || (ins == INS_cmpxchg); } // Because we don't actually have support for encoding these 3-op diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 590b320636bdee..e010f68defd3b1 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -526,13 +526,13 @@ bool emitter::AreUpper32BitsZero(regNumber reg) } } - // This is a special case for cdq/cwde. - // They always write to and sign-extend. + // This is a special case for cdq/cwde/cmpxchg. if (instrHasImplicitRegSingleDest(id->idIns())) { switch (id->idIns()) { case INS_cwde: + case INS_cmpxchg: { if (reg == REG_RAX) { From 25ac9697e0bcced7d7b0382f6cb0040a2ff4fa6e Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 27 Feb 2023 19:32:51 -0800 Subject: [PATCH 10/28] Feedback --- src/tests/JIT/opt/Regressions/Regression6.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/JIT/opt/Regressions/Regression6.cs b/src/tests/JIT/opt/Regressions/Regression6.cs index 582b8cd5eb3acf..f19dd733cc3a0f 100644 --- a/src/tests/JIT/opt/Regressions/Regression6.cs +++ b/src/tests/JIT/opt/Regressions/Regression6.cs @@ -4,6 +4,7 @@ // Generated by Fuzzlyn v1.5 on 2023-02-26 16:54:59 // Run on X64 Linux // Seed: 15812590312404596729 +// Note: This test is to make sure we do not remove a 'mov eax, eax' instruction if the trailing instructions like 'cwde' modifies 'eax'. public class C0 { public ulong F2; From 2cc3541b5175f08d1ffed29ba324b0020c78ed87 Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 28 Feb 2023 16:28:42 -0800 Subject: [PATCH 11/28] Temporarily disable cmp opt if we encounter a mov --- src/coreclr/jit/codegenxarch.cpp | 3 ++- src/coreclr/jit/emitxarch.cpp | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 428aea8b9e3e78..80e48877892aa1 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -6750,7 +6750,8 @@ void CodeGen::genCompareInt(GenTree* treeNode) emitAttr size = emitTypeSize(type); bool canSkip = compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && !op1->isUsedFromMemory() && - !op2->isUsedFromMemory() && emit->IsRedundantCmp(size, op1->GetRegNum(), op2->GetRegNum()); + (targetReg != REG_NA) && !op2->isUsedFromMemory() && + emit->IsRedundantCmp(size, op1->GetRegNum(), op2->GetRegNum()); if (!canSkip) { diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index ffac87294f7107..bf686b4fb0851d 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -756,17 +756,17 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) case INS_l_jg: return PEEPHOLE_CONTINUE; - case INS_mov: - case INS_movsx: - case INS_movzx: - { - if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) - { - return PEEPHOLE_ABORT; - } - - return PEEPHOLE_CONTINUE; - } + //case INS_mov: + //case INS_movsx: + //case INS_movzx: + //{ + // if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) + // { + // return PEEPHOLE_ABORT; + // } + + // return PEEPHOLE_CONTINUE; + //} case INS_cmp: { From 3218581168fd810b9fc45112b507fc04e8146ffd Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 1 Mar 2023 14:47:52 -0800 Subject: [PATCH 12/28] Allow checking for mov --- src/coreclr/jit/emitxarch.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index bf686b4fb0851d..ffac87294f7107 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -756,17 +756,17 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) case INS_l_jg: return PEEPHOLE_CONTINUE; - //case INS_mov: - //case INS_movsx: - //case INS_movzx: - //{ - // if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) - // { - // return PEEPHOLE_ABORT; - // } - - // return PEEPHOLE_CONTINUE; - //} + case INS_mov: + case INS_movsx: + case INS_movzx: + { + if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) + { + return PEEPHOLE_ABORT; + } + + return PEEPHOLE_CONTINUE; + } case INS_cmp: { From e5e2599d5af6ed9982adfdec23ae400dc5109912 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 1 Mar 2023 15:03:16 -0800 Subject: [PATCH 13/28] Allow regardless of targetReg --- src/coreclr/jit/codegenxarch.cpp | 3 +- src/coreclr/jit/emit.h | 4 + src/coreclr/jit/emitxarch.cpp | 164 ++++++++++++++++--------------- 3 files changed, 92 insertions(+), 79 deletions(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index a6f222af52bcba..ae07c6f6dd12ed 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -6731,8 +6731,7 @@ void CodeGen::genCompareInt(GenTree* treeNode) emitAttr size = emitTypeSize(type); bool canSkip = compiler->opts.OptimizationEnabled() && (ins == INS_cmp) && !op1->isUsedFromMemory() && - (targetReg != REG_NA) && !op2->isUsedFromMemory() && - emit->IsRedundantCmp(size, op1->GetRegNum(), op2->GetRegNum()); + !op2->isUsedFromMemory() && emit->IsRedundantCmp(size, op1->GetRegNum(), op2->GetRegNum()); if (!canSkip) { diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 413b25eb37e0d8..dc4841d5c4f952 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -2079,6 +2079,10 @@ class emitter void emitHandleMemOp(GenTreeIndir* indir, instrDesc* id, insFormat fmt, instruction ins); void spillIntArgRegsToShadowSlots(); +#ifdef TARGET_XARCH + bool emitIsInstructionWritingToReg(instrDesc* id, regNumber reg); +#endif // TARGET_XARCH + /************************************************************************/ /* The logic that creates and keeps track of instruction groups */ /************************************************************************/ diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index ffac87294f7107..67a7d5bfb98b29 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -696,93 +696,103 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) bool result = false; - //instInfo - emitPeepholeIterateLastInstrs([&](instrDesc* id) { - switch (id->idIns()) - { - case INS_seta: - case INS_setae: - case INS_setb: - case INS_setbe: - case INS_sete: - case INS_setg: - case INS_setge: - case INS_setl: - case INS_setle: - case INS_setne: - case INS_setno: - case INS_setnp: - case INS_setns: - case INS_seto: - case INS_setp: - case INS_sets: - - case INS_tail_i_jmp: - case INS_i_jmp: - case INS_jmp: - case INS_jo: - case INS_jno: - case INS_jb: - case INS_jae: - case INS_je: - case INS_jne: - case INS_jbe: - case INS_ja: - case INS_js: - case INS_jns: - case INS_jp: - case INS_jnp: - case INS_jl: - case INS_jge: - case INS_jle: - case INS_jg: - - case INS_l_jmp: - case INS_l_jo: - case INS_l_jno: - case INS_l_jb: - case INS_l_jae: - case INS_l_je: - case INS_l_jne: - case INS_l_jbe: - case INS_l_ja: - case INS_l_js: - case INS_l_jns: - case INS_l_jp: - case INS_l_jnp: - case INS_l_jl: - case INS_l_jge: - case INS_l_jle: - case INS_l_jg: - return PEEPHOLE_CONTINUE; + // instInfo + emitPeepholeIterateLastInstrs( + [&](instrDesc* id) + { + switch (id->idIns()) + { + case INS_seta: + case INS_setae: + case INS_setb: + case INS_setbe: + case INS_sete: + case INS_setg: + case INS_setge: + case INS_setl: + case INS_setle: + case INS_setne: + case INS_setno: + case INS_setnp: + case INS_setns: + case INS_seto: + case INS_setp: + case INS_sets: + { + if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) + { + return PEEPHOLE_ABORT; + } - case INS_mov: - case INS_movsx: - case INS_movzx: - { - if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) + return PEEPHOLE_CONTINUE; + } + + case INS_mov: + case INS_movsx: + case INS_movzx: { - return PEEPHOLE_ABORT; + if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) + { + return PEEPHOLE_ABORT; + } + + return PEEPHOLE_CONTINUE; } - return PEEPHOLE_CONTINUE; - } + case INS_tail_i_jmp: + case INS_i_jmp: + case INS_jmp: + case INS_jo: + case INS_jno: + case INS_jb: + case INS_jae: + case INS_je: + case INS_jne: + case INS_jbe: + case INS_ja: + case INS_js: + case INS_jns: + case INS_jp: + case INS_jnp: + case INS_jl: + case INS_jge: + case INS_jle: + case INS_jg: + + case INS_l_jmp: + case INS_l_jo: + case INS_l_jno: + case INS_l_jb: + case INS_l_jae: + case INS_l_je: + case INS_l_jne: + case INS_l_jbe: + case INS_l_ja: + case INS_l_js: + case INS_l_jns: + case INS_l_jp: + case INS_l_jnp: + case INS_l_jl: + case INS_l_jge: + case INS_l_jle: + case INS_l_jg: + return PEEPHOLE_CONTINUE; - case INS_cmp: - { - if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) + case INS_cmp: { - result = (size == id->idOpSize()); + if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) + { + result = (size == id->idOpSize()); + return PEEPHOLE_ABORT; + } + return PEEPHOLE_ABORT; } - return PEEPHOLE_ABORT; + default: + return PEEPHOLE_ABORT; } - - default: - return PEEPHOLE_ABORT; - } - }); + }); return result; } From baee67fc0446994490ebe561e1d9f4fb49ba6320 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 1 Mar 2023 15:03:50 -0800 Subject: [PATCH 14/28] Allow regardless of targetReg --- src/coreclr/jit/emitxarch.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 67a7d5bfb98b29..ef8f9d75ee3bb4 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -677,6 +677,12 @@ bool emitter::AreUpper32BitsSignExtended(regNumber reg) } #endif // TARGET_64BIT +bool emitter::emitIsInstructionWritingToReg(instrDesc* id, regNumber reg) +{ + // TODO: + return false; +} + bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) { // Only allow GPRs. From 03e4f8beebd45ed5171a6e3b0e54ade4b32cb9e1 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 1 Mar 2023 15:29:33 -0800 Subject: [PATCH 15/28] Checking if an instruction resets a flag. --- src/coreclr/jit/emit.h | 1 + src/coreclr/jit/emitxarch.cpp | 227 ++++++++++++++++++++++------------ 2 files changed, 149 insertions(+), 79 deletions(-) diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index dc4841d5c4f952..2cee0f4c88fb28 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -2081,6 +2081,7 @@ class emitter #ifdef TARGET_XARCH bool emitIsInstructionWritingToReg(instrDesc* id, regNumber reg); + bool emitIsInstructionResettingFlags(instrDesc* id); #endif // TARGET_XARCH /************************************************************************/ diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index c0df3e2f5cc43b..0d2968819f5bc0 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -706,9 +706,144 @@ bool emitter::AreUpper32BitsSignExtended(regNumber reg) } #endif // TARGET_64BIT + +bool emitter::emitIsInstructionResettingFlags(instrDesc* id) +{ + return (CodeGenInterface::instInfo[id->idIns()] & (Resets_OF | Resets_SF | Resets_AF | Resets_PF | Resets_CF)); +} + bool emitter::emitIsInstructionWritingToReg(instrDesc* id, regNumber reg) { - // TODO: + switch ((ID_OPS)emitFmtToOps[id->idInsFmt()]) + { + // This is conservative. + case ID_OP_CALL: + return true; + + default: + break; + } + + // This is a special case for idiv, div, imul, and mul. + // They always write to RAX and RDX. + if (instrHasImplicitRegPairDest(id->idIns())) + { + if (reg == REG_RAX || reg == REG_RDX) + { + return true; + } + } + +#ifdef TARGET_64BIT + // This is a special case for cdq/cwde/cmpxchg. + if (instrHasImplicitRegSingleDest(id->idIns())) + { + switch (id->idIns()) + { + case INS_cwde: + case INS_cmpxchg: + { + if (reg == REG_RAX) + { + return PEEPHOLE_ABORT; + } + break; + } + + case INS_cdq: + { + if (reg == REG_RDX) + { + return PEEPHOLE_ABORT; + } + break; + } + + default: + break; + } + } +#endif // TARGET_64BIT + + switch (id->idInsFmt()) + { + case IF_RWR: + case IF_RRW: + + case IF_RWR_CNS: + case IF_RRW_CNS: + case IF_RRW_SHF: + + case IF_RWR_RRD: + case IF_RRW_RRD: + case IF_RRW_RRW: + case IF_RRW_RRW_CNS: + + case IF_RWR_RRD_RRD: + case IF_RWR_RRD_RRD_CNS: + + case IF_RWR_RRD_RRD_RRD: + + case IF_RWR_MRD: + case IF_RRW_MRD: + case IF_RRW_MRD_CNS: + + case IF_RWR_RRD_MRD: + case IF_RWR_MRD_CNS: + case IF_RWR_RRD_MRD_CNS: + case IF_RWR_RRD_MRD_RRD: + case IF_RWR_MRD_OFF: + + case IF_RWR_SRD: + case IF_RRW_SRD: + case IF_RRW_SRD_CNS: + + case IF_RWR_RRD_SRD: + case IF_RWR_SRD_CNS: + case IF_RWR_RRD_SRD_CNS: + case IF_RWR_RRD_SRD_RRD: + + case IF_RWR_ARD: + case IF_RRW_ARD: + case IF_RRW_ARD_CNS: + + case IF_RWR_RRD_ARD: + case IF_RWR_ARD_CNS: + case IF_RWR_ARD_RRD: + case IF_RWR_RRD_ARD_CNS: + case IF_RWR_RRD_ARD_RRD: + { + if (id->idReg1() != reg) + { + switch (id->idInsFmt()) + { + // Handles instructions who write to two registers. + case IF_RRW_RRW: + case IF_RRW_RRW_CNS: + { + if (id->idReg2() == reg) + { + return true; + } + break; + } + + default: + break; + } + + return PEEPHOLE_CONTINUE; + } + + return true; + } + + default: + { + return false; + } + } + return false; } @@ -735,84 +870,18 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) emitPeepholeIterateLastInstrs( [&](instrDesc* id) { - switch (id->idIns()) + if (emitIsInstructionWritingToReg(id, reg1) || emitIsInstructionWritingToReg(id, reg2)) { - case INS_seta: - case INS_setae: - case INS_setb: - case INS_setbe: - case INS_sete: - case INS_setg: - case INS_setge: - case INS_setl: - case INS_setle: - case INS_setne: - case INS_setno: - case INS_setnp: - case INS_setns: - case INS_seto: - case INS_setp: - case INS_sets: - { - if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) - { - return PEEPHOLE_ABORT; - } - - return PEEPHOLE_CONTINUE; - } - - case INS_mov: - case INS_movsx: - case INS_movzx: - { - if ((id->idReg1() == reg1) || (id->idReg1() == reg2)) - { - return PEEPHOLE_ABORT; - } - - return PEEPHOLE_CONTINUE; - } + return PEEPHOLE_ABORT; + } - case INS_tail_i_jmp: - case INS_i_jmp: - case INS_jmp: - case INS_jo: - case INS_jno: - case INS_jb: - case INS_jae: - case INS_je: - case INS_jne: - case INS_jbe: - case INS_ja: - case INS_js: - case INS_jns: - case INS_jp: - case INS_jnp: - case INS_jl: - case INS_jge: - case INS_jle: - case INS_jg: - - case INS_l_jmp: - case INS_l_jo: - case INS_l_jno: - case INS_l_jb: - case INS_l_jae: - case INS_l_je: - case INS_l_jne: - case INS_l_jbe: - case INS_l_ja: - case INS_l_js: - case INS_l_jns: - case INS_l_jp: - case INS_l_jnp: - case INS_l_jl: - case INS_l_jge: - case INS_l_jle: - case INS_l_jg: - return PEEPHOLE_CONTINUE; + if (emitIsInstructionResettingFlags(id)) + { + return PEEPHOLE_ABORT; + } + switch (id->idIns()) + { case INS_cmp: { if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) @@ -821,13 +890,13 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) return PEEPHOLE_ABORT; } - return PEEPHOLE_ABORT; + return PEEPHOLE_CONTINUE; } default: - return PEEPHOLE_ABORT; + return PEEPHOLE_CONTINUE; } - }); + }); return result; } From 5058e59e0b0a94cf558fa7cb491e8541a285387a Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 1 Mar 2023 15:29:56 -0800 Subject: [PATCH 16/28] Remove useless comment --- src/coreclr/jit/emitxarch.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 0d2968819f5bc0..de608172ebd4cf 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -866,7 +866,6 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) bool result = false; - // instInfo emitPeepholeIterateLastInstrs( [&](instrDesc* id) { From 0ba01efe45e19b90e9f28c081f99fbe26c988649 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 1 Mar 2023 15:34:23 -0800 Subject: [PATCH 17/28] Minor fix --- src/coreclr/jit/emitxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index de608172ebd4cf..a816c893460029 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -832,7 +832,7 @@ bool emitter::emitIsInstructionWritingToReg(instrDesc* id, regNumber reg) break; } - return PEEPHOLE_CONTINUE; + return false; } return true; From 8d8485e0c7f583877ee149b30f53285d93723272 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 1 Mar 2023 17:18:01 -0800 Subject: [PATCH 18/28] Abort are checking cmp --- src/coreclr/jit/emitxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index a816c893460029..164cddaabcfa34 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -889,7 +889,7 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) return PEEPHOLE_ABORT; } - return PEEPHOLE_CONTINUE; + return PEEPHOLE_ABORT; } default: From 49b6f272c6cbb832080ccaf222d7dad6ddad12c9 Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 2 Mar 2023 16:42:56 -0800 Subject: [PATCH 19/28] Some refactoring. Taking into account any instruction that modifies flags. --- src/coreclr/jit/emit.h | 4 ++-- src/coreclr/jit/emitxarch.cpp | 42 ++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 2cee0f4c88fb28..babc201ad4daaa 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -2080,8 +2080,8 @@ class emitter void spillIntArgRegsToShadowSlots(); #ifdef TARGET_XARCH - bool emitIsInstructionWritingToReg(instrDesc* id, regNumber reg); - bool emitIsInstructionResettingFlags(instrDesc* id); + bool emitIsInstrWritingToReg(instrDesc* id, regNumber reg); + bool emitDoesInsModifyFlags(instruction ins); #endif // TARGET_XARCH /************************************************************************/ diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 164cddaabcfa34..b5eef98f305aec 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -707,17 +707,20 @@ bool emitter::AreUpper32BitsSignExtended(regNumber reg) #endif // TARGET_64BIT -bool emitter::emitIsInstructionResettingFlags(instrDesc* id) +bool emitter::emitDoesInsModifyFlags(instruction ins) { - return (CodeGenInterface::instInfo[id->idIns()] & (Resets_OF | Resets_SF | Resets_AF | Resets_PF | Resets_CF)); + return (CodeGenInterface::instInfo[ins] & + (Resets_OF | Resets_SF | Resets_AF | Resets_PF | Resets_CF | Undefined_OF | Undefined_SF | Undefined_AF | + Undefined_PF | Undefined_CF | Undefined_ZF | Writes_OF | Writes_SF | Writes_AF | Writes_PF | Writes_CF | + Writes_ZF | Restore_SF_ZF_AF_PF_CF)); } -bool emitter::emitIsInstructionWritingToReg(instrDesc* id, regNumber reg) +bool emitter::emitIsInstrWritingToReg(instrDesc* id, regNumber reg) { - switch ((ID_OPS)emitFmtToOps[id->idInsFmt()]) + switch (id->idIns()) { - // This is conservative. - case ID_OP_CALL: + // This is conservative. We assume a call will write to all regs even if it does not. + case INS_call: return true; default: @@ -869,32 +872,35 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) emitPeepholeIterateLastInstrs( [&](instrDesc* id) { - if (emitIsInstructionWritingToReg(id, reg1) || emitIsInstructionWritingToReg(id, reg2)) - { - return PEEPHOLE_ABORT; - } - - if (emitIsInstructionResettingFlags(id)) - { - return PEEPHOLE_ABORT; - } + instruction ins = id->idIns(); - switch (id->idIns()) + switch (ins) { case INS_cmp: { if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) { result = (size == id->idOpSize()); - return PEEPHOLE_ABORT; } return PEEPHOLE_ABORT; } default: - return PEEPHOLE_CONTINUE; + break; + } + + if (emitDoesInsModifyFlags(ins)) + { + return PEEPHOLE_ABORT; } + + if (emitIsInstrWritingToReg(id, reg1) || emitIsInstrWritingToReg(id, reg2)) + { + return PEEPHOLE_ABORT; + } + + return PEEPHOLE_CONTINUE; }); return result; From 49a8043f604c54edd99953b3bd0d4b6fdf66f929 Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 2 Mar 2023 17:10:42 -0800 Subject: [PATCH 20/28] Minor cleanup --- src/coreclr/jit/emitinl.h | 9 ----- src/coreclr/jit/emitxarch.cpp | 68 ++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/coreclr/jit/emitinl.h b/src/coreclr/jit/emitinl.h index b4ec3f4eb36cad..125c1ddd0fbd3f 100644 --- a/src/coreclr/jit/emitinl.h +++ b/src/coreclr/jit/emitinl.h @@ -30,18 +30,9 @@ inline bool emitter::instrIsExtendedReg3opImul(instruction ins) /* static */ inline bool emitter::instrHasImplicitRegPairDest(instruction ins) { - // These instructions write to RAX and RDX. return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv); } -/* static */ -inline bool emitter::instrHasImplicitRegSingleDest(instruction ins) -{ - // 'cdq' writes to RDX. - // 'cwde' and 'cmpxchg' writes to RAX. - return (ins == INS_cdq) || (ins == INS_cwde) || (ins == INS_cmpxchg); -} - // Because we don't actually have support for encoding these 3-op // multiplies we fake it with special opcodes. Make sure they are // contiguous. diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index b5eef98f305aec..0762a168f204f8 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -717,54 +717,58 @@ bool emitter::emitDoesInsModifyFlags(instruction ins) bool emitter::emitIsInstrWritingToReg(instrDesc* id, regNumber reg) { - switch (id->idIns()) + instruction ins = id->idIns(); + + // These are special cases since they modify one or more register(s) implicitly. + switch (ins) { - // This is conservative. We assume a call will write to all regs even if it does not. + // This is conservative. We assume a call will write to all registers even if it does not. case INS_call: return true; - default: + // These always write to RAX and RDX. + case INS_idiv: + case INS_div: + case INS_imulEAX: + case INS_mulEAX: + if (reg == REG_RAX || reg == REG_RDX) + { + return true; + } break; - } - // This is a special case for idiv, div, imul, and mul. - // They always write to RAX and RDX. - if (instrHasImplicitRegPairDest(id->idIns())) - { - if (reg == REG_RAX || reg == REG_RDX) - { - return true; - } + // Always writes to RAX. + case INS_cmpxchg: + if (reg == REG_RAX) + { + return true; + } + break; + + default: + break; } #ifdef TARGET_64BIT - // This is a special case for cdq/cwde/cmpxchg. - if (instrHasImplicitRegSingleDest(id->idIns())) + // This is a special case for cdq/cwde. + switch (ins) { - switch (id->idIns()) - { - case INS_cwde: - case INS_cmpxchg: + case INS_cwde: + if (reg == REG_RAX) { - if (reg == REG_RAX) - { - return PEEPHOLE_ABORT; - } - break; + return true; } + break; - case INS_cdq: + case INS_cdq: + if (reg == REG_RDX) { - if (reg == REG_RDX) - { - return PEEPHOLE_ABORT; - } - break; + return true; } + break; - default: - break; - } + default: + break; } #endif // TARGET_64BIT From ee0cd47b8f9f99615634ddd2cb2e7228b07cee75 Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 2 Mar 2023 17:13:13 -0800 Subject: [PATCH 21/28] Remove function from header --- src/coreclr/jit/emitpub.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/emitpub.h b/src/coreclr/jit/emitpub.h index 265254aea09690..0133fb19f0212d 100644 --- a/src/coreclr/jit/emitpub.h +++ b/src/coreclr/jit/emitpub.h @@ -102,7 +102,6 @@ UNATIVE_OFFSET emitDataSize(); static bool instrIs3opImul(instruction ins); static bool instrIsExtendedReg3opImul(instruction ins); static bool instrHasImplicitRegPairDest(instruction ins); -static bool instrHasImplicitRegSingleDest(instruction ins); static void check3opImulValues(); static regNumber inst3opImulReg(instruction ins); static instruction inst3opImulForReg(regNumber reg); From 91c1054aa7c3a5d732ddcf5bed85d3536cd33757 Mon Sep 17 00:00:00 2001 From: TIHan Date: Thu, 2 Mar 2023 17:26:35 -0800 Subject: [PATCH 22/28] Quick fix --- src/coreclr/jit/emitxarch.cpp | 153 +++++----------------------------- 1 file changed, 19 insertions(+), 134 deletions(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 0762a168f204f8..dae07ec4f97b3c 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -504,157 +504,42 @@ bool emitter::AreUpper32BitsZero(regNumber reg) bool result = false; - emitPeepholeIterateLastInstrs([&](instrDesc* id) { - switch ((ID_OPS)emitFmtToOps[id->idInsFmt()]) - { - // This is conservative. - case ID_OP_CALL: - return PEEPHOLE_ABORT; - - default: - break; - } - - // This is a special case for idiv, div, imul, and mul. - // They always write to RAX and RDX. - if (instrHasImplicitRegPairDest(id->idIns())) - { - if (reg == REG_RAX || reg == REG_RDX) - { - result = (id->idOpSize() == EA_4BYTE); - return PEEPHOLE_ABORT; - } - } - - // This is a special case for cdq/cwde/cmpxchg. - if (instrHasImplicitRegSingleDest(id->idIns())) + emitPeepholeIterateLastInstrs( + [&](instrDesc* id) { - switch (id->idIns()) + if (emitIsInstrWritingToReg(id, reg)) { - case INS_cwde: - case INS_cmpxchg: + switch (id->idIns()) { - if (reg == REG_RAX) - { + // Conservative. + case INS_call: return PEEPHOLE_ABORT; - } - break; - } - case INS_cdq: - { - if (reg == REG_RDX) - { + // These instructions sign-extend. + case INS_cwde: + case INS_cdq: + case INS_movsx: + case INS_movsxd: return PEEPHOLE_ABORT; - } - break; - } - default: - break; - } - } - - switch (id->idInsFmt()) - { - case IF_RWR: - case IF_RRW: - - case IF_RWR_CNS: - case IF_RRW_CNS: - case IF_RRW_SHF: - - case IF_RWR_RRD: - case IF_RRW_RRD: - case IF_RRW_RRW: - case IF_RRW_RRW_CNS: - - case IF_RWR_RRD_RRD: - case IF_RWR_RRD_RRD_CNS: - - case IF_RWR_RRD_RRD_RRD: - - case IF_RWR_MRD: - case IF_RRW_MRD: - case IF_RRW_MRD_CNS: - - case IF_RWR_RRD_MRD: - case IF_RWR_MRD_CNS: - case IF_RWR_RRD_MRD_CNS: - case IF_RWR_RRD_MRD_RRD: - case IF_RWR_MRD_OFF: - - case IF_RWR_SRD: - case IF_RRW_SRD: - case IF_RRW_SRD_CNS: - - case IF_RWR_RRD_SRD: - case IF_RWR_SRD_CNS: - case IF_RWR_RRD_SRD_CNS: - case IF_RWR_RRD_SRD_RRD: - - case IF_RWR_ARD: - case IF_RRW_ARD: - case IF_RRW_ARD_CNS: - - case IF_RWR_RRD_ARD: - case IF_RWR_ARD_CNS: - case IF_RWR_ARD_RRD: - case IF_RWR_RRD_ARD_CNS: - case IF_RWR_RRD_ARD_RRD: - { - if (id->idReg1() != reg) - { - switch (id->idInsFmt()) - { - // Handles instructions who write to two registers. - case IF_RRW_RRW: - case IF_RRW_RRW_CNS: - { - if (id->idReg2() == reg) - { - result = (id->idOpSize() == EA_4BYTE); - return PEEPHOLE_ABORT; - } - break; - } - - default: - break; - } - - return PEEPHOLE_CONTINUE; - } - - // movsx always sign extends to 8 bytes. - if (id->idIns() == INS_movsx) - { - return PEEPHOLE_ABORT; - } - - if (id->idIns() == INS_movsxd) - { - return PEEPHOLE_ABORT; - } + // movzx always zeroes the upper 32 bits. + case INS_movzx: + result = true; + return PEEPHOLE_ABORT; - // movzx always zeroes the upper 32 bits. - if (id->idIns() == INS_movzx) - { - result = true; - return PEEPHOLE_ABORT; + default: + break; } // otherwise rely on operation size. result = (id->idOpSize() == EA_4BYTE); return PEEPHOLE_ABORT; } - - default: + else { return PEEPHOLE_CONTINUE; } - } - }); + }); return result; } From 1c5f5181590ed586869b7d0c5a264564330bdbb3 Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 3 Mar 2023 17:07:43 -0800 Subject: [PATCH 23/28] Sync --- src/coreclr/jit/emitxarch.cpp | 73 ++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index dae07ec4f97b3c..6f848fc3ef2ebd 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -591,7 +591,16 @@ bool emitter::AreUpper32BitsSignExtended(regNumber reg) } #endif // TARGET_64BIT - +//------------------------------------------------------------------------ +// emitDoesInsModifyFlags: checks if the given instruction modifies flags +// +// Arguments: +// iins - instruction of interest +// +// Return Value: +// true if the instruction modifies flags. +// false if it did not. +// bool emitter::emitDoesInsModifyFlags(instruction ins) { return (CodeGenInterface::instInfo[ins] & @@ -600,8 +609,24 @@ bool emitter::emitDoesInsModifyFlags(instruction ins) Writes_ZF | Restore_SF_ZF_AF_PF_CF)); } +//------------------------------------------------------------------------ +// emitIsInstrWritingToReg: checks if the given register is being written to +// +// Arguments: +// id - instruction of interest +// reg - register of interest +// +// Return Value: +// true if the instruction writes to the given register. +// false if it did not. +// +// Note: This only handles integer registers. Also, an INS_call will always return true. +// bool emitter::emitIsInstrWritingToReg(instrDesc* id, regNumber reg) { + // This only handles integer registers for now. + assert(genIsValidIntReg(reg)); + instruction ins = id->idIns(); // These are special cases since they modify one or more register(s) implicitly. @@ -616,7 +641,7 @@ bool emitter::emitIsInstrWritingToReg(instrDesc* id, regNumber reg) case INS_div: case INS_imulEAX: case INS_mulEAX: - if (reg == REG_RAX || reg == REG_RDX) + if ((reg == REG_RAX) || (reg == REG_RDX)) { return true; } @@ -630,6 +655,50 @@ bool emitter::emitIsInstrWritingToReg(instrDesc* id, regNumber reg) } break; + case INS_movsb: + case INS_movsd: +#ifdef TARGET_AMD64 + case INS_movsq: +#endif // TARGET_AMD64 + if ((reg == REG_RDI) || (reg == REG_RSI)) + { + return true; + } + break; + + case INS_stosb: + case INS_stosd: +#ifdef TARGET_AMD64 + case INS_stosq: +#endif // TARGET_AMD64 + if (reg == REG_RDI) + { + return true; + } + break; + + case INS_r_movsb: + case INS_r_movsd: +#ifdef TARGET_AMD64 + case INS_r_movsq: +#endif // TARGET_AMD64 + if ((reg == REG_RDI) || (reg == REG_RSI) || (reg == REG_RCX)) + { + return true; + } + break; + + case INS_r_stosb: + case INS_r_stosd: +#ifdef TARGET_AMD64 + case INS_r_stosq: +#endif // TARGET_AMD64 + if ((reg == REG_RDI) || (reg == REG_RCX)) + { + return true; + } + break; + default: break; } From 4d4e059763b1367779d7fe45b8dae6ad7beab0ee Mon Sep 17 00:00:00 2001 From: TIHan Date: Mon, 3 Apr 2023 14:01:23 -0700 Subject: [PATCH 24/28] Formatting --- src/coreclr/jit/emitxarch.cpp | 44 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index eae35be8882bb3..e62b659724feb0 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -831,38 +831,36 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) bool result = false; - emitPeepholeIterateLastInstrs( - [&](instrDesc* id) - { - instruction ins = id->idIns(); + emitPeepholeIterateLastInstrs([&](instrDesc* id) { + instruction ins = id->idIns(); - switch (ins) + switch (ins) + { + case INS_cmp: { - case INS_cmp: + if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) { - if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) - { - result = (size == id->idOpSize()); - } - - return PEEPHOLE_ABORT; + result = (size == id->idOpSize()); } - default: - break; - } - - if (emitDoesInsModifyFlags(ins)) - { return PEEPHOLE_ABORT; } - if (emitIsInstrWritingToReg(id, reg1) || emitIsInstrWritingToReg(id, reg2)) - { - return PEEPHOLE_ABORT; - } + default: + break; + } - return PEEPHOLE_CONTINUE; + if (emitDoesInsModifyFlags(ins)) + { + return PEEPHOLE_ABORT; + } + + if (emitIsInstrWritingToReg(id, reg1) || emitIsInstrWritingToReg(id, reg2)) + { + return PEEPHOLE_ABORT; + } + + return PEEPHOLE_CONTINUE; }); return result; From 03d9ab321a49b9e7452a6e18913be036beddd030 Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 4 Apr 2023 19:22:09 -0700 Subject: [PATCH 25/28] Only look for 'cmp reg, reg' --- src/coreclr/jit/emitxarch.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index e62b659724feb0..007ac5948546dc 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -838,6 +838,10 @@ bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) { case INS_cmp: { + // We only care about 'cmp reg, reg'. + if (id->idInsFmt() != IF_RRD_RRD) + return PEEPHOLE_ABORT; + if ((id->idReg1() == reg1) && (id->idReg2() == reg2)) { result = (size == id->idOpSize()); From 51c70a734e8a876d801e3a1a0c434c7735645ec1 Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 4 Apr 2023 19:31:29 -0700 Subject: [PATCH 26/28] Added comment --- src/coreclr/jit/emitxarch.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 007ac5948546dc..93982b0a2434f2 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -812,6 +812,17 @@ bool emitter::emitIsInstrWritingToReg(instrDesc* id, regNumber reg) return false; } +//------------------------------------------------------------------------ +// IsRedundantCmp: determines if there is a 'cmp' instruction that is redundant with the given inputs +// +// Arguments: +// size - size of 'cmp' +// reg1 - op1 register of 'cmp' +// reg2 - op2 register of 'cmp' +// +// Return Value: +// true if there is a redundant 'cmp' +// bool emitter::IsRedundantCmp(emitAttr size, regNumber reg1, regNumber reg2) { // Only allow GPRs. From 3dd723fa5eef5bd0c2213d9360ebc5160f1db9f6 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 5 Apr 2023 13:06:46 -0700 Subject: [PATCH 27/28] Update src/coreclr/jit/emitxarch.cpp Co-authored-by: Bruce Forstall --- src/coreclr/jit/emitxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 93982b0a2434f2..152c02e653b730 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -599,7 +599,7 @@ bool emitter::AreUpper32BitsSignExtended(regNumber reg) // emitDoesInsModifyFlags: checks if the given instruction modifies flags // // Arguments: -// iins - instruction of interest +// ins - instruction of interest // // Return Value: // true if the instruction modifies flags. From 0cb00b4090827d2a58c764b4927bbfcca1a1e968 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 5 Apr 2023 13:06:53 -0700 Subject: [PATCH 28/28] Update src/coreclr/jit/emitxarch.cpp Co-authored-by: Bruce Forstall --- src/coreclr/jit/emitxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 152c02e653b730..2b179af46a37d6 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -603,7 +603,7 @@ bool emitter::AreUpper32BitsSignExtended(regNumber reg) // // Return Value: // true if the instruction modifies flags. -// false if it did not. +// false if it does not. // bool emitter::emitDoesInsModifyFlags(instruction ins) {