diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -52,6 +52,7 @@ CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory. CODEGENOPT(DiscardValueNames , 1, 0) ///< Discard Value Names from the IR (LLVMContext flag) +CODEGENOPT(DisableFrozenArgs , 1, 0) ///< Disable emitting `frozen` attributes on IR call arguments CODEGENOPT(DisableGCov , 1, 0) ///< Don't run the GCov pass, for testing. CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get ///< the pristine IR generated by the diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -503,6 +503,8 @@ HelpText<"Disable freeing of memory on exit">; def discard_value_names : Flag<["-"], "discard-value-names">, HelpText<"Discard value names in LLVM IR">; +def disable_frozen_args : Flag<["-"], "disable-frozen-args">, + HelpText<"Disable emitting frozen attribute in LLVM IR">; def load : Separate<["-"], "load">, MetaVarName<"">, HelpText<"Load the named plugin (dynamic shared object)">; def plugin : Separate<["-"], "plugin">, MetaVarName<"">, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2076,6 +2076,14 @@ QualType RetTy = FI.getReturnType(); const ABIArgInfo &RetAI = FI.getReturnInfo(); + + // Determine if the return type could be partially initialized + const Type *RetTyPtr = RetTy.getTypePtr(); + if (!RetTy->isVoidType() && !RetTyPtr->isRecordType() && + RetAI.getKind() != ABIArgInfo::Indirect) { + RetAttrs.addAttribute(llvm::Attribute::Frozen); + } + switch (RetAI.getKind()) { case ABIArgInfo::Extend: if (RetAI.isSignExt()) @@ -2161,6 +2169,15 @@ } } + // Decide whether the argument we're handling may have valid + // uninitialized bits. + const Type *ArgTyPtr = ParamType.getTypePtr(); + bool ArgFrozen = + !ArgTyPtr->isRecordType() || AI.getKind() == ABIArgInfo::Indirect; + if (!CodeGenOpts.DisableFrozenArgs && ArgFrozen) { + Attrs.addAttribute(llvm::Attribute::Frozen); + } + // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we // have the corresponding parameter variable. It doesn't make // sense to do it here because parameters are so messed up. @@ -4069,6 +4086,13 @@ const llvm::Twine &name) { llvm::CallInst *call = Builder.CreateCall( callee, args, getBundlesForFunclet(callee.getCallee()), name); + if (llvm::Function *f = dyn_cast(callee.getCallee())) { + for (unsigned arg = 0; arg < f->arg_size(); arg++) { + unsigned i = llvm::AttributeList::FirstArgIndex + arg; + if (f->hasAttribute(i, llvm::Attribute::Frozen)) + call->addAttribute(i, llvm::Attribute::Frozen); + } + } call->setCallingConv(getRuntimeCC()); return call; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -888,6 +888,7 @@ Opts.DisableFree = Args.hasArg(OPT_disable_free); Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names); + Opts.DisableFrozenArgs = Args.hasArg(OPT_disable_frozen_args); Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls); Opts.NoEscapingBlockTailCalls = Args.hasArg(OPT_fno_escaping_block_tail_calls); diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -643,6 +643,7 @@ ATTR_KIND_PREALLOCATED = 65, ATTR_KIND_NO_MERGE = 66, ATTR_KIND_NULL_POINTER_IS_VALID = 67, + ATTR_KIND_FROZEN = 68, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -39,6 +39,9 @@ /// Pass structure by value. def ByVal : TypeAttr<"byval">; +/// Parameter or return value may not contain uninitialized or poison bits +def Frozen : EnumAttr<"frozen">; + /// Marks function as being in a cold path. def Cold : EnumAttr<"cold">; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -696,6 +696,7 @@ KEYWORD(writeonly); KEYWORD(zeroext); KEYWORD(immarg); + KEYWORD(frozen); KEYWORD(type); KEYWORD(opaque); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1374,6 +1374,7 @@ case lltok::kw_inalloca: case lltok::kw_nest: case lltok::kw_noalias: + case lltok::kw_frozen: case lltok::kw_nocapture: case lltok::kw_nonnull: case lltok::kw_returned: @@ -1677,6 +1678,9 @@ case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; + case lltok::kw_frozen: + B.addAttribute(Attribute::Frozen); + break; case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break; case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break; case lltok::kw_nofree: B.addAttribute(Attribute::NoFree); break; @@ -1774,6 +1778,9 @@ } case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break; + case lltok::kw_frozen: + B.addAttribute(Attribute::Frozen); + break; case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break; case lltok::kw_signext: B.addAttribute(Attribute::SExt); break; case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break; diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -196,6 +196,7 @@ kw_naked, kw_nest, kw_noalias, + kw_frozen, kw_nobuiltin, kw_nocapture, kw_noduplicate, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1532,6 +1532,8 @@ return Attribute::SanitizeMemTag; case bitc::ATTR_KIND_PREALLOCATED: return Attribute::Preallocated; + case bitc::ATTR_KIND_FROZEN: + return Attribute::Frozen; } } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -731,6 +731,8 @@ return bitc::ATTR_KIND_SANITIZE_MEMTAG; case Attribute::Preallocated: return bitc::ATTR_KIND_PREALLOCATED; + case Attribute::Frozen: + return bitc::ATTR_KIND_FROZEN; case Attribute::EndAttrKinds: llvm_unreachable("Can not encode end-attribute kinds marker."); case Attribute::None: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -443,6 +443,8 @@ return "cold"; if (hasAttribute(Attribute::ImmArg)) return "immarg"; + if (hasAttribute(Attribute::Frozen)) + return "frozen"; if (hasAttribute(Attribute::ByVal)) { std::string Result; diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -929,6 +929,7 @@ case Attribute::StrictFP: case Attribute::UWTable: case Attribute::NoCfCheck: + case Attribute::Frozen: break; }