/// CheckAggExprForMemSetUse - If the initializer is large and has a lot of /// zeros in it, emit a memset and avoid storing the individual zeros. /// static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E, CodeGenFunction &CGF) { // If the slot is already known to be zeroed, nothing to do. Don't mess with // volatile stores. if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return; // If the type is 16-bytes or smaller, prefer individual stores over memset. std::pair<uint64_t, unsigned> TypeInfo = CGF.getContext().getTypeInfo(E->getType()); if (TypeInfo.first/8 <= 16) return; // Check to see if over 3/4 of the initializer are known to be zero. If so, // we prefer to emit memset + individual stores for the rest. uint64_t NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF); if (NumNonZeroBytes*4 > TypeInfo.first/8) return; // Okay, it seems like a good idea to use an initial memset, emit the call. llvm::Constant *SizeVal = CGF.Builder.getInt64(TypeInfo.first/8); unsigned Align = TypeInfo.second/8; llvm::Value *Loc = Slot.getAddr(); const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); Loc = CGF.Builder.CreateBitCast(Loc, BP); CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, Align, false); // Tell the AggExprEmitter that the slot is known zero. Slot.setZeroed(); }
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { // For an assignment to work, the value on the right has // to be compatible with the value on the left. assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(), E->getRHS()->getType()) && "Invalid assignment"); // FIXME: __block variables need the RHS evaluated first! LValue LHS = CGF.EmitLValue(E->getLHS()); // We have to special case property setters, otherwise we must have // a simple lvalue (no aggregates inside vectors, bitfields). if (LHS.isPropertyRef()) { AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); CGF.EmitAggExpr(E->getRHS(), Slot); CGF.EmitStoreThroughPropertyRefLValue(Slot.asRValue(), LHS); } else { bool GCollection = false; if (CGF.getContext().getLangOptions().getGCMode()) GCollection = TypeRequiresGCollection(E->getLHS()->getType()); // Codegen the RHS so that it stores directly into the LHS. AggValueSlot LHSSlot = AggValueSlot::forLValue(LHS, true, GCollection); CGF.EmitAggExpr(E->getRHS(), LHSSlot, false); EmitFinalDestCopy(E, LHS, true); } }
/// EmitAggExpr - Emit the computation of the specified expression of aggregate /// type. The result is computed into DestPtr. Note that if DestPtr is null, /// the value of the aggregate expression is not needed. If VolatileDest is /// true, DestPtr cannot be 0. /// /// \param IsInitializer - true if this evaluation is initializing an /// object whose lifetime is already being managed. void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot, bool IgnoreResult) { assert(E && hasAggregateLLVMType(E->getType()) && "Invalid aggregate expression to emit"); assert((Slot.getAddr() != 0 || Slot.isIgnored()) && "slot has bits but no address"); // Optimize the slot if possible. CheckAggExprForMemSetUse(Slot, E, *this); AggExprEmitter(*this, Slot, IgnoreResult).Visit(const_cast<Expr*>(E)); }
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { // For an assignment to work, the value on the right has // to be compatible with the value on the left. assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(), E->getRHS()->getType()) && "Invalid assignment"); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getLHS())) if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) if (VD->hasAttr<BlocksAttr>() && E->getRHS()->HasSideEffects(CGF.getContext())) { // When __block variable on LHS, the RHS must be evaluated first // as it may change the 'forwarding' field via call to Block_copy. LValue RHS = CGF.EmitLValue(E->getRHS()); LValue LHS = CGF.EmitLValue(E->getLHS()); bool GCollection = false; if (CGF.getContext().getLangOptions().getGCMode()) GCollection = TypeRequiresGCollection(E->getLHS()->getType()); Dest = AggValueSlot::forLValue(LHS, true, GCollection); EmitFinalDestCopy(E, RHS, true); return; } LValue LHS = CGF.EmitLValue(E->getLHS()); // We have to special case property setters, otherwise we must have // a simple lvalue (no aggregates inside vectors, bitfields). if (LHS.isPropertyRef()) { const ObjCPropertyRefExpr *RE = LHS.getPropertyRefExpr(); QualType ArgType = RE->getSetterArgType(); RValue Src; if (ArgType->isReferenceType()) Src = CGF.EmitReferenceBindingToExpr(E->getRHS(), 0); else { AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); CGF.EmitAggExpr(E->getRHS(), Slot); Src = Slot.asRValue(); } CGF.EmitStoreThroughPropertyRefLValue(Src, LHS); } else { bool GCollection = false; if (CGF.getContext().getLangOptions().getGCMode()) GCollection = TypeRequiresGCollection(E->getLHS()->getType()); // Codegen the RHS so that it stores directly into the LHS. AggValueSlot LHSSlot = AggValueSlot::forLValue(LHS, true, GCollection); CGF.EmitAggExpr(E->getRHS(), LHSSlot, false); EmitFinalDestCopy(E, LHS, true); } }
/// Emit a load from an l-value of atomic type. Note that the r-value /// we produce is an r-value of the atomic *value* type. RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc, AggValueSlot resultSlot) { AtomicInfo atomics(*this, src); // Check whether we should use a library call. if (atomics.shouldUseLibcall()) { llvm::Value *tempAddr; if (!resultSlot.isIgnored()) { assert(atomics.getEvaluationKind() == TEK_Aggregate); tempAddr = resultSlot.getAddr(); } else { tempAddr = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp"); } // void __atomic_load(size_t size, void *mem, void *return, int order); CallArgList args; args.add(RValue::get(atomics.getAtomicSizeValue()), getContext().getSizeType()); args.add(RValue::get(EmitCastToVoidPtr(src.getAddress())), getContext().VoidPtrTy); args.add(RValue::get(EmitCastToVoidPtr(tempAddr)), getContext().VoidPtrTy); args.add(RValue::get(llvm::ConstantInt::get( IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)), getContext().IntTy); emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args); // Produce the r-value. return atomics.convertTempToRValue(tempAddr, resultSlot, loc); } // Okay, we're doing this natively. llvm::Value *addr = atomics.emitCastToAtomicIntPointer(src.getAddress()); llvm::LoadInst *load = Builder.CreateLoad(addr, "atomic-load"); load->setAtomic(llvm::SequentiallyConsistent); // Other decoration. load->setAlignment(src.getAlignment().getQuantity()); if (src.isVolatileQualified()) load->setVolatile(true); if (src.getTBAAInfo()) CGM.DecorateInstruction(load, src.getTBAAInfo()); // If we're ignoring an aggregate return, don't do anything. if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored()) return RValue::getAggregate(nullptr, false); // Okay, turn that back into the original value type. return atomics.convertIntToValue(load, resultSlot, loc); }
RValue AtomicInfo::convertTempToRValue(llvm::Value *addr, AggValueSlot resultSlot) const { if (EvaluationKind == TEK_Aggregate) { // Nothing to do if the result is ignored. if (resultSlot.isIgnored()) return resultSlot.asRValue(); assert(resultSlot.getAddr() == addr || hasPadding()); // In these cases, we should have emitted directly into the result slot. if (!hasPadding() || resultSlot.isValueOfAtomic()) return resultSlot.asRValue(); // Otherwise, fall into the common path. } // Drill into the padding structure if we have one. if (hasPadding()) addr = CGF.Builder.CreateStructGEP(addr, 0); // If we're emitting to an aggregate, copy into the result slot. if (EvaluationKind == TEK_Aggregate) { CGF.EmitAggregateCopy(resultSlot.getAddr(), addr, getValueType(), resultSlot.isVolatile()); return resultSlot.asRValue(); } // Otherwise, just convert the temporary to an r-value using the // normal conversion routine. return CGF.convertTempToRValue(addr, getValueType()); }
/// CheckAggExprForMemSetUse - If the initializer is large and has a lot of /// zeros in it, emit a memset and avoid storing the individual zeros. /// static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E, CodeGenFunction &CGF) { // If the slot is already known to be zeroed, nothing to do. Don't mess with // volatile stores. if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return; // C++ objects with a user-declared constructor don't need zero'ing. if (CGF.getContext().getLangOptions().CPlusPlus) if (const RecordType *RT = CGF.getContext() .getBaseElementType(E->getType())->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (RD->hasUserDeclaredConstructor()) return; } // If the type is 16-bytes or smaller, prefer individual stores over memset. std::pair<CharUnits, CharUnits> TypeInfo = CGF.getContext().getTypeInfoInChars(E->getType()); if (TypeInfo.first <= CharUnits::fromQuantity(16)) return; // Check to see if over 3/4 of the initializer are known to be zero. If so, // we prefer to emit memset + individual stores for the rest. CharUnits NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF); if (NumNonZeroBytes*4 > TypeInfo.first) return; // Okay, it seems like a good idea to use an initial memset, emit the call. llvm::Constant *SizeVal = CGF.Builder.getInt64(TypeInfo.first.getQuantity()); CharUnits Align = TypeInfo.second; llvm::Value *Loc = Slot.getAddr(); llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); Loc = CGF.Builder.CreateBitCast(Loc, BP); CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, Align.getQuantity(), false); // Tell the AggExprEmitter that the slot is known zero. Slot.setZeroed(); }
RValue AtomicInfo::convertIntToValue(llvm::Value *IntVal, AggValueSlot ResultSlot, SourceLocation Loc) const { // Try not to in some easy cases. assert(IntVal->getType()->isIntegerTy() && "Expected integer value"); if (getEvaluationKind() == TEK_Scalar && !hasPadding()) { auto *ValTy = CGF.ConvertTypeForMem(ValueTy); if (ValTy->isIntegerTy()) { assert(IntVal->getType() == ValTy && "Different integer types."); return RValue::get(IntVal); } else if (ValTy->isPointerTy()) return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy)); else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy)) return RValue::get(CGF.Builder.CreateBitCast(IntVal, ValTy)); } // Create a temporary. This needs to be big enough to hold the // atomic integer. llvm::Value *Temp; bool TempIsVolatile = false; CharUnits TempAlignment; if (getEvaluationKind() == TEK_Aggregate) { assert(!ResultSlot.isIgnored()); Temp = ResultSlot.getAddr(); TempAlignment = getValueAlignment(); TempIsVolatile = ResultSlot.isVolatile(); } else { Temp = CGF.CreateMemTemp(getAtomicType(), "atomic-temp"); TempAlignment = getAtomicAlignment(); } // Slam the integer into the temporary. llvm::Value *CastTemp = emitCastToAtomicIntPointer(Temp); CGF.Builder.CreateAlignedStore(IntVal, CastTemp, TempAlignment.getQuantity()) ->setVolatile(TempIsVolatile); return convertTempToRValue(Temp, ResultSlot, Loc); }
RValue AtomicInfo::convertTempToRValue(llvm::Value *addr, AggValueSlot resultSlot, SourceLocation loc) const { if (EvaluationKind == TEK_Aggregate) return resultSlot.asRValue(); // Drill into the padding structure if we have one. if (hasPadding()) addr = CGF.Builder.CreateStructGEP(addr, 0); // Otherwise, just convert the temporary to an r-value using the // normal conversion routine. return CGF.convertTempToRValue(addr, getValueType(), loc); }
void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { QualType T = E->getType(); AggValueSlot Slot = EnsureSlot(T); EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T)); }
/// Emit a load from an l-value of atomic type. Note that the r-value /// we produce is an r-value of the atomic *value* type. RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc, AggValueSlot resultSlot) { AtomicInfo atomics(*this, src); // Check whether we should use a library call. if (atomics.shouldUseLibcall()) { llvm::Value *tempAddr; if (!resultSlot.isIgnored()) { assert(atomics.getEvaluationKind() == TEK_Aggregate); tempAddr = resultSlot.getAddr(); } else { tempAddr = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp"); } // void __atomic_load(size_t size, void *mem, void *return, int order); CallArgList args; args.add(RValue::get(atomics.getAtomicSizeValue()), getContext().getSizeType()); args.add(RValue::get(EmitCastToVoidPtr(src.getAddress())), getContext().VoidPtrTy); args.add(RValue::get(EmitCastToVoidPtr(tempAddr)), getContext().VoidPtrTy); args.add(RValue::get(llvm::ConstantInt::get( IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)), getContext().IntTy); emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args); // Produce the r-value. return atomics.convertTempToRValue(tempAddr, resultSlot, loc); } // Okay, we're doing this natively. llvm::Value *addr = atomics.emitCastToAtomicIntPointer(src.getAddress()); llvm::LoadInst *load = Builder.CreateLoad(addr, "atomic-load"); load->setAtomic(llvm::SequentiallyConsistent); // Other decoration. load->setAlignment(src.getAlignment().getQuantity()); if (src.isVolatileQualified()) load->setVolatile(true); if (src.getTBAAInfo()) CGM.DecorateInstruction(load, src.getTBAAInfo()); // Okay, turn that back into the original value type. QualType valueType = atomics.getValueType(); llvm::Value *result = load; // If we're ignoring an aggregate return, don't do anything. if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored()) return RValue::getAggregate(0, false); // The easiest way to do this this is to go through memory, but we // try not to in some easy cases. if (atomics.getEvaluationKind() == TEK_Scalar && !atomics.hasPadding()) { llvm::Type *resultTy = CGM.getTypes().ConvertTypeForMem(valueType); if (isa<llvm::IntegerType>(resultTy)) { assert(result->getType() == resultTy); result = EmitFromMemory(result, valueType); } else if (isa<llvm::PointerType>(resultTy)) { result = Builder.CreateIntToPtr(result, resultTy); } else { result = Builder.CreateBitCast(result, resultTy); } return RValue::get(result); } // Create a temporary. This needs to be big enough to hold the // atomic integer. llvm::Value *temp; bool tempIsVolatile = false; CharUnits tempAlignment; if (atomics.getEvaluationKind() == TEK_Aggregate) { assert(!resultSlot.isIgnored()); temp = resultSlot.getAddr(); tempAlignment = atomics.getValueAlignment(); tempIsVolatile = resultSlot.isVolatile(); } else { temp = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp"); tempAlignment = atomics.getAtomicAlignment(); } // Slam the integer into the temporary. llvm::Value *castTemp = atomics.emitCastToAtomicIntPointer(temp); Builder.CreateAlignedStore(result, castTemp, tempAlignment.getQuantity()) ->setVolatile(tempIsVolatile); return atomics.convertTempToRValue(temp, resultSlot, loc); }