Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -15097,6 +15097,51 @@ This intrinsic actually does nothing, but optimizers must assume that it has externally observable side effects. +'``llvm.is.constant.*``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use llvm.is.constant with any argument type. + +:: + + declare i1 @llvm.is.constant.i32(i32 %operand) nounwind readnone + declare i1 @llvm.is.constant.f32(float %operand) nounwind readnone + declare i1 @llvm.is.constant.TYPENAME(TYPE %operand) nounwind readnone + +Overview: +""""""""" + +The '``llvm.is.constant``' intrinsic will return true if the argument +is known to be a manifest compile-time constant. It is guaranteed to +fold to either true or false before generating machine code. + +Semantics: +"""""""""" + +This intrinsic generates no code. If its argument is known to be a +manifest compile-time constant value, then the intrinsic will be +converted to a constant true value. Otherwise, it will be converted to +a constant false value. + +In particular, note that if the argument is a constant expression +which refers to a global (the address of which _is_ a constant, but +not manifest during the compile), then the intrinsic evaluates to +false. + +The result also intentionally depends on the result of optimization +passes -- e.g., the result can change depending on whether a +function gets inlined or not. A function's parameters are +obviously not constant. However, a call like +``llvm.is.constant.i32(i32 %param)`` *can* return true after the +function is inlined, if the value passed to the function parameter was +a constant. + +On the other hand, if constant folding is not run, it will never +evaluate to true, even in simple cases. + Stack Map Intrinsics -------------------- Index: include/llvm/Analysis/TargetTransformInfoImpl.h =================================================================== --- include/llvm/Analysis/TargetTransformInfoImpl.h +++ include/llvm/Analysis/TargetTransformInfoImpl.h @@ -176,6 +176,7 @@ case Intrinsic::coro_suspend: case Intrinsic::coro_param: case Intrinsic::coro_subfn_addr: + case Intrinsic::is_constant: // These intrinsics don't actually represent code after lowering. return TTI::TCC_Free; } Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -850,6 +850,11 @@ def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], [], "llvm.clear_cache">; +// Intrinsic to detect whether its argument is a constant. +def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem], + "llvm.is.constant">, + GCCBuiltin<"__builtin_constant_p">; + //===-------------------------- Masked Intrinsics -------------------------===// // def int_masked_store : Intrinsic<[], [llvm_anyvector_ty, Index: lib/Analysis/ConstantFolding.cpp =================================================================== --- lib/Analysis/ConstantFolding.cpp +++ lib/Analysis/ConstantFolding.cpp @@ -1424,6 +1424,7 @@ case Intrinsic::x86_avx512_vcvtsd2usi64: case Intrinsic::x86_avx512_cvttsd2usi: case Intrinsic::x86_avx512_cvttsd2usi64: + case Intrinsic::is_constant: return true; default: return false; @@ -1603,6 +1604,15 @@ const TargetLibraryInfo *TLI, ImmutableCallSite CS) { if (Operands.size() == 1) { + if (IntrinsicID == Intrinsic::is_constant) { + // We know we have a "Constant" argument. But we want to only + // return true for manifest constants, not those that depend on + // constants with unknowable values, e.g. GlobalValue or BlockAddress. + if (isa(Operands[0]) || isa(Operands[0])) + return ConstantInt::getTrue(Ty->getContext()); + return ConstantInt::getFalse(Ty->getContext()); + } + if (isa(Operands[0])) { // cosine(arg) is between -1 and 1. cosine(invalid arg) is NaN if (IntrinsicID == Intrinsic::cos) Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -321,6 +321,24 @@ } private: + template + void resetIteratorIfInvalidatedWhileCalling(BasicBlock *BB, F f) { + // Substituting can cause recursive simplifications, which can invalidate + // our iterator. Use a WeakTrackingVH to hold onto it in case this + // happens. + Value *CurValue = &*CurInstIterator; + WeakTrackingVH IterHandle(CurValue); + + f(); + + // If the iterator instruction was recursively deleted, start over at the + // start of the block. + if (IterHandle != CurValue) { + CurInstIterator = BB->begin(); + SunkAddrs.clear(); + } + } + bool eliminateFallThrough(Function &F); bool eliminateMostlyEmptyBlocks(Function &F); BasicBlock *findDestBlockOfMergeableEmptyBlock(BasicBlock *BB); @@ -1690,21 +1708,18 @@ // Lower all uses of llvm.objectsize.* ConstantInt *RetVal = lowerObjectSizeCall(II, *DL, TLInfo, /*MustSucceed=*/true); - // Substituting this can cause recursive simplifications, which can - // invalidate our iterator. Use a WeakTrackingVH to hold onto it in case - // this - // happens. - Value *CurValue = &*CurInstIterator; - WeakTrackingVH IterHandle(CurValue); - replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr); - - // If the iterator instruction was recursively deleted, start over at the - // start of the block. - if (IterHandle != CurValue) { - CurInstIterator = BB->begin(); - SunkAddrs.clear(); - } + resetIteratorIfInvalidatedWhileCalling(BB, [&]() { + replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr); + }); + return true; + } + case Intrinsic::is_constant: { + // If is_constant hasn't folded away yet, lower it to false now. + Constant *RetVal = ConstantInt::getFalse(II->getContext()); + resetIteratorIfInvalidatedWhileCalling(BB, [&]() { + replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr); + }); return true; } case Intrinsic::aarch64_stlxr: Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -917,6 +917,11 @@ MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0); return true; } + case Intrinsic::is_constant: + // If this wasn't constant-folded away by now, then it's not a + // constant. + MIRBuilder.buildConstant(getOrCreateVReg(CI), 0); + return true; case Intrinsic::stackguard: getStackGuard(getOrCreateVReg(CI), MIRBuilder); return true; Index: lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FastISel.cpp +++ lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1457,6 +1457,14 @@ updateValueMap(II, ResultReg); return true; } + case Intrinsic::is_constant: { + Constant *ResCI = ConstantInt::getFalse(II->getContext()); + unsigned ResultReg = getRegForValue(ResCI); + if (!ResultReg) + return false; + updateValueMap(II, ResultReg); + return true; + } case Intrinsic::experimental_stackmap: return selectStackmap(II); case Intrinsic::experimental_patchpoint_void: Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5851,6 +5851,13 @@ setValue(&I, Res); return nullptr; } + + case Intrinsic::is_constant: + // If this wasn't constant-folded away by now, then it's not a + // constant. + setValue(&I, DAG.getConstant(0, sdl, MVT::i1)); + return nullptr; + case Intrinsic::annotation: case Intrinsic::ptr_annotation: case Intrinsic::launder_invariant_group: Index: lib/Transforms/Scalar/SCCP.cpp =================================================================== --- lib/Transforms/Scalar/SCCP.cpp +++ lib/Transforms/Scalar/SCCP.cpp @@ -1228,6 +1228,8 @@ SmallVector Operands; for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); AI != E; ++AI) { + if (AI->get()->getType()->isStructTy()) + return markOverdefined(I); // Can't handle struct args. LatticeVal State = getValueState(*AI); if (State.isUnknown())