diff options
Diffstat (limited to 'clang/lib/CodeGen/CGBuiltin.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 85 |
1 files changed, 84 insertions, 1 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a81a75b4135..92a4447398b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -11,14 +11,15 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenFunction.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/Analysis/Analyses/OSLog.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -564,6 +565,18 @@ Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, llvm_unreachable("Incorrect MSVC intrinsic!"); } +namespace { +// ARC cleanup for __builtin_os_log_format +struct CallObjCArcUse final : EHScopeStack::Cleanup { + CallObjCArcUse(llvm::Value *object) : object(object) {} + llvm::Value *object; + + void Emit(CodeGenFunction &CGF, Flags flags) override { + CGF.EmitARCIntrinsicUse(object); + } +}; +} + RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -2597,6 +2610,76 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Fall through - it's already mapped to the intrinsic by GCCBuiltin. break; } + case Builtin::BI__builtin_os_log_format: { + assert(E->getNumArgs() >= 2 && + "__builtin_os_log_format takes at least 2 arguments"); + analyze_os_log::OSLogBufferLayout Layout; + analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout); + Address BufAddr = EmitPointerWithAlignment(E->getArg(0)); + // Ignore argument 1, the format string. It is not currently used. + CharUnits Offset; + Builder.CreateStore( + Builder.getInt8(Layout.getSummaryByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "summary")); + Builder.CreateStore( + Builder.getInt8(Layout.getNumArgsByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "numArgs")); + + llvm::SmallVector<llvm::Value *, 4> RetainableOperands; + for (const auto &Item : Layout.Items) { + Builder.CreateStore( + Builder.getInt8(Item.getDescriptorByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "argDescriptor")); + Builder.CreateStore( + Builder.getInt8(Item.getSizeByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "argSize")); + Address Addr = Builder.CreateConstByteGEP(BufAddr, Offset); + if (const Expr *TheExpr = Item.getExpr()) { + Addr = Builder.CreateElementBitCast( + Addr, ConvertTypeForMem(TheExpr->getType())); + // Check if this is a retainable type. + if (TheExpr->getType()->isObjCRetainableType()) { + assert(getEvaluationKind(TheExpr->getType()) == TEK_Scalar && + "Only scalar can be a ObjC retainable type"); + llvm::Value *SV = EmitScalarExpr(TheExpr, /*Ignore*/ false); + RValue RV = RValue::get(SV); + LValue LV = MakeAddrLValue(Addr, TheExpr->getType()); + EmitStoreThroughLValue(RV, LV); + // Check if the object is constant, if not, save it in + // RetainableOperands. + if (!isa<Constant>(SV)) + RetainableOperands.push_back(SV); + } else { + EmitAnyExprToMem(TheExpr, Addr, Qualifiers(), /*isInit*/ true); + } + } else { + Addr = Builder.CreateElementBitCast(Addr, Int32Ty); + Builder.CreateStore( + Builder.getInt32(Item.getConstValue().getQuantity()), Addr); + } + Offset += Item.size(); + } + + // Push a clang.arc.use cleanup for each object in RetainableOperands. The + // cleanup will cause the use to appear after the final log call, keeping + // the object valid while it’s held in the log buffer. Note that if there’s + // a release cleanup on the object, it will already be active; since + // cleanups are emitted in reverse order, the use will occur before the + // object is released. + if (!RetainableOperands.empty() && getLangOpts().ObjCAutoRefCount && + CGM.getCodeGenOpts().OptimizationLevel != 0) + for (llvm::Value *object : RetainableOperands) + pushFullExprCleanup<CallObjCArcUse>(getARCCleanupKind(), object); + + return RValue::get(BufAddr.getPointer()); + } + + case Builtin::BI__builtin_os_log_format_buffer_size: { + analyze_os_log::OSLogBufferLayout Layout; + analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout); + return RValue::get(ConstantInt::get(ConvertType(E->getType()), + Layout.size().getQuantity())); + } } // If this is an alias for a lib function (e.g. __builtin_sin), emit |