diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1148,7 +1148,7 @@ static void emitStoresForConstant(CodeGenModule &CGM, const VarDecl &D, Address Loc, bool isVolatile, CGBuilderTy &Builder, - llvm::Constant *constant) { + llvm::Constant *constant, bool Trapping) { auto *Ty = constant->getType(); uint64_t ConstantSize = CGM.getDataLayout().getTypeAllocSize(Ty); if (!ConstantSize) @@ -1156,8 +1156,17 @@ bool canDoSingleStore = Ty->isIntOrIntVectorTy() || Ty->isPtrOrPtrVectorTy() || Ty->isFPOrFPVectorTy(); - if (canDoSingleStore) { - Builder.CreateStore(constant, Loc, isVolatile); + if (canDoSingleStore || Trapping) { + llvm::Value *V = constant; + + // Pass through @llvm.trapping if requested. + if (Trapping) { + llvm::Function *TrapFn = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::trapping, {V->getType()}); + V = Builder.CreateCall(TrapFn, {V}); + } + + Builder.CreateStore(V, Loc, isVolatile); return; } @@ -1202,7 +1211,8 @@ Address EltPtr = Builder.CreateStructGEP(Loc, i); emitStoresForConstant( CGM, D, EltPtr, isVolatile, Builder, - cast(Builder.CreateExtractValue(constant, i))); + cast(Builder.CreateExtractValue(constant, i)), + Trapping); } return; } @@ -1213,7 +1223,8 @@ Address EltPtr = Builder.CreateConstArrayGEP(Loc, i); emitStoresForConstant( CGM, D, EltPtr, isVolatile, Builder, - cast(Builder.CreateExtractValue(constant, i))); + cast(Builder.CreateExtractValue(constant, i)), + Trapping); } return; } @@ -1233,7 +1244,7 @@ llvm::Type *ElTy = Loc.getElementType(); llvm::Constant *constant = constWithPadding(CGM, IsPattern::No, llvm::Constant::getNullValue(ElTy)); - emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant); + emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant, /*FIXME*/true); } static void emitStoresForPatternInit(CodeGenModule &CGM, const VarDecl &D, @@ -1243,7 +1254,7 @@ llvm::Constant *constant = constWithPadding( CGM, IsPattern::Yes, initializationPatternFor(CGM, ElTy)); assert(!isa(constant)); - emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant); + emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant, /*FIXME*/true); } static bool containsUndef(llvm::Constant *constant) { @@ -1859,7 +1870,7 @@ llvm::Type *BP = CGM.Int8Ty->getPointerTo(Loc.getAddressSpace()); emitStoresForConstant( CGM, D, (Loc.getType() == BP) ? Loc : Builder.CreateBitCast(Loc, BP), - type.isVolatileQualified(), Builder, constant); + type.isVolatileQualified(), Builder, constant, /*Trapping=*/false); } /// Emit an expression as an initializer for an object (variable, field, etc.) diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h --- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h +++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -765,6 +765,7 @@ case Intrinsic::objectsize: case Intrinsic::ptr_annotation: case Intrinsic::var_annotation: + case Intrinsic::trapping: case Intrinsic::experimental_gc_result: case Intrinsic::experimental_gc_relocate: case Intrinsic::coro_alloc: diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1120,6 +1120,8 @@ GCCBuiltin<"__builtin_trap">; def int_debugtrap : Intrinsic<[]>, GCCBuiltin<"__builtin_debugtrap">; +def int_trapping : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], + [IntrNoMem, IntrWillReturn, IntrSpeculatable]>; // Support for dynamic deoptimization (or de-specialization) def int_experimental_deoptimize : Intrinsic<[llvm_any_ty], [llvm_vararg_ty], diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1992,6 +1992,8 @@ llvm_unreachable("llvm.objectsize.* should have been lowered already"); case Intrinsic::is_constant: llvm_unreachable("llvm.is.constant.* should have been lowered already"); + case Intrinsic::trapping: + llvm_unreachable("llvm.trapping.* should have been lowered already"); case Intrinsic::aarch64_stlxr: case Intrinsic::aarch64_stxr: { ZExtInst *ExtVal = dyn_cast(CI->getArgOperand(0)); diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1474,6 +1474,9 @@ case Intrinsic::is_constant: llvm_unreachable("llvm.is.constant.* should have been lowered already"); + case Intrinsic::trapping: + llvm_unreachable("llvm.trapping.* should have been lowered already"); + case Intrinsic::stackguard: getStackGuard(getOrCreateVReg(CI), MIRBuilder); return true; diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1474,6 +1474,9 @@ case Intrinsic::is_constant: llvm_unreachable("llvm.is.constant.* should have been lowered already"); + case Intrinsic::trapping: + llvm_unreachable("llvm.trapping.* should have been lowered already"); + case Intrinsic::launder_invariant_group: case Intrinsic::strip_invariant_group: case Intrinsic::expect: { diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6383,6 +6383,9 @@ case Intrinsic::is_constant: llvm_unreachable("llvm.is.constant.* should have been lowered already"); + case Intrinsic::trapping: + llvm_unreachable("llvm.trapping.* should have been lowered already"); + case Intrinsic::annotation: case Intrinsic::ptr_annotation: case Intrinsic::launder_invariant_group: diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1846,6 +1846,75 @@ return nullptr; } +static bool canObservePoison(Use &U, Instruction *I) { + if (U.getOperandNo() == 0 && + (isa(I) || isa(I) || isa(I) || + isa(I) || isa(I))) + return true; + if (auto *CB = dyn_cast(I)) + if (CB->getCalledOperandUse().getOperandNo() == U.getOperandNo()) + return true; + if (U.getOperandNo() == 1 && I->isIntDivRem()) + return true; + // FIXME: More cases? + return false; +} + +/// Simplify a use of @llvm.trapping.( %x) +/// +/// Return true if we've performed a simplification and the use should be +/// replaced by %x. +bool InstCombiner::simplifyTrappingUse(Use &U) { + auto *I = dyn_cast(U.getUser()); + + // We only care about trapping indicators on instructions. + if (!I) + return true; + + // FIXME: If all operands are trapping, we can convert to trapping(phi(...)). + if (isa(I)) + return false; + + // The result of select is trapping if its condition is trapping. + if (isa(I) && U.getOperandNo() != 0) + return false; + + // trapping(trapping(x)) -> trapping(x). + if (auto *II = dyn_cast(I)) + if (II->getIntrinsicID() == Intrinsic::trapping) + return true; + + // op(trapping(x)) -> @llvm.trap() where possible. + if (canObservePoison(U, I)) { + CallInst *Trap = CallInst::Create( + Intrinsic::getDeclaration(I->getModule(), Intrinsic::trap)); + InsertNewInstBefore(Trap, *I); + return true; + } + + // We can't propagate trapping to the result of a void-typed instruction and + // a few other cases. + if (I->getType()->isVoidTy() || I->getType()->isTokenTy() || + I->isTerminator()) + return false; + + // Don't propagate through call arguments to the result of the function for + // now. + if (isa(I)) + return false; + + // op(trapping(x)) -> trapping(op(x)) otherwise. + CallInst *TrappingI = + CallInst::Create(Intrinsic::getDeclaration( + I->getModule(), Intrinsic::trapping, {I->getType()}), + {I}); + TrappingI->insertAfter(I); + replaceInstUsesWith(*I, TrappingI); + // Undo effect of replaceInstUsesWith on TrappingI itself. + TrappingI->setArgOperand(0, I); + return true; +} + /// CallInst simplification. This mostly only handles folding of intrinsic /// instructions. For normal calls, it allows visitCallBase to do the heavy /// lifting. @@ -4207,6 +4276,23 @@ AC.updateAffectedValues(II); break; } + case Intrinsic::trapping: { + bool RemovedAllUses = true; + // Note, it's not safe to change the uses of II while iterating over the + // same list. + llvm::SmallVector UsesToReplace; + for (Use &U : II->uses()) { + if (simplifyTrappingUse(U)) + UsesToReplace.push_back(&U); + else + RemovedAllUses = false; + } + for (Use *U : UsesToReplace) + *U = II->getOperand(0); + if (!RemovedAllUses) + return nullptr; + return eraseInstFromFunction(*II); + } case Intrinsic::experimental_gc_relocate: { auto &GCR = *cast(II); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -635,6 +635,8 @@ Instruction *foldIntrinsicWithOverflowCommon(IntrinsicInst *II); + bool simplifyTrappingUse(Use &U); + public: /// Inserts an instruction \p New before instruction \p Old /// diff --git a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp --- a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp +++ b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp @@ -6,8 +6,9 @@ // //===----------------------------------------------------------------------===// // -// This pass lowers all remaining 'objectsize' 'is.constant' intrinsic calls -// and provides constant propagation and basic CFG cleanup on the result. +// This pass lowers all remaining 'objectsize', 'is.constant', and 'trapping' +// intrinsic calls and provides constant propagation and basic CFG cleanup on +// the result. // //===----------------------------------------------------------------------===// @@ -39,6 +40,8 @@ "Number of 'is.constant' intrinsic calls handled"); STATISTIC(ObjectSizeIntrinsicsHandled, "Number of 'objectsize' intrinsic calls handled"); +STATISTIC(TrappingIntrinsicsHandled, + "Number of 'trapping' intrinsic calls handled"); static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) { Value *Op = II->getOperand(0); @@ -99,6 +102,7 @@ break; case Intrinsic::is_constant: case Intrinsic::objectsize: + case Intrinsic::trapping: Worklist.push_back(WeakTrackingVH(&I)); break; } @@ -125,6 +129,10 @@ NewValue = lowerObjectSizeCall(II, DL, TLI, true); ObjectSizeIntrinsicsHandled++; break; + case Intrinsic::trapping: + NewValue = II->getOperand(0); + TrappingIntrinsicsHandled++; + break; } HasDeadBlocks |= replaceConditionalBranchesOnConstant(II, NewValue); }