diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h --- a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h @@ -119,14 +119,16 @@ unsigned VReg; }; /// If \p VReg is defined by a statically evaluable chain of -/// instructions rooted on a G_CONSTANT (\p LookThroughInstrs == true) -/// and that constant fits in int64_t, returns its value as well as -/// the virtual register defined by this G_CONSTANT. -/// When \p LookThroughInstrs == false, this function behaves like +/// instructions rooted on a G_F/CONSTANT (\p LookThroughInstrs == true) +/// and that constant fits in int64_t, returns its value as well as the +/// virtual register defined by this G_F/CONSTANT. +/// When \p LookThroughInstrs == false this function behaves like /// getConstantVRegVal. +/// When \p HandleFConstants == false the function bails on G_FCONSTANTs. Optional getConstantVRegValWithLookThrough(unsigned VReg, const MachineRegisterInfo &MRI, - bool LookThroughInstrs = true); + bool LookThroughInstrs = true, + bool HandleFConstants = true); const ConstantFP* getConstantFPVRegVal(unsigned VReg, const MachineRegisterInfo &MRI); diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp --- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -216,11 +216,34 @@ } Optional llvm::getConstantVRegValWithLookThrough( - unsigned VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) { + unsigned VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs, + bool HandleFConstant) { SmallVector, 4> SeenOpcodes; MachineInstr *MI; - while ((MI = MRI.getVRegDef(VReg)) && - MI->getOpcode() != TargetOpcode::G_CONSTANT && LookThroughInstrs) { + auto IsConstantOpcode = [HandleFConstant](unsigned Opcode) { + return Opcode == TargetOpcode::G_CONSTANT || + (HandleFConstant && Opcode == TargetOpcode::G_FCONSTANT); + }; + auto GetImmediateValue = [HandleFConstant, + &MRI](const MachineInstr &MI) -> Optional { + const MachineOperand &CstVal = MI.getOperand(1); + if (!CstVal.isImm() && !CstVal.isCImm() && + (!HandleFConstant || !CstVal.isFPImm())) + return None; + if (!CstVal.isFPImm()) { + unsigned BitWidth = + MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); + APInt Val = CstVal.isImm() ? APInt(BitWidth, CstVal.getImm()) + : CstVal.getCImm()->getValue(); + assert(Val.getBitWidth() == BitWidth && + "Value bitwidth doesn't match definition type"); + return Val; + } else { + return CstVal.getFPImm()->getValueAPF().bitcastToAPInt(); + } + }; + while ((MI = MRI.getVRegDef(VReg)) && !IsConstantOpcode(MI->getOpcode()) && + LookThroughInstrs) { switch (MI->getOpcode()) { case TargetOpcode::G_TRUNC: case TargetOpcode::G_SEXT: @@ -242,16 +265,13 @@ return None; } } - if (!MI || MI->getOpcode() != TargetOpcode::G_CONSTANT || - (!MI->getOperand(1).isImm() && !MI->getOperand(1).isCImm())) + if (!MI || !IsConstantOpcode(MI->getOpcode())) return None; - const MachineOperand &CstVal = MI->getOperand(1); - unsigned BitWidth = MRI.getType(MI->getOperand(0).getReg()).getSizeInBits(); - APInt Val = CstVal.isImm() ? APInt(BitWidth, CstVal.getImm()) - : CstVal.getCImm()->getValue(); - assert(Val.getBitWidth() == BitWidth && - "Value bitwidth doesn't match definition type"); + Optional MaybeVal = GetImmediateValue(*MI); + if (!MaybeVal) + return None; + APInt &Val = *MaybeVal; while (!SeenOpcodes.empty()) { std::pair OpcodeAndSize = SeenOpcodes.pop_back_val(); switch (OpcodeAndSize.first) { diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-frint.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-frint.mir --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-frint.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-frint.mir @@ -56,18 +56,14 @@ ; SI-LABEL: name: test_frint_s64 ; SI: [[COPY:%[0-9]+]]:_(s64) = COPY $vgpr0_vgpr1 - ; SI: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 0x4330000000000000 - ; SI: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -9223372036854775808 - ; SI: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 9223372036854775807 - ; SI: [[AND:%[0-9]+]]:_(s64) = G_AND [[C]], [[C2]] - ; SI: [[AND1:%[0-9]+]]:_(s64) = G_AND [[C]], [[C1]] - ; SI: [[OR:%[0-9]+]]:_(s64) = G_OR [[AND]], [[AND1]] - ; SI: [[FADD:%[0-9]+]]:_(s64) = G_FADD [[COPY]], [[OR]] - ; SI: [[FNEG:%[0-9]+]]:_(s64) = G_FNEG [[OR]] + ; SI: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 4841369599423283200 + ; SI: [[COPY1:%[0-9]+]]:_(s64) = COPY [[C]](s64) + ; SI: [[FADD:%[0-9]+]]:_(s64) = G_FADD [[COPY]], [[COPY1]] + ; SI: [[FNEG:%[0-9]+]]:_(s64) = G_FNEG [[COPY1]] ; SI: [[FADD1:%[0-9]+]]:_(s64) = G_FADD [[FADD]], [[FNEG]] - ; SI: [[C3:%[0-9]+]]:_(s64) = G_FCONSTANT double 0x432FFFFFFFFFFFFF + ; SI: [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 0x432FFFFFFFFFFFFF ; SI: [[FABS:%[0-9]+]]:_(s64) = G_FABS [[COPY]] - ; SI: [[FCMP:%[0-9]+]]:_(s1) = G_FCMP floatpred(ogt), [[FABS]](s64), [[C3]] + ; SI: [[FCMP:%[0-9]+]]:_(s1) = G_FCMP floatpred(ogt), [[FABS]](s64), [[C1]] ; SI: [[SELECT:%[0-9]+]]:_(s64) = G_SELECT [[FCMP]](s1), [[COPY]], [[FADD1]] ; SI: [[FRINT:%[0-9]+]]:_(s64) = G_FRINT [[COPY]] ; SI: $vgpr0_vgpr1 = COPY [[FRINT]](s64) @@ -131,26 +127,22 @@ ; SI-LABEL: name: test_frint_v2s64 ; SI: [[COPY:%[0-9]+]]:_(<2 x s64>) = COPY $vgpr0_vgpr1_vgpr2_vgpr3 ; SI: [[UV:%[0-9]+]]:_(s64), [[UV1:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[COPY]](<2 x s64>) - ; SI: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 0x4330000000000000 - ; SI: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -9223372036854775808 - ; SI: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 9223372036854775807 - ; SI: [[AND:%[0-9]+]]:_(s64) = G_AND [[C]], [[C2]] - ; SI: [[AND1:%[0-9]+]]:_(s64) = G_AND [[C]], [[C1]] - ; SI: [[OR:%[0-9]+]]:_(s64) = G_OR [[AND]], [[AND1]] - ; SI: [[COPY1:%[0-9]+]]:_(s64) = COPY [[OR]](s64) + ; SI: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 4841369599423283200 + ; SI: [[COPY1:%[0-9]+]]:_(s64) = COPY [[C]](s64) ; SI: [[FADD:%[0-9]+]]:_(s64) = G_FADD [[UV]], [[COPY1]] ; SI: [[FNEG:%[0-9]+]]:_(s64) = G_FNEG [[COPY1]] ; SI: [[FADD1:%[0-9]+]]:_(s64) = G_FADD [[FADD]], [[FNEG]] - ; SI: [[C3:%[0-9]+]]:_(s64) = G_FCONSTANT double 0x432FFFFFFFFFFFFF + ; SI: [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 0x432FFFFFFFFFFFFF ; SI: [[FABS:%[0-9]+]]:_(s64) = G_FABS [[UV]] - ; SI: [[FCMP:%[0-9]+]]:_(s1) = G_FCMP floatpred(ogt), [[FABS]](s64), [[C3]] + ; SI: [[FCMP:%[0-9]+]]:_(s1) = G_FCMP floatpred(ogt), [[FABS]](s64), [[C1]] ; SI: [[SELECT:%[0-9]+]]:_(s64) = G_SELECT [[FCMP]](s1), [[UV]], [[FADD1]] ; SI: [[FRINT:%[0-9]+]]:_(s64) = G_FRINT [[UV]] - ; SI: [[FADD2:%[0-9]+]]:_(s64) = G_FADD [[UV1]], [[OR]] - ; SI: [[FNEG1:%[0-9]+]]:_(s64) = G_FNEG [[OR]] + ; SI: [[COPY2:%[0-9]+]]:_(s64) = COPY [[C]](s64) + ; SI: [[FADD2:%[0-9]+]]:_(s64) = G_FADD [[UV1]], [[COPY2]] + ; SI: [[FNEG1:%[0-9]+]]:_(s64) = G_FNEG [[COPY2]] ; SI: [[FADD3:%[0-9]+]]:_(s64) = G_FADD [[FADD2]], [[FNEG1]] ; SI: [[FABS1:%[0-9]+]]:_(s64) = G_FABS [[UV1]] - ; SI: [[FCMP1:%[0-9]+]]:_(s1) = G_FCMP floatpred(ogt), [[FABS1]](s64), [[C3]] + ; SI: [[FCMP1:%[0-9]+]]:_(s1) = G_FCMP floatpred(ogt), [[FABS1]](s64), [[C1]] ; SI: [[SELECT:%[0-9]+]]:_(s64) = G_SELECT [[FCMP1]](s1), [[UV1]], [[FADD3]] ; SI: [[FRINT1:%[0-9]+]]:_(s64) = G_FRINT [[UV1]] ; SI: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x s64>) = G_BUILD_VECTOR [[FRINT]](s64), [[FRINT1]](s64) diff --git a/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp b/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp @@ -68,4 +68,172 @@ EXPECT_EQ(-0x80, Cst); } +TEST_F(GISelMITest, FoldBinOp) { + setUp(); + if (!TM) + return; + + LLT s32{LLT::scalar(32)}; + auto MIBCst1 = B.buildConstant(s32, 16); + auto MIBCst2 = B.buildConstant(s32, 9); + auto MIBFCst1 = B.buildFConstant(s32, 1.0000001); + auto MIBFCst2 = B.buildFConstant(s32, 2.0); + + // Test G_ADD folding Integer + Mixed Int-Float cases + Optional FoldGAddInt = + ConstantFoldBinOp(TargetOpcode::G_ADD, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGAddInt.hasValue()); + EXPECT_EQ(25ULL, FoldGAddInt.getValue().getLimitedValue()); + Optional FoldGAddMix = + ConstantFoldBinOp(TargetOpcode::G_ADD, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGAddMix.hasValue()); + EXPECT_EQ(1073741840ULL, FoldGAddMix.getValue().getLimitedValue()); + + // Test G_AND folding Integer + Mixed Int-Float cases + Optional FoldGAndInt = + ConstantFoldBinOp(TargetOpcode::G_AND, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGAndInt.hasValue()); + EXPECT_EQ(0ULL, FoldGAndInt.getValue().getLimitedValue()); + Optional FoldGAndMix = + ConstantFoldBinOp(TargetOpcode::G_AND, MIBCst2->getOperand(0).getReg(), + MIBFCst1->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGAndMix.hasValue()); + EXPECT_EQ(1ULL, FoldGAndMix.getValue().getLimitedValue()); + + // Test G_ASHR folding Integer + Mixed cases + Optional FoldGAShrInt = + ConstantFoldBinOp(TargetOpcode::G_ASHR, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGAShrInt.hasValue()); + EXPECT_EQ(0ULL, FoldGAShrInt.getValue().getLimitedValue()); + Optional FoldGAShrMix = + ConstantFoldBinOp(TargetOpcode::G_ASHR, MIBFCst2->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGAShrMix.hasValue()); + EXPECT_EQ(2097152ULL, FoldGAShrMix.getValue().getLimitedValue()); + + // Test G_LSHR folding Integer + Mixed Int-Float cases + Optional FoldGLShrInt = + ConstantFoldBinOp(TargetOpcode::G_LSHR, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGLShrInt.hasValue()); + EXPECT_EQ(0ULL, FoldGLShrInt.getValue().getLimitedValue()); + Optional FoldGLShrMix = + ConstantFoldBinOp(TargetOpcode::G_LSHR, MIBFCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGLShrMix.hasValue()); + EXPECT_EQ(2080768ULL, FoldGLShrMix.getValue().getLimitedValue()); + + // Test G_MUL folding Integer + Mixed Int-Float cases + Optional FoldGMulInt = + ConstantFoldBinOp(TargetOpcode::G_MUL, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGMulInt.hasValue()); + EXPECT_EQ(144ULL, FoldGMulInt.getValue().getLimitedValue()); + Optional FoldGMulMix = + ConstantFoldBinOp(TargetOpcode::G_MUL, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGMulMix.hasValue()); + EXPECT_EQ(0ULL, FoldGMulMix.getValue().getLimitedValue()); + + // Test G_OR folding Integer + Mixed Int-Float cases + Optional FoldGOrInt = + ConstantFoldBinOp(TargetOpcode::G_OR, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGOrInt.hasValue()); + EXPECT_EQ(25ULL, FoldGOrInt.getValue().getLimitedValue()); + Optional FoldGOrMix = + ConstantFoldBinOp(TargetOpcode::G_OR, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGOrMix.hasValue()); + EXPECT_EQ(1073741840ULL, FoldGOrMix.getValue().getLimitedValue()); + + // Test G_SHL folding Integer + Mixed Int-Float cases + Optional FoldGShlInt = + ConstantFoldBinOp(TargetOpcode::G_SHL, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGShlInt.hasValue()); + EXPECT_EQ(8192ULL, FoldGShlInt.getValue().getLimitedValue()); + Optional FoldGShlMix = + ConstantFoldBinOp(TargetOpcode::G_SHL, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGShlMix.hasValue()); + EXPECT_EQ(0ULL, FoldGShlMix.getValue().getLimitedValue()); + + // Test G_SUB folding Integer + Mixed Int-Float cases + Optional FoldGSubInt = + ConstantFoldBinOp(TargetOpcode::G_SUB, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGSubInt.hasValue()); + EXPECT_EQ(7ULL, FoldGSubInt.getValue().getLimitedValue()); + Optional FoldGSubMix = + ConstantFoldBinOp(TargetOpcode::G_SUB, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGSubMix.hasValue()); + EXPECT_EQ(3221225488ULL, FoldGSubMix.getValue().getLimitedValue()); + + // Test G_XOR folding Integer + Mixed Int-Float cases + Optional FoldGXorInt = + ConstantFoldBinOp(TargetOpcode::G_XOR, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGXorInt.hasValue()); + EXPECT_EQ(25ULL, FoldGXorInt.getValue().getLimitedValue()); + Optional FoldGXorMix = + ConstantFoldBinOp(TargetOpcode::G_XOR, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGXorMix.hasValue()); + EXPECT_EQ(1073741840ULL, FoldGXorMix.getValue().getLimitedValue()); + + // Test G_UDIV folding Integer + Mixed Int-Float cases + Optional FoldGUdivInt = + ConstantFoldBinOp(TargetOpcode::G_UDIV, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGUdivInt.hasValue()); + EXPECT_EQ(1ULL, FoldGUdivInt.getValue().getLimitedValue()); + Optional FoldGUdivMix = + ConstantFoldBinOp(TargetOpcode::G_UDIV, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGUdivMix.hasValue()); + EXPECT_EQ(0ULL, FoldGUdivMix.getValue().getLimitedValue()); + + // Test G_SDIV folding Integer + Mixed Int-Float cases + Optional FoldGSdivInt = + ConstantFoldBinOp(TargetOpcode::G_SDIV, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGSdivInt.hasValue()); + EXPECT_EQ(1ULL, FoldGSdivInt.getValue().getLimitedValue()); + Optional FoldGSdivMix = + ConstantFoldBinOp(TargetOpcode::G_SDIV, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGSdivMix.hasValue()); + EXPECT_EQ(0ULL, FoldGSdivMix.getValue().getLimitedValue()); + + // Test G_UREM folding Integer + Mixed Int-Float cases + Optional FoldGUremInt = + ConstantFoldBinOp(TargetOpcode::G_UDIV, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGUremInt.hasValue()); + EXPECT_EQ(1ULL, FoldGUremInt.getValue().getLimitedValue()); + Optional FoldGUremMix = + ConstantFoldBinOp(TargetOpcode::G_UDIV, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGUremMix.hasValue()); + EXPECT_EQ(0ULL, FoldGUremMix.getValue().getLimitedValue()); + + // Test G_SREM folding Integer + Mixed Int-Float cases + Optional FoldGSremInt = + ConstantFoldBinOp(TargetOpcode::G_SREM, MIBCst1->getOperand(0).getReg(), + MIBCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGSremInt.hasValue()); + EXPECT_EQ(7ULL, FoldGSremInt.getValue().getLimitedValue()); + Optional FoldGSremMix = + ConstantFoldBinOp(TargetOpcode::G_SREM, MIBCst1->getOperand(0).getReg(), + MIBFCst2->getOperand(0).getReg(), *MRI); + EXPECT_TRUE(FoldGSremMix.hasValue()); + EXPECT_EQ(16ULL, FoldGSremMix.getValue().getLimitedValue()); +} + } // namespace \ No newline at end of file