From 1687555572ee4fb435da400dde02e7a1e60b742c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Sat, 6 Jan 2024 11:28:10 +0100 Subject: [PATCH] [GlobalIsel] Combine select of binops (#76763) --- .../llvm/CodeGen/GlobalISel/CombinerHelper.h | 3 + .../CodeGen/GlobalISel/GenericMachineInstrs.h | 103 ++++++++++++ .../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 93 +++++++---- .../AArch64/GlobalISel/combine-select.mir | 151 ++++++++++++++++++ 4 files changed, 322 insertions(+), 28 deletions(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h index dcc1a4580b14a2..f3b68623596c46 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -910,6 +910,9 @@ class CombinerHelper { bool tryFoldSelectOfConstants(GSelect *Select, BuildFnTy &MatchInfo); + /// Try to fold select(cc, binop(), binop()) -> binop(select(), X) + bool tryFoldSelectOfBinOps(GSelect *Select, BuildFnTy &MatchInfo); + bool isOneOrOneSplat(Register Src, bool AllowUndefs); bool isZeroOrZeroSplat(Register Src, bool AllowUndefs); bool isConstantSplatVector(Register Src, int64_t SplatValue, diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h index 6ab1d4550c51ca..21d98d30356c93 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h @@ -558,6 +558,109 @@ class GVecReduce : public GenericMachineInstr { } }; +// Represents a binary operation, i.e, x = y op z. +class GBinOp : public GenericMachineInstr { +public: + Register getLHSReg() const { return getReg(1); } + Register getRHSReg() const { return getReg(2); } + + static bool classof(const MachineInstr *MI) { + switch (MI->getOpcode()) { + // Integer. + case TargetOpcode::G_ADD: + case TargetOpcode::G_SUB: + case TargetOpcode::G_MUL: + case TargetOpcode::G_SDIV: + case TargetOpcode::G_UDIV: + case TargetOpcode::G_SREM: + case TargetOpcode::G_UREM: + case TargetOpcode::G_SMIN: + case TargetOpcode::G_SMAX: + case TargetOpcode::G_UMIN: + case TargetOpcode::G_UMAX: + // Floating point. + case TargetOpcode::G_FMINNUM: + case TargetOpcode::G_FMAXNUM: + case TargetOpcode::G_FMINNUM_IEEE: + case TargetOpcode::G_FMAXNUM_IEEE: + case TargetOpcode::G_FMINIMUM: + case TargetOpcode::G_FMAXIMUM: + case TargetOpcode::G_FADD: + case TargetOpcode::G_FSUB: + case TargetOpcode::G_FMUL: + case TargetOpcode::G_FDIV: + case TargetOpcode::G_FPOW: + // Logical. + case TargetOpcode::G_AND: + case TargetOpcode::G_OR: + case TargetOpcode::G_XOR: + return true; + default: + return false; + } + }; +}; + +// Represents an integer binary operation. +class GIntBinOp : public GBinOp { +public: + static bool classof(const MachineInstr *MI) { + switch (MI->getOpcode()) { + case TargetOpcode::G_ADD: + case TargetOpcode::G_SUB: + case TargetOpcode::G_MUL: + case TargetOpcode::G_SDIV: + case TargetOpcode::G_UDIV: + case TargetOpcode::G_SREM: + case TargetOpcode::G_UREM: + case TargetOpcode::G_SMIN: + case TargetOpcode::G_SMAX: + case TargetOpcode::G_UMIN: + case TargetOpcode::G_UMAX: + return true; + default: + return false; + } + }; +}; + +// Represents a floating point binary operation. +class GFBinOp : public GBinOp { +public: + static bool classof(const MachineInstr *MI) { + switch (MI->getOpcode()) { + case TargetOpcode::G_FMINNUM: + case TargetOpcode::G_FMAXNUM: + case TargetOpcode::G_FMINNUM_IEEE: + case TargetOpcode::G_FMAXNUM_IEEE: + case TargetOpcode::G_FMINIMUM: + case TargetOpcode::G_FMAXIMUM: + case TargetOpcode::G_FADD: + case TargetOpcode::G_FSUB: + case TargetOpcode::G_FMUL: + case TargetOpcode::G_FDIV: + case TargetOpcode::G_FPOW: + return true; + default: + return false; + } + }; +}; + +// Represents a logical binary operation. +class GLogicalBinOp : public GBinOp { +public: + static bool classof(const MachineInstr *MI) { + switch (MI->getOpcode()) { + case TargetOpcode::G_AND: + case TargetOpcode::G_OR: + case TargetOpcode::G_XOR: + return true; + default: + return false; + } + }; +}; } // namespace llvm diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 8b15bdb0aca30b..5d8def4cca6668 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -6390,8 +6390,7 @@ bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select, if (TrueValue.isZero() && FalseValue.isOne()) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Inner = MRI.createGenericVirtualRegister(CondTy); - B.buildNot(Inner, Cond); + auto Inner = B.buildNot(CondTy, Cond); B.buildZExtOrTrunc(Dest, Inner); }; return true; @@ -6401,8 +6400,7 @@ bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select, if (TrueValue.isZero() && FalseValue.isAllOnes()) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Inner = MRI.createGenericVirtualRegister(CondTy); - B.buildNot(Inner, Cond); + auto Inner = B.buildNot(CondTy, Cond); B.buildSExtOrTrunc(Dest, Inner); }; return true; @@ -6412,8 +6410,7 @@ bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select, if (TrueValue - 1 == FalseValue) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Inner = MRI.createGenericVirtualRegister(TrueTy); - B.buildZExtOrTrunc(Inner, Cond); + auto Inner = B.buildZExtOrTrunc(TrueTy, Cond); B.buildAdd(Dest, Inner, False); }; return true; @@ -6423,8 +6420,7 @@ bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select, if (TrueValue + 1 == FalseValue) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Inner = MRI.createGenericVirtualRegister(TrueTy); - B.buildSExtOrTrunc(Inner, Cond); + auto Inner = B.buildSExtOrTrunc(TrueTy, Cond); B.buildAdd(Dest, Inner, False); }; return true; @@ -6434,8 +6430,7 @@ bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select, if (TrueValue.isPowerOf2() && FalseValue.isZero()) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Inner = MRI.createGenericVirtualRegister(TrueTy); - B.buildZExtOrTrunc(Inner, Cond); + auto Inner = B.buildZExtOrTrunc(TrueTy, Cond); // The shift amount must be scalar. LLT ShiftTy = TrueTy.isVector() ? TrueTy.getElementType() : TrueTy; auto ShAmtC = B.buildConstant(ShiftTy, TrueValue.exactLogBase2()); @@ -6447,8 +6442,7 @@ bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select, if (TrueValue.isAllOnes()) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Inner = MRI.createGenericVirtualRegister(TrueTy); - B.buildSExtOrTrunc(Inner, Cond); + auto Inner = B.buildSExtOrTrunc(TrueTy, Cond); B.buildOr(Dest, Inner, False, Flags); }; return true; @@ -6458,10 +6452,8 @@ bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select, if (FalseValue.isAllOnes()) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Not = MRI.createGenericVirtualRegister(CondTy); - B.buildNot(Not, Cond); - Register Inner = MRI.createGenericVirtualRegister(TrueTy); - B.buildSExtOrTrunc(Inner, Not); + auto Not = B.buildNot(CondTy, Cond); + auto Inner = B.buildSExtOrTrunc(TrueTy, Not); B.buildOr(Dest, Inner, True, Flags); }; return true; @@ -6496,8 +6488,7 @@ bool CombinerHelper::tryFoldBoolSelectToLogic(GSelect *Select, if ((Cond == True) || isOneOrOneSplat(True, /* AllowUndefs */ true)) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Ext = MRI.createGenericVirtualRegister(TrueTy); - B.buildZExtOrTrunc(Ext, Cond); + auto Ext = B.buildZExtOrTrunc(TrueTy, Cond); B.buildOr(DstReg, Ext, False, Flags); }; return true; @@ -6508,8 +6499,7 @@ bool CombinerHelper::tryFoldBoolSelectToLogic(GSelect *Select, if ((Cond == False) || isZeroOrZeroSplat(False, /* AllowUndefs */ true)) { MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); - Register Ext = MRI.createGenericVirtualRegister(TrueTy); - B.buildZExtOrTrunc(Ext, Cond); + auto Ext = B.buildZExtOrTrunc(TrueTy, Cond); B.buildAnd(DstReg, Ext, True); }; return true; @@ -6520,11 +6510,9 @@ bool CombinerHelper::tryFoldBoolSelectToLogic(GSelect *Select, MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); // First the not. - Register Inner = MRI.createGenericVirtualRegister(CondTy); - B.buildNot(Inner, Cond); + auto Inner = B.buildNot(CondTy, Cond); // Then an ext to match the destination register. - Register Ext = MRI.createGenericVirtualRegister(TrueTy); - B.buildZExtOrTrunc(Ext, Inner); + auto Ext = B.buildZExtOrTrunc(TrueTy, Inner); B.buildOr(DstReg, Ext, True, Flags); }; return true; @@ -6535,11 +6523,9 @@ bool CombinerHelper::tryFoldBoolSelectToLogic(GSelect *Select, MatchInfo = [=](MachineIRBuilder &B) { B.setInstrAndDebugLoc(*Select); // First the not. - Register Inner = MRI.createGenericVirtualRegister(CondTy); - B.buildNot(Inner, Cond); + auto Inner = B.buildNot(CondTy, Cond); // Then an ext to match the destination register. - Register Ext = MRI.createGenericVirtualRegister(TrueTy); - B.buildZExtOrTrunc(Ext, Inner); + auto Ext = B.buildZExtOrTrunc(TrueTy, Inner); B.buildAnd(DstReg, Ext, False); }; return true; @@ -6548,6 +6534,54 @@ bool CombinerHelper::tryFoldBoolSelectToLogic(GSelect *Select, return false; } +bool CombinerHelper::tryFoldSelectOfBinOps(GSelect *Select, + BuildFnTy &MatchInfo) { + Register DstReg = Select->getReg(0); + Register Cond = Select->getCondReg(); + Register False = Select->getFalseReg(); + Register True = Select->getTrueReg(); + LLT DstTy = MRI.getType(DstReg); + + GBinOp *LHS = getOpcodeDef(True, MRI); + GBinOp *RHS = getOpcodeDef(False, MRI); + + // We need two binops of the same kind on the true/false registers. + if (!LHS || !RHS || LHS->getOpcode() != RHS->getOpcode()) + return false; + + // Note that there are no constraints on CondTy. + unsigned Flags = (LHS->getFlags() & RHS->getFlags()) | Select->getFlags(); + unsigned Opcode = LHS->getOpcode(); + + // Fold select(cond, binop(x, y), binop(z, y)) + // --> binop(select(cond, x, z), y) + if (LHS->getRHSReg() == RHS->getRHSReg()) { + MatchInfo = [=](MachineIRBuilder &B) { + B.setInstrAndDebugLoc(*Select); + auto Sel = B.buildSelect(DstTy, Cond, LHS->getLHSReg(), RHS->getLHSReg(), + Select->getFlags()); + B.buildInstr(Opcode, {DstReg}, {Sel, LHS->getRHSReg()}, Flags); + }; + return true; + } + + // Fold select(cond, binop(x, y), binop(x, z)) + // --> binop(x, select(cond, y, z)) + if (LHS->getLHSReg() == RHS->getLHSReg()) { + MatchInfo = [=](MachineIRBuilder &B) { + B.setInstrAndDebugLoc(*Select); + auto Sel = B.buildSelect(DstTy, Cond, LHS->getRHSReg(), RHS->getRHSReg(), + Select->getFlags()); + B.buildInstr(Opcode, {DstReg}, {LHS->getLHSReg(), Sel}, Flags); + }; + return true; + } + + // FIXME: use isCommutable(). + + return false; +} + bool CombinerHelper::matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) { GSelect *Select = cast(&MI); @@ -6557,5 +6591,8 @@ bool CombinerHelper::matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) { if (tryFoldBoolSelectToLogic(Select, MatchInfo)) return true; + if (tryFoldSelectOfBinOps(Select, MatchInfo)) + return true; + return false; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir index be2de620fa456c..c5a3490221b661 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir @@ -544,3 +544,154 @@ body: | %ext:_(s32) = G_ANYEXT %sel $w0 = COPY %ext(s32) ... +--- +# select cond, and(x, y), and(z, y) --> and (select cond, x, z), y +name: select_cond_and_x_y_and_z_y_and_select_x_z_y +body: | + bb.1: + liveins: $x0, $x1, $x2 + ; CHECK-LABEL: name: select_cond_and_x_y_and_z_y_and_select_x_z_y + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY $x3 + ; CHECK-NEXT: %c:_(s1) = G_TRUNC [[COPY]](s64) + ; CHECK-NEXT: %a:_(s8) = G_TRUNC [[COPY1]](s64) + ; CHECK-NEXT: %b:_(s8) = G_TRUNC [[COPY2]](s64) + ; CHECK-NEXT: %d:_(s8) = G_TRUNC [[COPY3]](s64) + ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(s8) = G_SELECT %c(s1), %a, %d + ; CHECK-NEXT: %sel:_(s8) = G_AND [[SELECT]], %b + ; CHECK-NEXT: %ext:_(s32) = G_ANYEXT %sel(s8) + ; CHECK-NEXT: $w0 = COPY %ext(s32) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %3:_(s64) = COPY $x3 + %4:_(s64) = COPY $x4 + %c:_(s1) = G_TRUNC %0 + %a:_(s8) = G_TRUNC %1 + %b:_(s8) = G_TRUNC %2 + %d:_(s8) = G_TRUNC %3 + %e:_(s8) = G_TRUNC %4 + %and1:_(s8) = G_AND %a, %b + %and2:_(s8) = G_AND %d, %b + %sel:_(s8) = G_SELECT %c, %and1, %and2 + %ext:_(s32) = G_ANYEXT %sel + $w0 = COPY %ext(s32) +... +--- +# select cond, xor(x, y), xor(x, z) --> xor x, select, x, z) +name: select_cond_xor_x_y_xor_x_z_xor_x__select_x_y +body: | + bb.1: + liveins: $x0, $x1, $x2 + ; CHECK-LABEL: name: select_cond_xor_x_y_xor_x_z_xor_x__select_x_y + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x3 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY $x4 + ; CHECK-NEXT: %c:_(s1) = G_TRUNC [[COPY]](s64) + ; CHECK-NEXT: %a:_(s8) = G_TRUNC [[COPY1]](s64) + ; CHECK-NEXT: %d:_(s8) = G_TRUNC [[COPY2]](s64) + ; CHECK-NEXT: %e:_(s8) = G_TRUNC [[COPY3]](s64) + ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(s8) = G_SELECT %c(s1), %e, %d + ; CHECK-NEXT: %sel:_(s8) = G_XOR %a, [[SELECT]] + ; CHECK-NEXT: %ext:_(s32) = G_ANYEXT %sel(s8) + ; CHECK-NEXT: $w0 = COPY %ext(s32) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %3:_(s64) = COPY $x3 + %4:_(s64) = COPY $x4 + %c:_(s1) = G_TRUNC %0 + %a:_(s8) = G_TRUNC %1 + %b:_(s8) = G_TRUNC %2 + %d:_(s8) = G_TRUNC %3 + %e:_(s8) = G_TRUNC %4 + %xor1:_(s8) = G_XOR %a, %e + %xor2:_(s8) = G_XOR %a, %d + %sel:_(s8) = G_SELECT %c, %xor1, %xor2 + %ext:_(s32) = G_ANYEXT %sel + $w0 = COPY %ext(s32) +... +--- +# negative test select cond, and(x, y), or(z, a) --> failed +name: select_cond_and_x_y_or_z_a_failed +body: | + bb.1: + liveins: $x0, $x1, $x2 + ; CHECK-LABEL: name: select_cond_and_x_y_or_z_a_failed + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY $x3 + ; CHECK-NEXT: [[COPY4:%[0-9]+]]:_(s64) = COPY $x4 + ; CHECK-NEXT: %c:_(s1) = G_TRUNC [[COPY]](s64) + ; CHECK-NEXT: %a:_(s8) = G_TRUNC [[COPY1]](s64) + ; CHECK-NEXT: %b:_(s8) = G_TRUNC [[COPY2]](s64) + ; CHECK-NEXT: %d:_(s8) = G_TRUNC [[COPY3]](s64) + ; CHECK-NEXT: %e:_(s8) = G_TRUNC [[COPY4]](s64) + ; CHECK-NEXT: %and1:_(s8) = G_AND %a, %b + ; CHECK-NEXT: %or2:_(s8) = G_OR %e, %d + ; CHECK-NEXT: %sel:_(s8) = G_SELECT %c(s1), %and1, %or2 + ; CHECK-NEXT: %ext:_(s32) = G_ANYEXT %sel(s8) + ; CHECK-NEXT: $w0 = COPY %ext(s32) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %3:_(s64) = COPY $x3 + %4:_(s64) = COPY $x4 + %c:_(s1) = G_TRUNC %0 + %a:_(s8) = G_TRUNC %1 + %b:_(s8) = G_TRUNC %2 + %d:_(s8) = G_TRUNC %3 + %e:_(s8) = G_TRUNC %4 + %and1:_(s8) = G_AND %a, %b + %or2:_(s8) = G_OR %e, %d + %sel:_(s8) = G_SELECT %c, %and1, %or2 + %ext:_(s32) = G_ANYEXT %sel + $w0 = COPY %ext(s32) +... +--- +# flags test select cond, xor(x, y), xor(x, z) --> xor x, select, cond, x, z) +name: flags_select_cond_xor_x_y_xor_x_z_xor_x__select_cond_x_y +body: | + bb.1: + liveins: $x0, $x1, $x2 + ; CHECK-LABEL: name: flags_select_cond_xor_x_y_xor_x_z_xor_x__select_cond_x_y + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s64) = COPY $x3 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s64) = COPY $x4 + ; CHECK-NEXT: %c:_(s1) = G_TRUNC [[COPY]](s64) + ; CHECK-NEXT: %a:_(s8) = G_TRUNC [[COPY1]](s64) + ; CHECK-NEXT: %d:_(s8) = G_TRUNC [[COPY2]](s64) + ; CHECK-NEXT: %e:_(s8) = G_TRUNC [[COPY3]](s64) + ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(s8) = ninf exact G_SELECT %c(s1), %e, %d + ; CHECK-NEXT: %sel:_(s8) = ninf arcp exact G_XOR %a, [[SELECT]] + ; CHECK-NEXT: %ext:_(s32) = G_ANYEXT %sel(s8) + ; CHECK-NEXT: $w0 = COPY %ext(s32) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %3:_(s64) = COPY $x3 + %4:_(s64) = COPY $x4 + %c:_(s1) = G_TRUNC %0 + %a:_(s8) = G_TRUNC %1 + %b:_(s8) = G_TRUNC %2 + %d:_(s8) = G_TRUNC %3 + %e:_(s8) = G_TRUNC %4 + %xor1:_(s8) = nsz arcp nsw G_XOR %a, %e + %xor2:_(s8) = nnan arcp nuw G_XOR %a, %d + %sel:_(s8) = ninf exact G_SELECT %c, %xor1, %xor2 + %ext:_(s32) = G_ANYEXT %sel + $w0 = COPY %ext(s32) +...