12ca300f9SThorsten Schütt //===- CombinerHelperCasts.cpp---------------------------------------------===// 22ca300f9SThorsten Schütt // 32ca300f9SThorsten Schütt // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42ca300f9SThorsten Schütt // See https://llvm.org/LICENSE.txt for license information. 52ca300f9SThorsten Schütt // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62ca300f9SThorsten Schütt // 72ca300f9SThorsten Schütt //===----------------------------------------------------------------------===// 82ca300f9SThorsten Schütt // 92ca300f9SThorsten Schütt // This file implements CombinerHelper for G_ANYEXT, G_SEXT, G_TRUNC, and 102ca300f9SThorsten Schütt // G_ZEXT 112ca300f9SThorsten Schütt // 122ca300f9SThorsten Schütt //===----------------------------------------------------------------------===// 132ca300f9SThorsten Schütt #include "llvm/CodeGen/GlobalISel/CombinerHelper.h" 142ca300f9SThorsten Schütt #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 152ca300f9SThorsten Schütt #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" 162ca300f9SThorsten Schütt #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 172ca300f9SThorsten Schütt #include "llvm/CodeGen/GlobalISel/Utils.h" 182ca300f9SThorsten Schütt #include "llvm/CodeGen/LowLevelTypeUtils.h" 192ca300f9SThorsten Schütt #include "llvm/CodeGen/MachineOperand.h" 202ca300f9SThorsten Schütt #include "llvm/CodeGen/MachineRegisterInfo.h" 212ca300f9SThorsten Schütt #include "llvm/CodeGen/TargetOpcodes.h" 222ca300f9SThorsten Schütt #include "llvm/Support/Casting.h" 232ca300f9SThorsten Schütt 242ca300f9SThorsten Schütt #define DEBUG_TYPE "gi-combiner" 252ca300f9SThorsten Schütt 262ca300f9SThorsten Schütt using namespace llvm; 272ca300f9SThorsten Schütt 282ca300f9SThorsten Schütt bool CombinerHelper::matchSextOfTrunc(const MachineOperand &MO, 292ca300f9SThorsten Schütt BuildFnTy &MatchInfo) { 302ca300f9SThorsten Schütt GSext *Sext = cast<GSext>(getDefIgnoringCopies(MO.getReg(), MRI)); 312ca300f9SThorsten Schütt GTrunc *Trunc = cast<GTrunc>(getDefIgnoringCopies(Sext->getSrcReg(), MRI)); 322ca300f9SThorsten Schütt 332ca300f9SThorsten Schütt Register Dst = Sext->getReg(0); 342ca300f9SThorsten Schütt Register Src = Trunc->getSrcReg(); 352ca300f9SThorsten Schütt 362ca300f9SThorsten Schütt LLT DstTy = MRI.getType(Dst); 372ca300f9SThorsten Schütt LLT SrcTy = MRI.getType(Src); 382ca300f9SThorsten Schütt 392ca300f9SThorsten Schütt if (DstTy == SrcTy) { 402ca300f9SThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); }; 412ca300f9SThorsten Schütt return true; 422ca300f9SThorsten Schütt } 432ca300f9SThorsten Schütt 442ca300f9SThorsten Schütt if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() && 452ca300f9SThorsten Schütt isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) { 462ca300f9SThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { 472ca300f9SThorsten Schütt B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoSWrap); 482ca300f9SThorsten Schütt }; 492ca300f9SThorsten Schütt return true; 502ca300f9SThorsten Schütt } 512ca300f9SThorsten Schütt 522ca300f9SThorsten Schütt if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() && 532ca300f9SThorsten Schütt isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}})) { 542ca300f9SThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); }; 552ca300f9SThorsten Schütt return true; 562ca300f9SThorsten Schütt } 572ca300f9SThorsten Schütt 582ca300f9SThorsten Schütt return false; 592ca300f9SThorsten Schütt } 602ca300f9SThorsten Schütt 612ca300f9SThorsten Schütt bool CombinerHelper::matchZextOfTrunc(const MachineOperand &MO, 622ca300f9SThorsten Schütt BuildFnTy &MatchInfo) { 632ca300f9SThorsten Schütt GZext *Zext = cast<GZext>(getDefIgnoringCopies(MO.getReg(), MRI)); 642ca300f9SThorsten Schütt GTrunc *Trunc = cast<GTrunc>(getDefIgnoringCopies(Zext->getSrcReg(), MRI)); 652ca300f9SThorsten Schütt 662ca300f9SThorsten Schütt Register Dst = Zext->getReg(0); 672ca300f9SThorsten Schütt Register Src = Trunc->getSrcReg(); 682ca300f9SThorsten Schütt 692ca300f9SThorsten Schütt LLT DstTy = MRI.getType(Dst); 702ca300f9SThorsten Schütt LLT SrcTy = MRI.getType(Src); 712ca300f9SThorsten Schütt 722ca300f9SThorsten Schütt if (DstTy == SrcTy) { 732ca300f9SThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); }; 742ca300f9SThorsten Schütt return true; 752ca300f9SThorsten Schütt } 762ca300f9SThorsten Schütt 772ca300f9SThorsten Schütt if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() && 782ca300f9SThorsten Schütt isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) { 792ca300f9SThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { 802ca300f9SThorsten Schütt B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoUWrap); 812ca300f9SThorsten Schütt }; 822ca300f9SThorsten Schütt return true; 832ca300f9SThorsten Schütt } 842ca300f9SThorsten Schütt 852ca300f9SThorsten Schütt if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() && 862ca300f9SThorsten Schütt isLegalOrBeforeLegalizer({TargetOpcode::G_ZEXT, {DstTy, SrcTy}})) { 872ca300f9SThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { 882ca300f9SThorsten Schütt B.buildZExt(Dst, Src, MachineInstr::MIFlag::NonNeg); 892ca300f9SThorsten Schütt }; 902ca300f9SThorsten Schütt return true; 912ca300f9SThorsten Schütt } 922ca300f9SThorsten Schütt 932ca300f9SThorsten Schütt return false; 942ca300f9SThorsten Schütt } 952ca300f9SThorsten Schütt 962ca300f9SThorsten Schütt bool CombinerHelper::matchNonNegZext(const MachineOperand &MO, 972ca300f9SThorsten Schütt BuildFnTy &MatchInfo) { 982ca300f9SThorsten Schütt GZext *Zext = cast<GZext>(MRI.getVRegDef(MO.getReg())); 992ca300f9SThorsten Schütt 1002ca300f9SThorsten Schütt Register Dst = Zext->getReg(0); 1012ca300f9SThorsten Schütt Register Src = Zext->getSrcReg(); 1022ca300f9SThorsten Schütt 1032ca300f9SThorsten Schütt LLT DstTy = MRI.getType(Dst); 1042ca300f9SThorsten Schütt LLT SrcTy = MRI.getType(Src); 1052ca300f9SThorsten Schütt const auto &TLI = getTargetLowering(); 1062ca300f9SThorsten Schütt 1072ca300f9SThorsten Schütt // Convert zext nneg to sext if sext is the preferred form for the target. 1082ca300f9SThorsten Schütt if (isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}}) && 1092ca300f9SThorsten Schütt TLI.isSExtCheaperThanZExt(getMVTForLLT(SrcTy), getMVTForLLT(DstTy))) { 1102ca300f9SThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); }; 1112ca300f9SThorsten Schütt return true; 1122ca300f9SThorsten Schütt } 1132ca300f9SThorsten Schütt 1142ca300f9SThorsten Schütt return false; 1152ca300f9SThorsten Schütt } 116bfcfb0fdSThorsten Schütt 117bfcfb0fdSThorsten Schütt bool CombinerHelper::matchTruncateOfExt(const MachineInstr &Root, 118bfcfb0fdSThorsten Schütt const MachineInstr &ExtMI, 119bfcfb0fdSThorsten Schütt BuildFnTy &MatchInfo) { 120bfcfb0fdSThorsten Schütt const GTrunc *Trunc = cast<GTrunc>(&Root); 121bfcfb0fdSThorsten Schütt const GExtOp *Ext = cast<GExtOp>(&ExtMI); 122bfcfb0fdSThorsten Schütt 123bfcfb0fdSThorsten Schütt if (!MRI.hasOneNonDBGUse(Ext->getReg(0))) 124bfcfb0fdSThorsten Schütt return false; 125bfcfb0fdSThorsten Schütt 126bfcfb0fdSThorsten Schütt Register Dst = Trunc->getReg(0); 127bfcfb0fdSThorsten Schütt Register Src = Ext->getSrcReg(); 128bfcfb0fdSThorsten Schütt LLT DstTy = MRI.getType(Dst); 129bfcfb0fdSThorsten Schütt LLT SrcTy = MRI.getType(Src); 130bfcfb0fdSThorsten Schütt 131bfcfb0fdSThorsten Schütt if (SrcTy == DstTy) { 132bfcfb0fdSThorsten Schütt // The source and the destination are equally sized. We need to copy. 133bfcfb0fdSThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); }; 134bfcfb0fdSThorsten Schütt 135bfcfb0fdSThorsten Schütt return true; 136bfcfb0fdSThorsten Schütt } 137bfcfb0fdSThorsten Schütt 138bfcfb0fdSThorsten Schütt if (SrcTy.getScalarSizeInBits() < DstTy.getScalarSizeInBits()) { 139bfcfb0fdSThorsten Schütt // If the source is smaller than the destination, we need to extend. 140bfcfb0fdSThorsten Schütt 141bfcfb0fdSThorsten Schütt if (!isLegalOrBeforeLegalizer({Ext->getOpcode(), {DstTy, SrcTy}})) 142bfcfb0fdSThorsten Schütt return false; 143bfcfb0fdSThorsten Schütt 144bfcfb0fdSThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { 145bfcfb0fdSThorsten Schütt B.buildInstr(Ext->getOpcode(), {Dst}, {Src}); 146bfcfb0fdSThorsten Schütt }; 147bfcfb0fdSThorsten Schütt 148bfcfb0fdSThorsten Schütt return true; 149bfcfb0fdSThorsten Schütt } 150bfcfb0fdSThorsten Schütt 151bfcfb0fdSThorsten Schütt if (SrcTy.getScalarSizeInBits() > DstTy.getScalarSizeInBits()) { 152bfcfb0fdSThorsten Schütt // If the source is larger than the destination, then we need to truncate. 153bfcfb0fdSThorsten Schütt 154bfcfb0fdSThorsten Schütt if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) 155bfcfb0fdSThorsten Schütt return false; 156bfcfb0fdSThorsten Schütt 157bfcfb0fdSThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { B.buildTrunc(Dst, Src); }; 158bfcfb0fdSThorsten Schütt 159bfcfb0fdSThorsten Schütt return true; 160bfcfb0fdSThorsten Schütt } 161bfcfb0fdSThorsten Schütt 162bfcfb0fdSThorsten Schütt return false; 163bfcfb0fdSThorsten Schütt } 164*db8c84fcSThorsten Schütt 165*db8c84fcSThorsten Schütt bool CombinerHelper::isCastFree(unsigned Opcode, LLT ToTy, LLT FromTy) const { 166*db8c84fcSThorsten Schütt const TargetLowering &TLI = getTargetLowering(); 167*db8c84fcSThorsten Schütt const DataLayout &DL = getDataLayout(); 168*db8c84fcSThorsten Schütt LLVMContext &Ctx = getContext(); 169*db8c84fcSThorsten Schütt 170*db8c84fcSThorsten Schütt switch (Opcode) { 171*db8c84fcSThorsten Schütt case TargetOpcode::G_ANYEXT: 172*db8c84fcSThorsten Schütt case TargetOpcode::G_ZEXT: 173*db8c84fcSThorsten Schütt return TLI.isZExtFree(FromTy, ToTy, DL, Ctx); 174*db8c84fcSThorsten Schütt case TargetOpcode::G_TRUNC: 175*db8c84fcSThorsten Schütt return TLI.isTruncateFree(FromTy, ToTy, DL, Ctx); 176*db8c84fcSThorsten Schütt default: 177*db8c84fcSThorsten Schütt return false; 178*db8c84fcSThorsten Schütt } 179*db8c84fcSThorsten Schütt } 180*db8c84fcSThorsten Schütt 181*db8c84fcSThorsten Schütt bool CombinerHelper::matchCastOfSelect(const MachineInstr &CastMI, 182*db8c84fcSThorsten Schütt const MachineInstr &SelectMI, 183*db8c84fcSThorsten Schütt BuildFnTy &MatchInfo) { 184*db8c84fcSThorsten Schütt const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI); 185*db8c84fcSThorsten Schütt const GSelect *Select = cast<GSelect>(&SelectMI); 186*db8c84fcSThorsten Schütt 187*db8c84fcSThorsten Schütt if (!MRI.hasOneNonDBGUse(Select->getReg(0))) 188*db8c84fcSThorsten Schütt return false; 189*db8c84fcSThorsten Schütt 190*db8c84fcSThorsten Schütt Register Dst = Cast->getReg(0); 191*db8c84fcSThorsten Schütt LLT DstTy = MRI.getType(Dst); 192*db8c84fcSThorsten Schütt LLT CondTy = MRI.getType(Select->getCondReg()); 193*db8c84fcSThorsten Schütt Register TrueReg = Select->getTrueReg(); 194*db8c84fcSThorsten Schütt Register FalseReg = Select->getFalseReg(); 195*db8c84fcSThorsten Schütt LLT SrcTy = MRI.getType(TrueReg); 196*db8c84fcSThorsten Schütt Register Cond = Select->getCondReg(); 197*db8c84fcSThorsten Schütt 198*db8c84fcSThorsten Schütt if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SELECT, {DstTy, CondTy}})) 199*db8c84fcSThorsten Schütt return false; 200*db8c84fcSThorsten Schütt 201*db8c84fcSThorsten Schütt if (!isCastFree(Cast->getOpcode(), DstTy, SrcTy)) 202*db8c84fcSThorsten Schütt return false; 203*db8c84fcSThorsten Schütt 204*db8c84fcSThorsten Schütt MatchInfo = [=](MachineIRBuilder &B) { 205*db8c84fcSThorsten Schütt auto True = B.buildInstr(Cast->getOpcode(), {DstTy}, {TrueReg}); 206*db8c84fcSThorsten Schütt auto False = B.buildInstr(Cast->getOpcode(), {DstTy}, {FalseReg}); 207*db8c84fcSThorsten Schütt B.buildSelect(Dst, Cond, True, False); 208*db8c84fcSThorsten Schütt }; 209*db8c84fcSThorsten Schütt 210*db8c84fcSThorsten Schütt return true; 211*db8c84fcSThorsten Schütt } 212