Index: include/llvm/CodeGen/GlobalISel/LegalizerHelper.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -93,6 +93,18 @@ const LegalizerInfo &getLegalizerInfo() const { return LI; } private: + /// Legalize a single operand \p OpIdx of the machine instruction \p MI as a + /// Use by extending the operand's type to \p WideTy using the specified \p + /// ExtOpcode for the extension instruction, and replacing the vreg of the + /// operand in place. + void widenScalarSrc(MachineInstr &MI, LLT WideTy, unsigned OpIdx, + unsigned ExtOpcode); + + /// Legalize a single operand \p OpIdx of the machine instruction \p MI as a + /// Def by extending the operand's type to \p WideTy and truncating it back + /// with the \p TruncOpcode, and replacing the vreg of the operand in place. + void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx = 0, + unsigned TruncOpcode = TargetOpcode::G_TRUNC); /// Helper function to split a wide generic register into bitwise blocks with /// the given Type (which implies the number of blocks needed). The generic Index: include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -154,6 +154,7 @@ /// \name Control where instructions we create are recorded (typically for /// visiting again later during legalization). /// @{ + void recordInsertion(MachineInstr *InsertedInstr) const; void recordInsertions(std::function InsertedInstr); void stopRecordingInsertions(); /// @} Index: include/llvm/CodeGen/MachineOperand.h =================================================================== --- include/llvm/CodeGen/MachineOperand.h +++ include/llvm/CodeGen/MachineOperand.h @@ -630,6 +630,11 @@ Contents.ImmVal = immVal; } + void setCImm(const ConstantInt *CI) { + assert(isCImm() && "Wrong MachineOperand mutator"); + Contents.CI = CI; + } + void setFPImm(const ConstantFP *CFP) { assert(isFPImm() && "Wrong MachineOperand mutator"); Contents.CFP = CFP; Index: lib/CodeGen/GlobalISel/LegalizerHelper.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -591,6 +591,23 @@ } } +void LegalizerHelper::widenScalarSrc(MachineInstr &MI, LLT WideTy, + unsigned OpIdx, unsigned ExtOpcode) { + MachineOperand &MO = MI.getOperand(OpIdx); + unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildInstr(ExtOpcode).addDef(SrcExt).addUse(MO.getReg()); + MO.setReg(SrcExt); +} + +void LegalizerHelper::widenScalarDst(MachineInstr &MI, LLT WideTy, + unsigned OpIdx, unsigned TruncOpcode) { + MachineOperand &MO = MI.getOperand(OpIdx); + unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt()); + MIRBuilder.buildInstr(TruncOpcode).addDef(MO.getReg()).addUse(DstExt); + MO.setReg(DstExt); +} + LegalizerHelper::LegalizeResult LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { MIRBuilder.setInstr(MI); @@ -598,140 +615,99 @@ switch (MI.getOpcode()) { default: return UnableToLegalize; + case TargetOpcode::G_ADD: case TargetOpcode::G_AND: case TargetOpcode::G_MUL: case TargetOpcode::G_OR: case TargetOpcode::G_XOR: case TargetOpcode::G_SUB: - case TargetOpcode::G_SHL: { // Perform operation at larger width (any extension is fine here, high bits // don't affect the result) and then truncate the result back to the // original type. - unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy); - unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg()); - MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg()); - - unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildInstr(MI.getOpcode()) - .addDef(DstExt) - .addUse(Src1Ext) - .addUse(Src2Ext); - - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); - MI.eraseFromParent(); + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT); + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; - } + + case TargetOpcode::G_SHL: + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT); + // The "number of bits to shift" operand must preserve its value as an + // unsigned integer: + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); + return Legalized; + case TargetOpcode::G_SDIV: - case TargetOpcode::G_UDIV: case TargetOpcode::G_SREM: - case TargetOpcode::G_UREM: + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT); + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); + return Legalized; + case TargetOpcode::G_ASHR: - case TargetOpcode::G_LSHR: { - unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV || - MI.getOpcode() == TargetOpcode::G_SREM || - MI.getOpcode() == TargetOpcode::G_ASHR - ? TargetOpcode::G_SEXT - : TargetOpcode::G_ZEXT; - - unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse( - MI.getOperand(1).getReg()); - - unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse( - MI.getOperand(2).getReg()); - - unsigned ResExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildInstr(MI.getOpcode()) - .addDef(ResExt) - .addUse(LHSExt) - .addUse(RHSExt); - - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt); - MI.eraseFromParent(); + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT); + // The "number of bits to shift" operand must preserve its value as an + // unsigned integer: + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; - } - case TargetOpcode::G_SELECT: { + + case TargetOpcode::G_UDIV: + case TargetOpcode::G_UREM: + case TargetOpcode::G_LSHR: + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT); + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); + return Legalized; + + case TargetOpcode::G_SELECT: if (TypeIdx != 0) return UnableToLegalize; - // Perform operation at larger width (any extension is fine here, high bits // don't affect the result) and then truncate the result back to the // original type. - unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy); - unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(2).getReg()); - MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(3).getReg()); - - unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildInstr(TargetOpcode::G_SELECT) - .addDef(DstExt) - .addReg(MI.getOperand(1).getReg()) - .addUse(Src1Ext) - .addUse(Src2Ext); - - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); - MI.eraseFromParent(); + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT); + widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; - } + case TargetOpcode::G_FPTOSI: - case TargetOpcode::G_FPTOUI: { + case TargetOpcode::G_FPTOUI: if (TypeIdx != 0) return UnableToLegalize; - - unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildInstr(MI.getOpcode()) - .addDef(DstExt) - .addUse(MI.getOperand(1).getReg()); - - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); - MI.eraseFromParent(); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; - } + case TargetOpcode::G_SITOFP: - case TargetOpcode::G_UITOFP: { if (TypeIdx != 1) return UnableToLegalize; + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT); + MIRBuilder.recordInsertion(&MI); + return Legalized; - unsigned Src = MI.getOperand(1).getReg(); - unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); - - if (MI.getOpcode() == TargetOpcode::G_SITOFP) { - MIRBuilder.buildSExt(SrcExt, Src); - } else { - assert(MI.getOpcode() == TargetOpcode::G_UITOFP && "Unexpected conv op"); - MIRBuilder.buildZExt(SrcExt, Src); - } - - MIRBuilder.buildInstr(MI.getOpcode()) - .addDef(MI.getOperand(0).getReg()) - .addUse(SrcExt); - - MI.eraseFromParent(); + case TargetOpcode::G_UITOFP: + if (TypeIdx != 1) + return UnableToLegalize; + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT); + MIRBuilder.recordInsertion(&MI); return Legalized; - } - case TargetOpcode::G_INSERT: { + + case TargetOpcode::G_INSERT: if (TypeIdx != 0) return UnableToLegalize; - - unsigned Src = MI.getOperand(1).getReg(); - unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildAnyExt(SrcExt, Src); - - unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); - auto MIB = MIRBuilder.buildInsert(DstExt, SrcExt, MI.getOperand(2).getReg(), - MI.getOperand(3).getImm()); - for (unsigned OpNum = 4; OpNum < MI.getNumOperands(); OpNum += 2) { - MIB.addReg(MI.getOperand(OpNum).getReg()); - MIB.addImm(MI.getOperand(OpNum + 1).getImm()); - } - - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); - MI.eraseFromParent(); + widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; - } + case TargetOpcode::G_LOAD: // For some types like i24, we might try to widen to i32. To properly handle // this we should be using a dedicated extending load, until then avoid @@ -741,164 +717,109 @@ return UnableToLegalize; LLVM_FALLTHROUGH; case TargetOpcode::G_SEXTLOAD: - case TargetOpcode::G_ZEXTLOAD: { - unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildLoadInstr(MI.getOpcode(), DstExt, MI.getOperand(1).getReg(), - **MI.memoperands_begin()); - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); - MI.eraseFromParent(); + case TargetOpcode::G_ZEXTLOAD: + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; - } + case TargetOpcode::G_STORE: { if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(1) || WideTy != LLT::scalar(8)) return UnableToLegalize; - auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); - auto Content = TLI.getBooleanContents(false, false); - - unsigned ExtOp = TargetOpcode::G_ANYEXT; - if (Content == TargetLoweringBase::ZeroOrOneBooleanContent) - ExtOp = TargetOpcode::G_ZEXT; - else if (Content == TargetLoweringBase::ZeroOrNegativeOneBooleanContent) - ExtOp = TargetOpcode::G_SEXT; - else - ExtOp = TargetOpcode::G_ANYEXT; - - unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildInstr(ExtOp).addDef(SrcExt).addUse( - MI.getOperand(0).getReg()); - MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(), - **MI.memoperands_begin()); - MI.eraseFromParent(); + const auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); + switch (TLI.getBooleanContents(false, false)) { + case TargetLoweringBase::ZeroOrNegativeOneBooleanContent: + widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_SEXT); + break; + case TargetLoweringBase::ZeroOrOneBooleanContent: + widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ZEXT); + break; + default: + widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT); + } + MIRBuilder.recordInsertion(&MI); return Legalized; } case TargetOpcode::G_CONSTANT: { - unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm()); - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); - MI.eraseFromParent(); + MachineOperand &SrcMO = MI.getOperand(1); + LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); + const APInt &Val = SrcMO.getCImm()->getValue().sext(WideTy.getSizeInBits()); + SrcMO.setCImm(ConstantInt::get(Ctx, Val)); + + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; } case TargetOpcode::G_FCONSTANT: { - const ConstantFP *CFP = MI.getOperand(1).getFPImm(); - APFloat Val = CFP->getValueAPF(); + MachineOperand &SrcMO = MI.getOperand(1); LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); - auto LLT2Sem = [](LLT Ty) { - switch (Ty.getSizeInBits()) { - case 32: - return &APFloat::IEEEsingle(); - break; - case 64: - return &APFloat::IEEEdouble(); - break; - default: - llvm_unreachable("Unhandled fp widen type"); - } - }; + APFloat Val = SrcMO.getFPImm()->getValueAPF(); bool LosesInfo; - Val.convert(*LLT2Sem(WideTy), APFloat::rmTowardZero, &LosesInfo); - auto Cst = MIRBuilder.buildFConstant(WideTy, *ConstantFP::get(Ctx, Val)); - MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), Cst); - MI.eraseFromParent(); + switch (WideTy.getSizeInBits()) { + case 32: + Val.convert(APFloat::IEEEsingle(), APFloat::rmTowardZero, &LosesInfo); + break; + case 64: + Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &LosesInfo); + break; + default: + llvm_unreachable("Unhandled fp widen type"); + } + SrcMO.setFPImm(ConstantFP::get(Ctx, Val)); + + widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC); + MIRBuilder.recordInsertion(&MI); return Legalized; } - case TargetOpcode::G_BRCOND: { - unsigned TstExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg()); - MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB()); - MI.eraseFromParent(); + case TargetOpcode::G_BRCOND: + widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT); + MIRBuilder.recordInsertion(&MI); return Legalized; - } - case TargetOpcode::G_FCMP: { - unsigned Op0Ext, Op1Ext, DstReg; - unsigned Cmp1 = MI.getOperand(2).getReg(); - unsigned Cmp2 = MI.getOperand(3).getReg(); - if (TypeIdx == 0) { - Op0Ext = Cmp1; - Op1Ext = Cmp2; - DstReg = MRI.createGenericVirtualRegister(WideTy); - } else { - Op0Ext = MRI.createGenericVirtualRegister(WideTy); - Op1Ext = MRI.createGenericVirtualRegister(WideTy); - DstReg = MI.getOperand(0).getReg(); - MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op0Ext, Cmp1); - MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op1Ext, Cmp2); - } - MIRBuilder.buildFCmp( - static_cast(MI.getOperand(1).getPredicate()), - DstReg, Op0Ext, Op1Ext); + + case TargetOpcode::G_FCMP: if (TypeIdx == 0) - MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(), - DstReg); - MI.eraseFromParent(); - return Legalized; - } - case TargetOpcode::G_ICMP: { - bool IsSigned = CmpInst::isSigned( - static_cast(MI.getOperand(1).getPredicate())); - unsigned Cmp1 = MI.getOperand(2).getReg(); - unsigned Cmp2 = MI.getOperand(3).getReg(); - unsigned Op0Ext, Op1Ext, DstReg; - if (TypeIdx == 0) { - Op0Ext = Cmp1; - Op1Ext = Cmp2; - DstReg = MRI.createGenericVirtualRegister(WideTy); - } else { - Op0Ext = MRI.createGenericVirtualRegister(WideTy); - Op1Ext = MRI.createGenericVirtualRegister(WideTy); - DstReg = MI.getOperand(0).getReg(); - if (IsSigned) { - MIRBuilder.buildSExt(Op0Ext, Cmp1); - MIRBuilder.buildSExt(Op1Ext, Cmp2); - } else { - MIRBuilder.buildZExt(Op0Ext, Cmp1); - MIRBuilder.buildZExt(Op1Ext, Cmp2); - } + widenScalarDst(MI, WideTy); + else { + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT); + widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_FPEXT); } - MIRBuilder.buildICmp( - static_cast(MI.getOperand(1).getPredicate()), - DstReg, Op0Ext, Op1Ext); + MIRBuilder.recordInsertion(&MI); + return Legalized; + + case TargetOpcode::G_ICMP: if (TypeIdx == 0) - MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(), - DstReg); - MI.eraseFromParent(); + widenScalarDst(MI, WideTy); + else { + unsigned ExtOpcode = CmpInst::isSigned(static_cast( + MI.getOperand(1).getPredicate())) + ? TargetOpcode::G_SEXT + : TargetOpcode::G_ZEXT; + widenScalarSrc(MI, WideTy, 2, ExtOpcode); + widenScalarSrc(MI, WideTy, 3, ExtOpcode); + } + MIRBuilder.recordInsertion(&MI); return Legalized; - } - case TargetOpcode::G_GEP: { + + case TargetOpcode::G_GEP: assert(TypeIdx == 1 && "unable to legalize pointer of GEP"); - unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy); - MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg()); - MI.getOperand(2).setReg(OffsetExt); + widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT); + MIRBuilder.recordInsertion(&MI); return Legalized; - } + case TargetOpcode::G_PHI: { assert(TypeIdx == 0 && "Expecting only Idx 0"); - auto getExtendedReg = [&](unsigned Reg, MachineBasicBlock &MBB) { - auto FirstTermIt = MBB.getFirstTerminator(); - MIRBuilder.setInsertPt(MBB, FirstTermIt); - MachineInstr *DefMI = MRI.getVRegDef(Reg); - MachineInstrBuilder MIB; - if (DefMI->getOpcode() == TargetOpcode::G_TRUNC) - MIB = MIRBuilder.buildAnyExtOrTrunc(WideTy, - DefMI->getOperand(1).getReg()); - else - MIB = MIRBuilder.buildAnyExt(WideTy, Reg); - return MIB->getOperand(0).getReg(); - }; - auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI, WideTy); - for (auto OpIt = MI.operands_begin() + 1, OpE = MI.operands_end(); - OpIt != OpE;) { - unsigned Reg = OpIt++->getReg(); - MachineBasicBlock *OpMBB = OpIt++->getMBB(); - MIB.addReg(getExtendedReg(Reg, *OpMBB)); - MIB.addMBB(OpMBB); + + for (unsigned I = 1; I < MI.getNumOperands(); I += 2) { + MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB(); + MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator()); + widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT); } - auto *MBB = MI.getParent(); - MIRBuilder.setInsertPt(*MBB, MBB->getFirstNonPHI()); - MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), - MIB->getOperand(0).getReg()); - MI.eraseFromParent(); + + MachineBasicBlock &MBB = *MI.getParent(); + MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI()); + widenScalarDst(MI, WideTy); + MIRBuilder.recordInsertion(&MI); return Legalized; } } Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -53,6 +53,11 @@ State.II = II; } +void MachineIRBuilderBase::recordInsertion(MachineInstr *InsertedInstr) const { + if (State.InsertedInstr) + State.InsertedInstr(InsertedInstr); +} + void MachineIRBuilderBase::recordInsertions( std::function Inserted) { State.InsertedInstr = std::move(Inserted); @@ -77,8 +82,7 @@ MachineInstrBuilder MachineIRBuilderBase::insertInstr(MachineInstrBuilder MIB) { getMBB().insert(getInsertPt(), MIB); - if (State.InsertedInstr) - State.InsertedInstr(MIB); + recordInsertion(MIB); return MIB; } Index: test/CodeGen/AArch64/GlobalISel/legalize-phi.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-phi.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-phi.mir @@ -1,4 +1,3 @@ -# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple=aarch64-unknown-unknown -global-isel -verify-machineinstrs -run-pass=legalizer %s -o - | FileCheck %s --- | ; ModuleID = '/tmp/test.ll' @@ -296,7 +295,7 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[C1]](s32) ; CHECK: bb.1: ; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000) - ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, %14(s16), %bb.1 + ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, [[TRUNC3:%[0-9]+]](s16), %bb.1 ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI]](s16) ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY [[C]](s32) ; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[ANYEXT]], [[COPY1]] @@ -306,7 +305,7 @@ ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C2]] ; CHECK: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[AND]](s32), [[COPY]] ; CHECK: [[TRUNC2:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP]](s32) - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s16) = G_TRUNC [[ADD]](s32) + ; CHECK: [[TRUNC3]]:_(s16) = G_TRUNC [[ADD]](s32) ; CHECK: G_BRCOND [[TRUNC2]](s1), %bb.1 ; CHECK: bb.2: ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 @@ -363,14 +362,14 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[C]](s32) ; CHECK: bb.1: ; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000) - ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, %8(s16), %bb.1 + ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC]](s16), %bb.0, [[COPY1:%[0-9]+]](s16), %bb.1 ; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[PHI]](s16) ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI]](s16) ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[ANYEXT]], [[C1]] ; CHECK: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[AND]](s32), [[COPY]] ; CHECK: [[TRUNC2:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP]](s32) - ; CHECK: [[COPY1:%[0-9]+]]:_(s16) = COPY [[PHI]](s16) + ; CHECK: [[COPY1]]:_(s16) = COPY [[PHI]](s16) ; CHECK: G_BRCOND [[TRUNC2]](s1), %bb.1 ; CHECK: bb.2: ; CHECK: $w0 = COPY [[AND]](s32) @@ -456,8 +455,8 @@ ; CHECK: [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI1]](s16) ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ANYEXT1]], [[C5]] - ; CHECK: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[C]]1, [[C]]2 - ; CHECK: $w0 = COPY [[C]]3(s32) + ; CHECK: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[AND]], [[AND1]] + ; CHECK: $w0 = COPY [[ADD2]](s32) ; CHECK: RET_ReallyLR implicit $w0 bb.0: successors: %bb.1(0x40000000), %bb.2(0x40000000) @@ -532,6 +531,7 @@ ; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000) ; CHECK: liveins: $w0, $w1 ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 3 ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 @@ -546,7 +546,7 @@ ; CHECK: G_BR %bb.2 ; CHECK: bb.1: ; CHECK: successors: %bb.2(0x40000000), %bb.1(0x40000000) - ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC2]](s16), %bb.0, [[C]]2(s16), %bb.1 + ; CHECK: [[PHI:%[0-9]+]]:_(s16) = G_PHI [[TRUNC2]](s16), %bb.0, [[TRUNC5:%[0-9]+]](s16), %bb.1 ; CHECK: [[TRUNC3:%[0-9]+]]:_(s8) = G_TRUNC [[PHI]](s16) ; CHECK: [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI]](s16) @@ -554,15 +554,15 @@ ; CHECK: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[AND]], [[C2]] ; CHECK: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(ugt), [[ADD1]](s32), [[C3]] ; CHECK: [[TRUNC4:%[0-9]+]]:_(s1) = G_TRUNC [[ICMP1]](s32) - ; CHECK: [[COPY1:%[0-9]+]]:_(s16) = COPY [[PHI]](s16) - ; CHECK: [[TRUNC5:%[0-9]+]]:_(s16) = G_TRUNC [[C4]](s32) + ; CHECK: [[COPY2:%[0-9]+]]:_(s16) = COPY [[PHI]](s16) + ; CHECK: [[TRUNC5]]:_(s16) = G_TRUNC [[C4]](s32) ; CHECK: G_BRCOND [[TRUNC4]](s1), %bb.2 ; CHECK: G_BR %bb.1 ; CHECK: bb.2: - ; CHECK: [[PHI1:%[0-9]+]]:_(s16) = G_PHI [[COPY1]](s16), %bb.1, [[TRUNC1]](s16), %bb.0 + ; CHECK: [[PHI1:%[0-9]+]]:_(s16) = G_PHI [[COPY2]](s16), %bb.1, [[TRUNC1]](s16), %bb.0 ; CHECK: [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[PHI1]](s16) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[C]]8, [[C]]7 + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[ANYEXT1]], [[C6]] ; CHECK: $w0 = COPY [[AND1]](s32) ; CHECK: RET_ReallyLR implicit $w0 bb.0: Index: test/CodeGen/AArch64/GlobalISel/legalize-shift.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-shift.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-shift.mir @@ -30,26 +30,27 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) ; CHECK: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[TRUNC]], [[C]] ; CHECK: [[ASHR:%[0-9]+]]:_(s32) = G_ASHR [[SHL]], [[C]] - ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 + ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC1]], [[C1]] - ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[SHL1]], [[C1]] - ; CHECK: [[ASHR2:%[0-9]+]]:_(s32) = G_ASHR [[ASHR]], [[ASHR1]] - ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[ASHR2]](s32) + ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[TRUNC1]], [[C1]] + ; CHECK: [[ASHR1:%[0-9]+]]:_(s32) = G_ASHR [[ASHR]], [[AND]] + ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[ASHR1]](s32) ; CHECK: $w0 = COPY [[COPY2]](s32) ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[TRUNC2]], [[C2]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC2]], [[C2]] ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[TRUNC3]], [[C3]] - ; CHECK: [[LSHR:%[0-9]+]]:_(s32) = G_LSHR [[AND]], [[AND1]] + ; CHECK: [[AND2:%[0-9]+]]:_(s32) = G_AND [[TRUNC3]], [[C3]] + ; CHECK: [[LSHR:%[0-9]+]]:_(s32) = G_LSHR [[AND1]], [[AND2]] ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY [[LSHR]](s32) ; CHECK: $w0 = COPY [[COPY3]](s32) ; CHECK: [[TRUNC4:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) + ; CHECK: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 255 ; CHECK: [[TRUNC5:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) - ; CHECK: [[SHL2:%[0-9]+]]:_(s32) = G_SHL [[COPY1]]0, [[COPY1]]1 - ; CHECK: [[COPY4:%[0-9]+]]:_(s32) = COPY [[COPY1]]2(s32) + ; CHECK: [[AND3:%[0-9]+]]:_(s32) = G_AND [[TRUNC5]], [[C4]] + ; CHECK: [[SHL1:%[0-9]+]]:_(s32) = G_SHL [[TRUNC4]], [[AND3]] + ; CHECK: [[COPY4:%[0-9]+]]:_(s32) = COPY [[SHL1]](s32) ; CHECK: $w0 = COPY [[COPY4]](s32) %0(s64) = COPY $x0 %1(s64) = COPY $x1 Index: test/CodeGen/X86/GlobalISel/ashr-scalar.ll =================================================================== --- test/CodeGen/X86/GlobalISel/ashr-scalar.ll +++ test/CodeGen/X86/GlobalISel/ashr-scalar.ll @@ -153,8 +153,7 @@ ; X64: # %bb.0: ; X64-NEXT: shlb $7, %dil ; X64-NEXT: sarb $7, %dil -; X64-NEXT: shlb $7, %sil -; X64-NEXT: sarb $7, %sil +; X64-NEXT: andb $1, %sil ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: sarb %cl, %dil ; X64-NEXT: movl %edi, %eax @@ -171,8 +170,7 @@ ; X64-NEXT: movb $-1, %cl ; X64-NEXT: shlb $7, %dil ; X64-NEXT: sarb $7, %dil -; X64-NEXT: shlb $7, %cl -; X64-NEXT: sarb $7, %cl +; X64-NEXT: andb $1, %cl ; X64-NEXT: sarb %cl, %dil ; X64-NEXT: movl %edi, %eax ; X64-NEXT: retq Index: test/CodeGen/X86/GlobalISel/shl-scalar-widening.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/shl-scalar-widening.ll @@ -0,0 +1,67 @@ +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=X64 + +define i16 @test_shl_i4(i16 %v, i16 %a, i16 %b) { +; Let's say the arguments are the following unsigned +; integers in two’s complement representation: +; +; %v: 77 (0000 0000 0100 1101) +; %a: 74 (0000 0000 0100 1010) +; %b: 72 (0000 0000 0100 1000) + %v.t = trunc i16 %v to i4 ; %v.t: 13 (1101) + %a.t = trunc i16 %a to i4 ; %a.t: 10 (1010) + %b.t = trunc i16 %b to i4 ; %b.t: 8 (1000) + %n.t = add i4 %a.t, %b.t ; %n.t: 2 (0010) + %r.t = shl i4 %v.t, %n.t ; %r.t: 4 (0100) + %r = zext i4 %r.t to i16 +; %r: 4 (0000 0000 0000 0100) + ret i16 %r + +; X64-LABEL: test_shl_i4 +; +; %di: 77 (0000 0000 0100 1101) +; %si: 74 (0000 0000 0100 1010) +; %dx: 72 (0000 0000 0100 1000) +; +; X64: # %bb.0: +; +; X64-NEXT: addb %sil, %dl +; %dx: 146 (0000 0000 1001 0010) +; +; X64-NEXT: andb $15, %dl +; %dx: 2 (0000 0000 0000 0010) +; +; X64-NEXT: movl %edx, %ecx +; %cx: 2 (0000 0000 0000 0010) +; +; X64-NEXT: shlb %cl, %dil +; %di: 52 (0000 0000 0011 0100) +; +; X64-NEXT: andw $15, %di +; %di: 4 (0000 0000 0000 0100) +; +; X64-NEXT: movl %edi, %eax +; %ax: 4 (0000 0000 0000 0100) +; +; X64-NEXT: retq +; +; Let's pretend that legalizing G_SHL by widening its second +; source operand is done via G_ANYEXT rather than G_ZEXT and +; see what happens: +; +; addb %sil, %dl +; %dx: 146 (0000 0000 1001 0010) +; +; movl %edx, %ecx +; %cx: 146 (0000 0000 1001 0010) +; +; shlb %cl, %dil +; %di: 0 (0000 0000 0000 0000) +; +; andw $15, %di +; %di: 0 (0000 0000 0000 0000) +; +; movl %edi, %eax +; %ax: 0 (0000 0000 0000 0000) +; +; retq +} Index: test/CodeGen/X86/GlobalISel/shl-scalar.ll =================================================================== --- test/CodeGen/X86/GlobalISel/shl-scalar.ll +++ test/CodeGen/X86/GlobalISel/shl-scalar.ll @@ -151,6 +151,7 @@ define i1 @test_shl_i1(i32 %arg1, i32 %arg2) { ; X64-LABEL: test_shl_i1: ; X64: # %bb.0: +; X64-NEXT: andb $1, %sil ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: shlb %cl, %dil ; X64-NEXT: movl %edi, %eax @@ -165,6 +166,7 @@ ; X64-LABEL: test_shl_i1_imm1: ; X64: # %bb.0: ; X64-NEXT: movb $-1, %cl +; X64-NEXT: andb $1, %cl ; X64-NEXT: shlb %cl, %dil ; X64-NEXT: movl %edi, %eax ; X64-NEXT: retq