Index: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp @@ -223,8 +223,17 @@ namespace { +enum ExtType { + ZeroExtension, // Zero extension has been seen. + SignExtension, // Sign extension has been seen. + BothExtension // This extension type is used if we saw sext after + // ZeroExtension had been set, or if we saw zext after + // SignExtension had been set. It makes the type + // information of a promoted instruction invalid. +}; + using SetOfInstrs = SmallPtrSet; -using TypeIsSExt = PointerIntPair; +using TypeIsSExt = PointerIntPair; using InstrToOrigTy = DenseMap; using SExts = SmallVector; using ValueToSExts = DenseMap; @@ -3277,6 +3286,41 @@ /// Hepler class to perform type promotion. class TypePromotionHelper { + /// Utility function to add a promoted instruction \p ExtOpnd to + /// \p PromotedInsts and record the type of extension we have seen. + static void addPromotedInst(InstrToOrigTy &PromotedInsts, + Instruction *ExtOpnd, + bool IsSExt) { + ExtType ExtTy = IsSExt ? SignExtension : ZeroExtension; + InstrToOrigTy::iterator It = PromotedInsts.find(ExtOpnd); + if (It != PromotedInsts.end()) { + // If the new extension is same as original, the information in + // PromotedInsts[ExtOpnd] is still correct. + if (It->second.getInt() == ExtTy) + return; + + // Now the new extension is different from old extension, we make + // the type information invalid by setting extension type to + // BothExtension. + ExtTy = BothExtension; + } + PromotedInsts[ExtOpnd] = TypeIsSExt(ExtOpnd->getType(), ExtTy); + } + + /// Utility function to query the original type of instruction \p Opnd + /// with a matched extension type. If the extension doesn't match, we + /// cannot use the information we had on the original type. + /// BothExtension doesn't match any extension type. + static const Type *getOrigType(const InstrToOrigTy &PromotedInsts, + Instruction *Opnd, + bool IsSExt) { + ExtType ExtTy = IsSExt ? SignExtension : ZeroExtension; + InstrToOrigTy::const_iterator It = PromotedInsts.find(Opnd); + if (It != PromotedInsts.end() && It->second.getInt() == ExtTy) + return It->second.getPointer(); + return nullptr; + } + /// Utility function to check whether or not a sign or zero extension /// of \p Inst with \p ConsideredExtType can be moved through \p Inst by /// either using the operands of \p Inst or promoting \p Inst. @@ -3465,10 +3509,9 @@ // I.e., check that trunc just drops extended bits of the same kind of // the extension. // #1 get the type of the operand and check the kind of the extended bits. - const Type *OpndType; - InstrToOrigTy::const_iterator It = PromotedInsts.find(Opnd); - if (It != PromotedInsts.end() && It->second.getInt() == IsSExt) - OpndType = It->second.getPointer(); + const Type *OpndType = getOrigType(PromotedInsts, Opnd, IsSExt); + if (OpndType) + ; else if ((IsSExt && isa(Opnd)) || (!IsSExt && isa(Opnd))) OpndType = Opnd->getOperand(0)->getType(); else @@ -3596,8 +3639,7 @@ // Remember the original type of the instruction before promotion. // This is useful to know that the high bits are sign extended bits. - PromotedInsts.insert(std::pair( - ExtOpnd, TypeIsSExt(ExtOpnd->getType(), IsSExt))); + addPromotedInst(PromotedInsts, ExtOpnd, IsSExt); // Step #1. TPT.mutateType(ExtOpnd, Ext->getType()); // Step #2. Index: llvm/trunk/test/Transforms/CodeGenPrepare/X86/multi-extension.ll =================================================================== --- llvm/trunk/test/Transforms/CodeGenPrepare/X86/multi-extension.ll +++ llvm/trunk/test/Transforms/CodeGenPrepare/X86/multi-extension.ll @@ -0,0 +1,25 @@ +; RUN: opt < %s -codegenprepare -S -mtriple=x86_64-unknown-unknown | FileCheck %s +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.13.0" + +declare void @bar(i64) + +@b = global i16 0, align 2 + +; This test case is extracted from PR38125. +; %or is reachable by both a sext and zext that are going to be promoted. +; It ensures correct operation on PromotedInsts. + +; CHECK: %promoted = trunc i32 %or to i16 +; CHECK-NEXT: %c = sext i16 %promoted to i64 +define i32 @foo(i16 %kkk) { +entry: + %t4 = load i16, i16* @b, align 2 + %conv4 = zext i16 %t4 to i32 + %or = or i16 %kkk, %t4 + %c = sext i16 %or to i64 + call void @bar(i64 %c) + %t5 = and i16 %or, 5 + %z = zext i16 %t5 to i32 + ret i32 %z +}