Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
cfe/trunk/lib/CodeGen/CGDecl.cpp
Show First 20 Lines • Show All 942 Lines • ▼ Show 20 Lines | static bool shouldUseBZeroPlusStoresToInitialize(llvm::Constant *Init, | ||||
// plopping in more stores. | // plopping in more stores. | ||||
unsigned StoreBudget = 6; | unsigned StoreBudget = 6; | ||||
uint64_t SizeLimit = 32; | uint64_t SizeLimit = 32; | ||||
return GlobalSize > SizeLimit && | return GlobalSize > SizeLimit && | ||||
canEmitInitWithFewStoresAfterBZero(Init, StoreBudget); | canEmitInitWithFewStoresAfterBZero(Init, StoreBudget); | ||||
} | } | ||||
/// A byte pattern. | |||||
/// | |||||
/// Can be "any" pattern if the value was padding or known to be undef. | |||||
/// Can be "none" pattern if a sequence doesn't exist. | |||||
class BytePattern { | |||||
uint8_t Val; | |||||
enum class ValueType : uint8_t { Specific, Any, None } Type; | |||||
BytePattern(ValueType Type) : Type(Type) {} | |||||
public: | |||||
BytePattern(uint8_t Value) : Val(Value), Type(ValueType::Specific) {} | |||||
static BytePattern Any() { return BytePattern(ValueType::Any); } | |||||
static BytePattern None() { return BytePattern(ValueType::None); } | |||||
bool isAny() const { return Type == ValueType::Any; } | |||||
bool isNone() const { return Type == ValueType::None; } | |||||
bool isValued() const { return Type == ValueType::Specific; } | |||||
uint8_t getValue() const { | |||||
assert(isValued()); | |||||
return Val; | |||||
} | |||||
BytePattern merge(const BytePattern Other) const { | |||||
if (isNone() || Other.isNone()) | |||||
return None(); | |||||
if (isAny()) | |||||
return Other; | |||||
if (Other.isAny()) | |||||
return *this; | |||||
if (getValue() == Other.getValue()) | |||||
return *this; | |||||
return None(); | |||||
} | |||||
}; | |||||
/// Figures out whether the constant can be initialized with memset. | |||||
static BytePattern constantIsRepeatedBytePattern(llvm::Constant *C) { | |||||
if (isa<llvm::ConstantAggregateZero>(C) || isa<llvm::ConstantPointerNull>(C)) | |||||
return BytePattern(0x00); | |||||
if (isa<llvm::UndefValue>(C)) | |||||
return BytePattern::Any(); | |||||
if (isa<llvm::ConstantInt>(C)) { | |||||
auto *Int = cast<llvm::ConstantInt>(C); | |||||
if (Int->getBitWidth() % 8 != 0) | |||||
return BytePattern::None(); | |||||
const llvm::APInt &Value = Int->getValue(); | |||||
if (Value.isSplat(8)) | |||||
return BytePattern(Value.getLoBits(8).getLimitedValue()); | |||||
return BytePattern::None(); | |||||
} | |||||
if (isa<llvm::ConstantFP>(C)) { | |||||
auto *FP = cast<llvm::ConstantFP>(C); | |||||
llvm::APInt Bits = FP->getValueAPF().bitcastToAPInt(); | |||||
if (Bits.getBitWidth() % 8 != 0) | |||||
return BytePattern::None(); | |||||
if (!Bits.isSplat(8)) | |||||
return BytePattern::None(); | |||||
return BytePattern(Bits.getLimitedValue() & 0xFF); | |||||
} | |||||
if (isa<llvm::ConstantVector>(C)) { | |||||
llvm::Constant *Splat = cast<llvm::ConstantVector>(C)->getSplatValue(); | |||||
if (Splat) | |||||
return constantIsRepeatedBytePattern(Splat); | |||||
return BytePattern::None(); | |||||
} | |||||
if (isa<llvm::ConstantArray>(C) || isa<llvm::ConstantStruct>(C)) { | |||||
BytePattern Pattern(BytePattern::Any()); | |||||
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) { | |||||
llvm::Constant *Elt = cast<llvm::Constant>(C->getOperand(I)); | |||||
Pattern = Pattern.merge(constantIsRepeatedBytePattern(Elt)); | |||||
if (Pattern.isNone()) | |||||
return Pattern; | |||||
} | |||||
return Pattern; | |||||
} | |||||
if (llvm::ConstantDataSequential *CDS = | |||||
dyn_cast<llvm::ConstantDataSequential>(C)) { | |||||
BytePattern Pattern(BytePattern::Any()); | |||||
for (unsigned I = 0, E = CDS->getNumElements(); I != E; ++I) { | |||||
llvm::Constant *Elt = CDS->getElementAsConstant(I); | |||||
Pattern = Pattern.merge(constantIsRepeatedBytePattern(Elt)); | |||||
if (Pattern.isNone()) | |||||
return Pattern; | |||||
} | |||||
return Pattern; | |||||
} | |||||
// BlockAddress, ConstantExpr, and everything else is scary. | |||||
return BytePattern::None(); | |||||
} | |||||
/// Decide whether we should use memset to initialize a local variable instead | |||||
/// of using a memcpy from a constant global. Assumes we've already decided to | |||||
/// not user bzero. | |||||
/// FIXME We could be more clever, as we are for bzero above, and generate | |||||
/// memset followed by stores. It's unclear that's worth the effort. | |||||
static BytePattern shouldUseMemSetToInitialize(llvm::Constant *Init, | |||||
uint64_t GlobalSize) { | |||||
uint64_t SizeLimit = 32; | |||||
if (GlobalSize <= SizeLimit) | |||||
return BytePattern::None(); | |||||
return constantIsRepeatedBytePattern(Init); | |||||
} | |||||
/// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a | /// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a | ||||
/// variable declaration with auto, register, or no storage class specifier. | /// variable declaration with auto, register, or no storage class specifier. | ||||
/// These turn into simple stack objects, or GlobalValues depending on target. | /// These turn into simple stack objects, or GlobalValues depending on target. | ||||
void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) { | void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) { | ||||
AutoVarEmission emission = EmitAutoVarAlloca(D); | AutoVarEmission emission = EmitAutoVarAlloca(D); | ||||
EmitAutoVarInit(emission); | EmitAutoVarInit(emission); | ||||
EmitAutoVarCleanups(emission); | EmitAutoVarCleanups(emission); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 437 Lines • ▼ Show 20 Lines | void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { | ||||
llvm::Value *SizeVal = | llvm::Value *SizeVal = | ||||
llvm::ConstantInt::get(IntPtrTy, | llvm::ConstantInt::get(IntPtrTy, | ||||
getContext().getTypeSizeInChars(type).getQuantity()); | getContext().getTypeSizeInChars(type).getQuantity()); | ||||
llvm::Type *BP = CGM.Int8Ty->getPointerTo(Loc.getAddressSpace()); | llvm::Type *BP = CGM.Int8Ty->getPointerTo(Loc.getAddressSpace()); | ||||
if (Loc.getType() != BP) | if (Loc.getType() != BP) | ||||
Loc = Builder.CreateBitCast(Loc, BP); | Loc = Builder.CreateBitCast(Loc, BP); | ||||
// If the initializer is all or mostly zeros, codegen with bzero then do a | // If the initializer is all or mostly the same, codegen with bzero / memset | ||||
// few stores afterward. | // then do a few stores afterward. | ||||
if (shouldUseBZeroPlusStoresToInitialize( | uint64_t ConstantSize = | ||||
constant, | CGM.getDataLayout().getTypeAllocSize(constant->getType()); | ||||
CGM.getDataLayout().getTypeAllocSize(constant->getType()))) { | if (shouldUseBZeroPlusStoresToInitialize(constant, ConstantSize)) { | ||||
Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal, | Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal, | ||||
isVolatile); | isVolatile); | ||||
// Zero and undef don't require a stores. | // Zero and undef don't require a stores. | ||||
if (!constant->isNullValue() && !isa<llvm::UndefValue>(constant)) { | if (!constant->isNullValue() && !isa<llvm::UndefValue>(constant)) { | ||||
Loc = Builder.CreateBitCast(Loc, | Loc = Builder.CreateBitCast(Loc, | ||||
constant->getType()->getPointerTo(Loc.getAddressSpace())); | constant->getType()->getPointerTo(Loc.getAddressSpace())); | ||||
emitStoresForInitAfterBZero(CGM, constant, Loc, isVolatile, Builder); | emitStoresForInitAfterBZero(CGM, constant, Loc, isVolatile, Builder); | ||||
} | } | ||||
} else { | return; | ||||
} | |||||
BytePattern Pattern = shouldUseMemSetToInitialize(constant, ConstantSize); | |||||
if (!Pattern.isNone()) { | |||||
uint8_t Value = Pattern.isAny() ? 0x00 : Pattern.getValue(); | |||||
Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, Value), SizeVal, | |||||
isVolatile); | |||||
return; | |||||
} | |||||
// Otherwise, create a temporary global with the initializer then | // Otherwise, create a temporary global with the initializer then | ||||
// memcpy from the global to the alloca. | // memcpy from the global to the alloca. | ||||
std::string Name = getStaticDeclName(CGM, D); | std::string Name = getStaticDeclName(CGM, D); | ||||
unsigned AS = CGM.getContext().getTargetAddressSpace( | unsigned AS = CGM.getContext().getTargetAddressSpace( | ||||
CGM.getStringLiteralAddressSpace()); | CGM.getStringLiteralAddressSpace()); | ||||
BP = llvm::PointerType::getInt8PtrTy(getLLVMContext(), AS); | BP = llvm::PointerType::getInt8PtrTy(getLLVMContext(), AS); | ||||
llvm::GlobalVariable *GV = | llvm::GlobalVariable *GV = new llvm::GlobalVariable( | ||||
new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true, | CGM.getModule(), constant->getType(), true, | ||||
llvm::GlobalValue::PrivateLinkage, | llvm::GlobalValue::PrivateLinkage, constant, Name, nullptr, | ||||
constant, Name, nullptr, | |||||
llvm::GlobalValue::NotThreadLocal, AS); | llvm::GlobalValue::NotThreadLocal, AS); | ||||
GV->setAlignment(Loc.getAlignment().getQuantity()); | GV->setAlignment(Loc.getAlignment().getQuantity()); | ||||
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); | GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); | ||||
Address SrcPtr = Address(GV, Loc.getAlignment()); | Address SrcPtr = Address(GV, Loc.getAlignment()); | ||||
if (SrcPtr.getType() != BP) | if (SrcPtr.getType() != BP) | ||||
SrcPtr = Builder.CreateBitCast(SrcPtr, BP); | SrcPtr = Builder.CreateBitCast(SrcPtr, BP); | ||||
Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, isVolatile); | Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, isVolatile); | ||||
} | } | ||||
} | |||||
/// Emit an expression as an initializer for an object (variable, field, etc.) | /// Emit an expression as an initializer for an object (variable, field, etc.) | ||||
/// at the given location. The expression is not necessarily the normal | /// at the given location. The expression is not necessarily the normal | ||||
/// initializer for the object, and the address is not necessarily | /// initializer for the object, and the address is not necessarily | ||||
/// its normal location. | /// its normal location. | ||||
/// | /// | ||||
/// \param init the initializing expression | /// \param init the initializing expression | ||||
/// \param D the object to act as if we're initializing | /// \param D the object to act as if we're initializing | ||||
▲ Show 20 Lines • Show All 658 Lines • Show Last 20 Lines |