// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Operand* ConstantFolder::LoadFromGlobal(Operand* op, const Type* loadType, __int64 offset) { // If the operand is not a reference to a global variable then we can't do anything, // even if the variable may be a constant. auto variableRef = op->As<VariableReference>(); if(variableRef == nullptr) { return nullptr; } auto globalVar = variableRef->GetGlobal(); if(globalVar == nullptr) { return nullptr; } // It's a global variable, now make sure that it's a constant // with an initializer that is not a tentative definition. if((globalVar->HasInitializer() == false) || (globalVar->IsConstant() == false) || globalVar->IsTentative()) { return nullptr; } // If the offset is negative or larger than the size of the type we give up // (some bytes may be available, but it's not worth the effort trying to extract them). if(IsValidOffset(globalVar, loadType, offset) == false) { return nullptr; } // If this is a simple value load it now; this is the common case. // Note that we can't load the value if it originates from something like // 'int a = (int)&a;', because it's not a compile-time constant. // An exception is when we the converted operand is 0 or a null pointer. if(globalVar->HasZeroInitializer()) { // The variable is initialized only with zeros, so the offset // doesn't matter as long as it's valid (and we checked that above). __int64 data = 0; return GetOperandHavingData((unsigned char*)&data, 8, loadType); } Initializer* initializer = globalVar->GetInitializer(); DebugValidator::IsNotNull(initializer); if(initializer->IsInitializerList() == false) { return LoadFromInitializer(initializer, loadType, offset); } // We have an initializer list, try to compute the index // of the initializer from which we should load. return LoadFromOffset(initializer, globalVar->GetType(), loadType, offset); }