Index: llvm/include/llvm/AsmParser/LLToken.h =================================================================== --- llvm/include/llvm/AsmParser/LLToken.h +++ llvm/include/llvm/AsmParser/LLToken.h @@ -110,6 +110,7 @@ kw_nsw, kw_exact, kw_inbounds, + kw_was_sext, kw_inrange, kw_addrspace, kw_section, Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -505,6 +505,10 @@ AllowReassoc = (1 << 7) }; +/// WSXTOperatorOptionalFlags - Flags for serializing +/// WSXTOperator's SubclassOptionalData contents. +enum WSXTOperatorOptionalFlags { WSXTO_WAS_SEXT = 0 }; + /// PossiblyExactOperatorOptionalFlags - Flags for serializing /// PossiblyExactOperator's SubclassOptionalData contents. enum PossiblyExactOperatorOptionalFlags { PEO_EXACT = 0 }; Index: llvm/include/llvm/IR/Constants.h =================================================================== --- llvm/include/llvm/IR/Constants.h +++ llvm/include/llvm/IR/Constants.h @@ -1056,7 +1056,8 @@ static Constant *getAShr(Constant *C1, Constant *C2, bool isExact = false); static Constant *getTrunc(Constant *C, Type *Ty, bool OnlyIfReduced = false); static Constant *getSExt(Constant *C, Type *Ty, bool OnlyIfReduced = false); - static Constant *getZExt(Constant *C, Type *Ty, bool OnlyIfReduced = false); + static Constant *getZExt(Constant *C, Type *Ty, bool OnlyIfReduced = false, + bool WasSext = false); static Constant *getFPTrunc(Constant *C, Type *Ty, bool OnlyIfReduced = false); static Constant *getFPExtend(Constant *C, Type *Ty, Index: llvm/include/llvm/IR/Instruction.h =================================================================== --- llvm/include/llvm/IR/Instruction.h +++ llvm/include/llvm/IR/Instruction.h @@ -369,12 +369,19 @@ /// which supports this flag. See LangRef.html for the meaning of this flag. void setIsExact(bool b = true); + /// Set or clear the sext flag on this instruction, which must be an operator + /// which supports this flag. In our case WSXTOperator defined in Operator.h. + void setWasSext(bool b = true); + /// Determine whether the no unsigned wrap flag is set. bool hasNoUnsignedWrap() const LLVM_READONLY; /// Determine whether the no signed wrap flag is set. bool hasNoSignedWrap() const LLVM_READONLY; + /// Determine whether the sext flag is set. + bool wasSext() const LLVM_READONLY; + /// Return true if this operator has flags which may cause this instruction /// to evaluate to poison despite having non-poison inputs. bool hasPoisonGeneratingFlags() const LLVM_READONLY; Index: llvm/include/llvm/IR/Operator.h =================================================================== --- llvm/include/llvm/IR/Operator.h +++ llvm/include/llvm/IR/Operator.h @@ -331,6 +331,36 @@ } }; +/// An utility class for the zext instructions that were +/// created by a conversion from sext instructions. +class WSXTOperator : public Operator { +public: + enum { WasSext = (1 << 0) }; + +private: + friend class Instruction; + friend class ConstantExpr; + + void setWasSext(bool B) { + SubclassOptionalData = (SubclassOptionalData & ~WasSext) | (B * WasSext); + } + +public: + /// + bool wasSext() const { return (SubclassOptionalData & WasSext) != 0; } + + static bool classof(const Instruction *I) { + return I->getOpcode() == Instruction::ZExt; + } + static bool classof(const ConstantExpr *CE) { + return CE->getOpcode() == Instruction::ZExt; + } + static bool classof(const Value *V) { + return (isa(V) && classof(cast(V))) || + (isa(V) && classof(cast(V))); + } +}; + /// A helper template for defining operators for individual opcodes. template class ConcreteOperator : public SuperClass { @@ -373,7 +403,8 @@ : public ConcreteOperator { }; -class ZExtOperator : public ConcreteOperator {}; +class ZExtOperator : public ConcreteOperator { +}; class GEPOperator : public ConcreteOperator { Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -564,6 +564,7 @@ KEYWORD(fast); KEYWORD(nuw); KEYWORD(nsw); + KEYWORD(was_sext); KEYWORD(exact); KEYWORD(inbounds); KEYWORD(inrange); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -3740,9 +3740,14 @@ case lltok::kw_inttoptr: case lltok::kw_ptrtoint: { unsigned Opc = Lex.getUIntVal(); + bool WasSext = false; Type *DestTy = nullptr; Constant *SrcVal; Lex.Lex(); + if (Opc == Instruction::ZExt) { + if (EatIfPresent(lltok::kw_was_sext)) + WasSext = true; + } if (parseToken(lltok::lparen, "expected '(' after constantexpr cast") || parseGlobalTypeAndValue(SrcVal) || parseToken(lltok::kw_to, "expected 'to' in constantexpr cast") || @@ -3753,9 +3758,17 @@ return error(ID.Loc, "invalid cast opcode for cast from '" + getTypeString(SrcVal->getType()) + "' to '" + getTypeString(DestTy) + "'"); - ID.ConstantVal = ConstantExpr::getCast((Instruction::CastOps)Opc, - SrcVal, DestTy); + ID.Kind = ValID::t_Constant; + if (WasSext) { + ID.ConstantVal = + ConstantExpr::getZExt(SrcVal, DestTy, + /* OnlyIfReduced */ false, /* WasSext */ true); + + } else { + ID.ConstantVal = + ConstantExpr::getCast((Instruction::CastOps)Opc, SrcVal, DestTy); + } return false; } case lltok::kw_extractvalue: @@ -6339,6 +6352,7 @@ if (parseArithmetic(Inst, PFS, KeywordVal, /*IsFP*/ false)) return true; + if (Exact) cast(Inst)->setIsExact(true); return false; } @@ -6364,8 +6378,17 @@ } // Casts. + case lltok::kw_zext: { + bool WasSext = EatIfPresent(lltok::kw_was_sext); + bool Res = parseCast(Inst, PFS, KeywordVal); + if (Res != 0) { + return Res; + } + if (WasSext == true) + Inst->setWasSext(true); + return 0; + } case lltok::kw_trunc: - case lltok::kw_zext: case lltok::kw_sext: case lltok::kw_fptrunc: case lltok::kw_fpext: Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1469,7 +1469,7 @@ // Materialize as constant expression if possible. if (isConstExprSupported(BC->Opcode) && ConstOps.size() == Ops.size()) { Constant *C; - if (Instruction::isCast(BC->Opcode)) { + if (Instruction::isCast(BC->Opcode)) { // TODO C = UpgradeBitCastExpr(BC->Opcode, ConstOps[0], BC->getType()); if (!C) C = ConstantExpr::getCast(BC->Opcode, ConstOps[0], BC->getType()); @@ -1582,6 +1582,9 @@ if (Instruction::isCast(BC->Opcode)) { I = CastInst::Create((Instruction::CastOps)BC->Opcode, Ops[0], BC->getType(), "constexpr", InsertBB); + if (isa(I) && (BC->Flags & WSXTOperator::WasSext)) + I->setWasSext(true); + } else if (Instruction::isUnaryOp(BC->Opcode)) { I = UnaryOperator::Create((Instruction::UnaryOps)BC->Opcode, Ops[0], "constexpr", InsertBB); @@ -3210,18 +3213,25 @@ } break; } - case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] + case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] #TODO if (Record.size() < 3) return error("Invalid cast constexpr record"); int Opc = getDecodedCastOpcode(Record[0]); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown cast. } else { + uint8_t Flags = 0; + if (Record.size() >= 4) { + if (Record[3] & (1 << bitc::WSXTO_WAS_SEXT)) { + Flags |= WSXTOperator::WasSext; + } + } unsigned OpTyID = Record[1]; Type *OpTy = getTypeByID(OpTyID); if (!OpTy) return error("Invalid cast constexpr record"); - V = BitcodeConstant::create(Alloc, CurTy, Opc, (unsigned)Record[2]); + V = BitcodeConstant::create(Alloc, CurTy, {(uint8_t)Opc, Flags}, + (unsigned)Record[2]); } break; } @@ -4861,18 +4871,14 @@ ResTypeID = TypeID; InstructionList.push_back(I); if (OpNum < Record.size()) { - if (Opc == Instruction::Add || - Opc == Instruction::Sub || - Opc == Instruction::Mul || - Opc == Instruction::Shl) { - if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) - cast(I)->setHasNoSignedWrap(true); + if (Opc == Instruction::Add || Opc == Instruction::Sub || + Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) cast(I)->setHasNoUnsignedWrap(true); - } else if (Opc == Instruction::SDiv || - Opc == Instruction::UDiv || - Opc == Instruction::LShr || - Opc == Instruction::AShr) { + if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) + cast(I)->setHasNoSignedWrap(true); + } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || + Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(I)) { @@ -4880,21 +4886,22 @@ if (FMF.any()) I->setFastMathFlags(FMF); } - } break; } - case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] + case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] + // #TODO unsigned OpNum = 0; Value *Op; unsigned OpTypeID; if (getValueTypePair(Record, OpNum, NextValueNo, Op, OpTypeID, CurBB) || - OpNum+2 != Record.size()) + OpNum + 1 > Record.size()) return error("Invalid record"); - ResTypeID = Record[OpNum]; + ResTypeID = Record[OpNum++]; Type *ResTy = getTypeByID(ResTypeID); - int Opc = getDecodedCastOpcode(Record[OpNum + 1]); + int Opc = getDecodedCastOpcode(Record[OpNum++]); + if (Opc == -1 || !ResTy) return error("Invalid record"); Instruction *Temp = nullptr; @@ -4906,10 +4913,19 @@ } } else { auto CastOp = (Instruction::CastOps)Opc; + if (!CastInst::castIsValid(CastOp, Op, ResTy)) return error("Invalid cast"); I = CastInst::Create(CastOp, Op, ResTy); } + if (OpNum < Record.size()) { + if (isa(I)) { + if ((Record[OpNum] & (1 << bitc::WSXTO_WAS_SEXT))) { + cast(I)->setWasSext(true); + } + } + } + InstructionList.push_back(I); break; } @@ -6401,7 +6417,7 @@ if (Error Err = propagateAttributeTypes(cast(I), ArgTyIDs)) { I->deleteValue(); return Err; - } + } // CHECK FOR ZEXT FLAG possible on call? if (FMF.any()) { if (!isa(I)) return error("Fast-math-flags specified for call without " Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -102,7 +102,8 @@ namespace { /// These are manifest constants used by the bitcode writer. They do not need to -/// be kept in sync with the reader, but need to be consistent within this file. +/// // TODO add zext be kept in sync with the reader, but need to be consistent +/// within this file. enum { // VALUE_SYMTAB_BLOCK abbrev id's. VST_ENTRY_8_ABBREV = bitc::FIRST_APPLICATION_ABBREV, @@ -114,6 +115,7 @@ CONSTANTS_SETTYPE_ABBREV = bitc::FIRST_APPLICATION_ABBREV, CONSTANTS_INTEGER_ABBREV, CONSTANTS_CE_CAST_Abbrev, + CONSTANTS_CE_CAST_FLAGS_ABBREV, CONSTANTS_NULL_Abbrev, // FUNCTION_BLOCK abbrev id's. @@ -123,6 +125,7 @@ FUNCTION_INST_BINOP_ABBREV, FUNCTION_INST_BINOP_FLAGS_ABBREV, FUNCTION_INST_CAST_ABBREV, + FUNCTION_INST_CAST_FLAGS_ABBREV, FUNCTION_INST_RET_VOID_ABBREV, FUNCTION_INST_RET_VAL_ABBREV, FUNCTION_INST_UNREACHABLE_ABBREV, @@ -1551,8 +1554,11 @@ Flags |= bitc::AllowContract; if (FPMO->hasApproxFunc()) Flags |= bitc::ApproxFunc; + } else if (const auto *WSXTO = dyn_cast(V)) { + if (WSXTO->wasSext()) { + Flags |= 1 << bitc::WSXTO_WAS_SEXT; + } } - return Flags; } @@ -2647,6 +2653,11 @@ Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); Record.push_back(VE.getValueID(C->getOperand(0))); AbbrevToUse = CONSTANTS_CE_CAST_Abbrev; + uint64_t Flags = getOptimizationFlags(CE); + if (Flags != 0) { + AbbrevToUse = CONSTANTS_CE_CAST_FLAGS_ABBREV; + Record.push_back(Flags); + } } else { assert(CE->getNumOperands() == 2 && "Unknown constant expr!"); Code = bitc::CST_CODE_CE_BINOP; @@ -2833,6 +2844,12 @@ AbbrevToUse = FUNCTION_INST_CAST_ABBREV; Vals.push_back(VE.getTypeID(I.getType())); Vals.push_back(getEncodedCastOpcode(I.getOpcode())); + uint64_t Flags = getOptimizationFlags(&I); + if (Flags != 0) { + if (AbbrevToUse == FUNCTION_INST_CAST_ABBREV) + AbbrevToUse = FUNCTION_INST_CAST_FLAGS_ABBREV; + Vals.push_back(Flags); + } } else { assert(isa(I) && "Unknown instruction!"); Code = bitc::FUNC_CODE_INST_BINOP; @@ -3568,6 +3585,17 @@ CONSTANTS_INTEGER_ABBREV) llvm_unreachable("Unexpected abbrev ordering!"); } + { // CE_CAST abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CE_CAST)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // cast opc + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // typeid + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, Abbv) != + CONSTANTS_CE_CAST_Abbrev) + llvm_unreachable("Unexpected abbrev ordering!"); + } { // CE_CAST abbrev for CONSTANTS_BLOCK. auto Abbv = std::make_shared(); @@ -3576,9 +3604,10 @@ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // typeid VE.computeBitsRequiredForTypeIndicies())); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // flags if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, Abbv) != - CONSTANTS_CE_CAST_Abbrev) + CONSTANTS_CE_CAST_FLAGS_ABBREV) llvm_unreachable("Unexpected abbrev ordering!"); } { // NULL abbrev for CONSTANTS_BLOCK. @@ -3643,7 +3672,7 @@ FUNCTION_INST_BINOP_FLAGS_ABBREV) llvm_unreachable("Unexpected abbrev ordering!"); } - { // INST_CAST abbrev for FUNCTION_BLOCK. + { // INST_CAST abbrev for FUNCTION_BLOCK. TODO possible zext flag auto Abbv = std::make_shared(); Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_CAST)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpVal @@ -3654,6 +3683,18 @@ FUNCTION_INST_CAST_ABBREV) llvm_unreachable("Unexpected abbrev ordering!"); } + { // INST_CAST FLAGS abbrev for FUNCTION_BLOCK. TODO possible zext flag + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_CAST)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpVal + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // flags + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, Abbv) != + FUNCTION_INST_CAST_FLAGS_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } { // INST_RET abbrev for FUNCTION_BLOCK. auto Abbv = std::make_shared(); Index: llvm/lib/Bitcode/flags.ll =================================================================== --- /dev/null +++ llvm/lib/Bitcode/flags.ll @@ -0,0 +1,30 @@ +; RUN: llvm-as < %s | llvm-dis > %t0 +; RUN: opt -S < %s > %t1 +; RUN: diff %t0 %t1 +; RUN: verify-uselistorder < %s +; PR6140 + +; Make sure the flags are serialized/deserialized properly for both +; forward and backward references. + +define void @foo() nounwind { +entry: + br label %first + +second: ; preds = %first + %u = add nuw i32 %a, 0 ; [#uses=0] + %s = add nsw i32 %a, 0 ; [#uses=0] + %us = add nuw nsw i32 %a, 0 ; [#uses=0] + %z = add i32 %a, 0 ; [#uses=0] + %hh = zext i32 %a to i64 ; [#uses=0] + unreachable + +first: ; preds = %entry + %a = bitcast i32 0 to i32 ; [#uses=8] + %uu = add nuw i32 %a, 0 ; [#uses=0] + %ss = add nsw i32 %a, 0 ; [#uses=0] + %uuss = add nuw nsw i32 %a, 0 ; [#uses=0] + %zz = add i32 %a, 0 ; [#uses=0] + %kk = zext was_sext i32 %a to i64 ; [#uses=0] + br label %second +} Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -1343,6 +1343,9 @@ } else if (const GEPOperator *GEP = dyn_cast(U)) { if (GEP->isInBounds()) Out << " inbounds"; + } else if (const WSXTOperator *WSXTO = dyn_cast(U)) { + if (WSXTO->wasSext()) + Out << " was_sext"; } } Index: llvm/lib/IR/Constants.cpp =================================================================== --- llvm/lib/IR/Constants.cpp +++ llvm/lib/IR/Constants.cpp @@ -1953,7 +1953,8 @@ /// This is a utility function to handle folding of casts and lookup of the /// cast in the ExprConstants map. It is used by the various get* methods below. static Constant *getFoldedCast(Instruction::CastOps opc, Constant *C, Type *Ty, - bool OnlyIfReduced = false) { + bool OnlyIfReduced = false, + bool WasSext = false) { assert(Ty->isFirstClassType() && "Cannot cast to an aggregate type!"); // Fold a few common cases if (Constant *FC = ConstantFoldCastInstruction(opc, C, Ty)) @@ -1965,7 +1966,7 @@ LLVMContextImpl *pImpl = Ty->getContext().pImpl; // Look up the constant in the table first to ensure uniqueness. - ConstantExprKeyType Key(opc, C); + ConstantExprKeyType Key(opc, C, 0, WasSext); return pImpl->ExprConstants.getOrCreate(Ty, Key); } @@ -2116,7 +2117,8 @@ return getFoldedCast(Instruction::SExt, C, Ty, OnlyIfReduced); } -Constant *ConstantExpr::getZExt(Constant *C, Type *Ty, bool OnlyIfReduced) { +Constant *ConstantExpr::getZExt(Constant *C, Type *Ty, bool OnlyIfReduced, + bool WasSext) { #ifndef NDEBUG bool fromVec = isa(C->getType()); bool toVec = isa(Ty); @@ -2127,7 +2129,7 @@ assert(C->getType()->getScalarSizeInBits() < Ty->getScalarSizeInBits()&& "SrcTy must be smaller than DestTy for ZExt!"); - return getFoldedCast(Instruction::ZExt, C, Ty, OnlyIfReduced); + return getFoldedCast(Instruction::ZExt, C, Ty, OnlyIfReduced, WasSext); } Constant *ConstantExpr::getFPTrunc(Constant *C, Type *Ty, bool OnlyIfReduced) { Index: llvm/lib/IR/Instruction.cpp =================================================================== --- llvm/lib/IR/Instruction.cpp +++ llvm/lib/IR/Instruction.cpp @@ -170,6 +170,10 @@ cast(this)->setIsExact(b); } +void Instruction::setWasSext(bool b) { + cast(this)->setWasSext(b); +} + bool Instruction::hasNoUnsignedWrap() const { return cast(this)->hasNoUnsignedWrap(); } @@ -178,6 +182,10 @@ return cast(this)->hasNoSignedWrap(); } +bool Instruction::wasSext() const { + return cast(this)->wasSext(); +} + bool Instruction::hasPoisonGeneratingFlags() const { return cast(this)->hasPoisonGeneratingFlags(); } @@ -202,7 +210,12 @@ case Instruction::GetElementPtr: cast(this)->setIsInBounds(false); break; + + case Instruction::ZExt: + cast(this)->setWasSext(false); + break; } + if (isa(this)) { setHasNoNaNs(false); setHasNoInfs(false); Index: llvm/lib/IR/Instructions.cpp =================================================================== --- llvm/lib/IR/Instructions.cpp +++ llvm/lib/IR/Instructions.cpp @@ -3758,16 +3758,20 @@ // Switch on the opcode provided switch (op) { - default: return false; // This is an input error + default: { + return false; // This is an input error + } case Instruction::Trunc: return SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy() && SrcEC == DstEC && SrcScalarBitSize > DstScalarBitSize; - case Instruction::ZExt: + case Instruction::ZExt: { return SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy() && SrcEC == DstEC && SrcScalarBitSize < DstScalarBitSize; - case Instruction::SExt: + } + case Instruction::SExt: { return SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy() && SrcEC == DstEC && SrcScalarBitSize < DstScalarBitSize; + } case Instruction::FPTrunc: return SrcTy->isFPOrFPVectorTy() && DstTy->isFPOrFPVectorTy() && SrcEC == DstEC && SrcScalarBitSize > DstScalarBitSize; Index: llvm/test/Assembler/flags.ll =================================================================== --- llvm/test/Assembler/flags.ll +++ llvm/test/Assembler/flags.ll @@ -259,4 +259,15 @@ ; CHECK: ret i64 mul nuw (i64 ptrtoint (ptr @addr to i64), i64 91) ret i64 mul nuw (i64 ptrtoint (ptr @addr to i64), i64 91) } +define i64 @zext_after_add_signed(i32 %a, i32 %b) { +; CHECK: %res = zext was_sext i32 %a to i64 + %res = zext was_sext i32 %a to i64 + ret i64 %res +} + +define i64 @zext_after_mul_signed(i32 %a, i32 %b) { +; CHECK: %res = zext was_sext i32 %a to i64 + %res = zext was_sext i32 %a to i64 + ret i64 %res +} Index: llvm/test/Bitcode/constantsTest.3.2.ll =================================================================== --- llvm/test/Bitcode/constantsTest.3.2.ll +++ llvm/test/Bitcode/constantsTest.3.2.ll @@ -121,4 +121,4 @@ insertvalue { i32, float } { i32 1, float 2.0 }, i32 0, 0 ret void -} \ No newline at end of file +} Index: llvm/test/Bitcode/flags.ll =================================================================== --- llvm/test/Bitcode/flags.ll +++ llvm/test/Bitcode/flags.ll @@ -16,6 +16,8 @@ %s = add nsw i32 %a, 0 ; [#uses=0] %us = add nuw nsw i32 %a, 0 ; [#uses=0] %z = add i32 %a, 0 ; [#uses=0] + %hh = zext was_sext i32 %a to i64 ; [#uses=0] + %ll = zext i32 %s to i64 ; [#uses=0] unreachable first: ; preds = %entry @@ -24,5 +26,7 @@ %ss = add nsw i32 %a, 0 ; [#uses=0] %uuss = add nuw nsw i32 %a, 0 ; [#uses=0] %zz = add i32 %a, 0 ; [#uses=0] + %kk = zext was_sext i32 %a to i64 ; [#uses=0] + %rr = zext i32 %ss to i64 ; [#uses=0] br label %second }