Index: include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -735,6 +735,11 @@ MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef Ops); + /// Build and insert \p Res = G_BUILD_VECTOR with \p Src0 replicated to fill + /// the number of elements + MachineInstrBuilder buildSplatVector(const DstOp &Res, + const SrcOp &Src); + /// Build and insert \p Res = G_BUILD_VECTOR_TRUNC \p Op0, ... /// /// G_BUILD_VECTOR_TRUNC creates a vector value from multiple scalar registers Index: lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp +++ lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp @@ -192,8 +192,14 @@ MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res, const ConstantInt &Val) { constexpr unsigned Opc = TargetOpcode::G_CONSTANT; + LLT Ty = Res.getLLTTy(*getMRI()); // TODO: Handle vectors if (!canPerformCSEForOpc(Opc)) return MachineIRBuilder::buildConstant(Res, Val); + + // For vectors, CSE the element only for now. + if (Ty.isVector()) + return buildSplatVector(Res, buildConstant(Ty.getElementType(), Val)); + FoldingSetNodeID ID; GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); void *InsertPos = nullptr; @@ -205,6 +211,7 @@ // Handle generating copies here. return generateCopiesIfRequired({Res}, MIB); } + MachineInstrBuilder NewMIB = MachineIRBuilder::buildConstant(Res, Val); return memoizeMI(NewMIB, InsertPos); } @@ -212,8 +219,14 @@ MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res, const ConstantFP &Val) { constexpr unsigned Opc = TargetOpcode::G_FCONSTANT; + LLT Ty = Res.getLLTTy(*getMRI()); // TODO: Handle vectors if (!canPerformCSEForOpc(Opc)) return MachineIRBuilder::buildFConstant(Res, Val); + + // For vectors, CSE the element only for now. + if (Ty.isVector()) + return buildSplatVector(Res, buildFConstant(Ty.getElementType(), Val)); + FoldingSetNodeID ID; GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); void *InsertPos = nullptr; Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -307,38 +307,26 @@ const ConstantInt &Val) { LLT Ty = Res.getLLTTy(*getMRI()); LLT EltTy = Ty.getScalarType(); - - const ConstantInt *NewVal = &Val; - if (EltTy.getSizeInBits() != Val.getBitWidth()) { - NewVal = ConstantInt::get( - getMF().getFunction().getContext(), - Val.getValue().sextOrTrunc(EltTy.getSizeInBits())); - } + assert(EltTy.getScalarSizeInBits() == Val.getBitWidth() && + "creating constant with the wrong size"); if (Ty.isVector()) { - unsigned EltReg = getMRI()->createGenericVirtualRegister(EltTy); - buildInstr(TargetOpcode::G_CONSTANT) - .addDef(EltReg) - .addCImm(NewVal); - - auto MIB = buildInstr(TargetOpcode::G_BUILD_VECTOR); - Res.addDefToMIB(*getMRI(), MIB); - - for (unsigned I = 0, E = Ty.getNumElements(); I != E; ++I) - MIB.addUse(EltReg); - return MIB; + auto Const = buildInstr(TargetOpcode::G_CONSTANT) + .addDef(getMRI()->createGenericVirtualRegister(EltTy)) + .addCImm(&Val); + return buildSplatVector(Res, Const); } - auto MIB = buildInstr(TargetOpcode::G_CONSTANT); - Res.addDefToMIB(*getMRI(), MIB); - MIB.addCImm(NewVal); - return MIB; + auto Const = buildInstr(TargetOpcode::G_CONSTANT); + Res.addDefToMIB(*getMRI(), Const); + Const.addCImm(&Val); + return Const; } MachineInstrBuilder MachineIRBuilder::buildConstant(const DstOp &Res, int64_t Val) { auto IntN = IntegerType::get(getMF().getFunction().getContext(), - Res.getLLTTy(*getMRI()).getSizeInBits()); + Res.getLLTTy(*getMRI()).getScalarSizeInBits()); ConstantInt *CI = ConstantInt::get(IntN, Val, true); return buildConstant(Res, *CI); } @@ -352,28 +340,26 @@ MachineInstrBuilder MachineIRBuilder::buildFConstant(const DstOp &Res, const ConstantFP &Val) { LLT Ty = Res.getLLTTy(*getMRI()); + LLT EltTy = Ty.getScalarType(); + + assert(APFloat::getSizeInBits(Val.getValueAPF().getSemantics()) + == EltTy.getSizeInBits() && + "creating fconstant with the wrong size"); assert(!Ty.isPointer() && "invalid operand type"); if (Ty.isVector()) { - unsigned EltReg - = getMRI()->createGenericVirtualRegister(Ty.getElementType()); - buildInstr(TargetOpcode::G_FCONSTANT) - .addDef(EltReg) - .addFPImm(&Val); - - auto MIB = buildInstr(TargetOpcode::G_BUILD_VECTOR); - Res.addDefToMIB(*getMRI(), MIB); - - for (unsigned I = 0, E = Ty.getNumElements(); I != E; ++I) - MIB.addUse(EltReg); - return MIB; + auto Const = buildInstr(TargetOpcode::G_FCONSTANT) + .addDef(getMRI()->createGenericVirtualRegister(EltTy)) + .addFPImm(&Val); + + return buildSplatVector(Res, Const); } - auto MIB = buildInstr(TargetOpcode::G_FCONSTANT); - Res.addDefToMIB(*getMRI(), MIB); - MIB.addFPImm(&Val); - return MIB; + auto Const = buildInstr(TargetOpcode::G_FCONSTANT); + Res.addDefToMIB(*getMRI(), Const); + Const.addFPImm(&Val); + return Const; } MachineInstrBuilder MachineIRBuilder::buildFConstant(const DstOp &Res, @@ -381,7 +367,7 @@ LLT DstTy = Res.getLLTTy(*getMRI()); auto &Ctx = getMF().getFunction().getContext(); auto *CFP = - ConstantFP::get(Ctx, getAPFloatFromSize(Val, DstTy.getSizeInBits())); + ConstantFP::get(Ctx, getAPFloatFromSize(Val, DstTy.getScalarSizeInBits())); return buildFConstant(Res, *CFP); } @@ -626,6 +612,12 @@ return buildInstr(TargetOpcode::G_BUILD_VECTOR, Res, TmpVec); } +MachineInstrBuilder MachineIRBuilder::buildSplatVector(const DstOp &Res, + const SrcOp &Src) { + SmallVector TmpVec(Res.getLLTTy(*getMRI()).getNumElements(), Src); + return buildInstr(TargetOpcode::G_BUILD_VECTOR, Res, TmpVec); +} + MachineInstrBuilder MachineIRBuilder::buildBuildVectorTrunc(const DstOp &Res, ArrayRef Ops) { Index: unittests/CodeGen/GlobalISel/CSETest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/CSETest.cpp +++ unittests/CodeGen/GlobalISel/CSETest.cpp @@ -25,39 +25,53 @@ CSEInfo.analyze(*MF); B.setCSEInfo(&CSEInfo); CSEMIRBuilder CSEB(B.getState()); + CSEB.setInsertPt(*EntryMBB, EntryMBB->begin()); unsigned AddReg = MRI->createGenericVirtualRegister(s16); auto MIBAddCopy = CSEB.buildInstr(TargetOpcode::G_ADD, {AddReg}, {MIBInput, MIBInput}); - ASSERT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY); + EXPECT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY); auto MIBAdd2 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); - ASSERT_TRUE(&*MIBAdd == &*MIBAdd2); + EXPECT_TRUE(&*MIBAdd == &*MIBAdd2); auto MIBAdd4 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); - ASSERT_TRUE(&*MIBAdd == &*MIBAdd4); + EXPECT_TRUE(&*MIBAdd == &*MIBAdd4); auto MIBAdd5 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput1}); - ASSERT_TRUE(&*MIBAdd != &*MIBAdd5); + EXPECT_TRUE(&*MIBAdd != &*MIBAdd5); // Try building G_CONSTANTS. auto MIBCst = CSEB.buildConstant(s32, 0); auto MIBCst1 = CSEB.buildConstant(s32, 0); - ASSERT_TRUE(&*MIBCst == &*MIBCst1); + EXPECT_TRUE(&*MIBCst == &*MIBCst1); // Try the CFing of BinaryOps. auto MIBCF1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s32}, {MIBCst, MIBCst}); - ASSERT_TRUE(&*MIBCF1 == &*MIBCst); + EXPECT_TRUE(&*MIBCF1 == &*MIBCst); + // Try out building FCONSTANTs. auto MIBFP0 = CSEB.buildFConstant(s32, 1.0); auto MIBFP0_1 = CSEB.buildFConstant(s32, 1.0); - ASSERT_TRUE(&*MIBFP0 == &*MIBFP0_1); + EXPECT_TRUE(&*MIBFP0 == &*MIBFP0_1); CSEInfo.print(); + // Make sure buildConstant with a vector type doesn't crash, and the elements + // CSE. + auto Splat0 = CSEB.buildConstant(LLT::vector(2, s32), 0); + EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, Splat0->getOpcode()); + EXPECT_EQ(Splat0->getOperand(1).getReg(), Splat0->getOperand(2).getReg()); + EXPECT_EQ(&*MIBCst, MRI->getVRegDef(Splat0->getOperand(1).getReg())); + + auto FSplat = CSEB.buildFConstant(LLT::vector(2, s32), 1.0); + EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, FSplat->getOpcode()); + EXPECT_EQ(FSplat->getOperand(1).getReg(), FSplat->getOperand(2).getReg()); + EXPECT_EQ(&*MIBFP0, MRI->getVRegDef(FSplat->getOperand(1).getReg())); + // Check G_UNMERGE_VALUES auto MIBUnmerge = CSEB.buildUnmerge({s32, s32}, Copies[0]); auto MIBUnmerge2 = CSEB.buildUnmerge({s32, s32}, Copies[0]); - ASSERT_TRUE(&*MIBUnmerge == &*MIBUnmerge2); + EXPECT_TRUE(&*MIBUnmerge == &*MIBUnmerge2); } TEST_F(GISelMITest, TestCSEConstantConfig) { @@ -77,10 +91,10 @@ auto MIBAdd1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); // We should CSE constants only. Adds should not be CSEd. - ASSERT_TRUE(MIBAdd1->getOpcode() != TargetOpcode::COPY); - ASSERT_TRUE(&*MIBAdd1 != &*MIBAdd); + EXPECT_TRUE(MIBAdd1->getOpcode() != TargetOpcode::COPY); + EXPECT_TRUE(&*MIBAdd1 != &*MIBAdd); // We should CSE constant. auto MIBZeroTmp = CSEB.buildConstant(s16, 0); - ASSERT_TRUE(&*MIBZero == &*MIBZeroTmp); + EXPECT_TRUE(&*MIBZero == &*MIBZeroTmp); } } // namespace Index: unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp +++ unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp @@ -13,9 +13,6 @@ if (!TM) return; - MachineIRBuilder B(*MF); - B.setInsertPt(*EntryMBB, EntryMBB->begin()); - B.buildConstant(LLT::scalar(32), 42); B.buildFConstant(LLT::scalar(32), 1.0); @@ -27,10 +24,45 @@ CHECK: [[FCONST0:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+00 CHECK: [[CONST1:%[0-9]+]]:_(s32) = G_CONSTANT i32 99 CHECK: [[VEC0:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[CONST1]]:_(s32), [[CONST1]]:_(s32) - CHECK: [[FCONST1:%[0-9]+]]:_(s32) = G_FCONSTANT double 2.000000e+00 + CHECK: [[FCONST1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00 CHECK: [[VEC1:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[FCONST1]]:_(s32), [[FCONST1]]:_(s32) )"; ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } + + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG + +TEST_F(GISelMITest, TestBuildConstantFConstantDeath) { + if (!TM) + return; + + LLVMContext &Ctx = MF->getFunction().getContext(); + APInt APV32(32, 12345); + + // Test APInt version breaks + EXPECT_DEATH(B.buildConstant(LLT::scalar(16), APV32), + "creating constant with the wrong size"); + EXPECT_DEATH(B.buildConstant(LLT::vector(2, 16), APV32), + "creating constant with the wrong size"); + + // Test ConstantInt version breaks + ConstantInt *CI = ConstantInt::get(Ctx, APV32); + EXPECT_DEATH(B.buildConstant(LLT::scalar(16), *CI), + "creating constant with the wrong size"); + EXPECT_DEATH(B.buildConstant(LLT::vector(2, 16), *CI), + "creating constant with the wrong size"); + + APFloat DoubleVal(APFloat::IEEEdouble()); + ConstantFP *CF = ConstantFP::get(Ctx, DoubleVal); + EXPECT_DEATH(B.buildFConstant(LLT::scalar(16), *CF), + "creating fconstant with the wrong size"); + EXPECT_DEATH(B.buildFConstant(LLT::vector(2, 16), *CF), + "creating fconstant with the wrong size"); +} + +#endif +#endif