Several major fixes, particularly in emitting constant aggregates:

(1) Padding bytes between structure fields (for alignment) were never
    being emitted into the constant pool so the layout did not match!
(2) In printing constants, structures containing structures or arrays
    were never handled.
(3) Support new model for external/uninitialized/initialized globals.
    Uninitialized globals are no longer emitted since they are external.
    Initialized globals may go either in .bss or in .data.

llvm-svn: 4134
This commit is contained in:
Vikram S. Adve 2002-10-13 00:32:18 +00:00
parent 78044fbc8e
commit 10d8164013
1 changed files with 105 additions and 60 deletions

View File

@ -60,7 +60,7 @@ public:
Text, Text,
ReadOnlyData, ReadOnlyData,
InitRWData, InitRWData,
UninitRWData, ZeroInitRWData,
} CurSection; } CurSection;
AsmPrinter(std::ostream &os, const TargetMachine &T) AsmPrinter(std::ostream &os, const TargetMachine &T)
@ -105,7 +105,7 @@ public:
case Text: toAsm << "\".text\""; break; case Text: toAsm << "\".text\""; break;
case ReadOnlyData: toAsm << "\".rodata\",#alloc"; break; case ReadOnlyData: toAsm << "\".rodata\",#alloc"; break;
case InitRWData: toAsm << "\".data\",#alloc,#write"; break; case InitRWData: toAsm << "\".data\",#alloc,#write"; break;
case UninitRWData: toAsm << "\".bss\",#alloc,#write"; break; case ZeroInitRWData: toAsm << "\".bss\",#alloc,#write"; break;
} }
toAsm << "\n"; toAsm << "\n";
} }
@ -541,28 +541,29 @@ public:
} }
private: private:
void emitGlobalsAndConstants(const Module &M); void emitGlobalsAndConstants (const Module &M);
void printGlobalVariable(const GlobalVariable *GV); void printGlobalVariable (const GlobalVariable *GV);
void printSingleConstant( const Constant* CV); void PrintZeroBytesToPad (int numBytes);
void printConstantValueOnly(const Constant* CV); void printSingleConstantValue (const Constant* CV);
void printConstant( const Constant* CV, std::string valID = ""); void printConstantValueOnly (const Constant* CV, int numPadBytes = 0);
void printConstant (const Constant* CV, std::string valID = "");
static void FoldConstants(const Module &M, static void FoldConstants (const Module &M,
hash_set<const Constant*> &moduleConstants); hash_set<const Constant*> &moduleConstants);
}; };
// Can we treat the specified array as a string? Only if it is an array of // Can we treat the specified array as a string? Only if it is an array of
// ubytes or non-negative sbytes. // ubytes or non-negative sbytes.
// //
static bool isStringCompatible(const ConstantArray *CPA) { static bool isStringCompatible(const ConstantArray *CVA) {
const Type *ETy = cast<ArrayType>(CPA->getType())->getElementType(); const Type *ETy = cast<ArrayType>(CVA->getType())->getElementType();
if (ETy == Type::UByteTy) return true; if (ETy == Type::UByteTy) return true;
if (ETy != Type::SByteTy) return false; if (ETy != Type::SByteTy) return false;
for (unsigned i = 0; i < CPA->getNumOperands(); ++i) for (unsigned i = 0; i < CVA->getNumOperands(); ++i)
if (cast<ConstantSInt>(CPA->getOperand(i))->getValue() < 0) if (cast<ConstantSInt>(CVA->getOperand(i))->getValue() < 0)
return false; return false;
return true; return true;
@ -576,16 +577,16 @@ static inline char toOctal(int X) {
// getAsCString - Return the specified array as a C compatible string, only if // getAsCString - Return the specified array as a C compatible string, only if
// the predicate isStringCompatible is true. // the predicate isStringCompatible is true.
// //
static string getAsCString(const ConstantArray *CPA) { static string getAsCString(const ConstantArray *CVA) {
assert(isStringCompatible(CPA) && "Array is not string compatible!"); assert(isStringCompatible(CVA) && "Array is not string compatible!");
string Result; string Result;
const Type *ETy = cast<ArrayType>(CPA->getType())->getElementType(); const Type *ETy = cast<ArrayType>(CVA->getType())->getElementType();
Result = "\""; Result = "\"";
for (unsigned i = 0; i < CPA->getNumOperands(); ++i) { for (unsigned i = 0; i < CVA->getNumOperands(); ++i) {
unsigned char C = (ETy == Type::SByteTy) ? unsigned char C = (ETy == Type::SByteTy) ?
(unsigned char)cast<ConstantSInt>(CPA->getOperand(i))->getValue() : (unsigned char)cast<ConstantSInt>(CVA->getOperand(i))->getValue() :
(unsigned char)cast<ConstantUInt>(CPA->getOperand(i))->getValue(); (unsigned char)cast<ConstantUInt>(CVA->getOperand(i))->getValue();
if (C == '"') { if (C == '"') {
Result += "\\\""; Result += "\\\"";
@ -649,24 +650,30 @@ TypeToDataDirective(const Type* type)
} }
} }
// Get the size of the type
//
inline unsigned int
TypeToSize(const Type* type, const TargetMachine& target)
{
return target.findOptimalStorageSize(type);
}
// Get the size of the constant for the given target. // Get the size of the constant for the given target.
// If this is an unsized array, return 0. // If this is an unsized array, return 0.
// //
inline unsigned int inline unsigned int
ConstantToSize(const Constant* CV, const TargetMachine& target) ConstantToSize(const Constant* CV, const TargetMachine& target)
{ {
if (const ConstantArray* CPA = dyn_cast<ConstantArray>(CV)) if (const ConstantArray* CVA = dyn_cast<ConstantArray>(CV))
{ {
const ArrayType *aty = cast<ArrayType>(CPA->getType()); const ArrayType *aty = cast<ArrayType>(CVA->getType());
if (ArrayTypeIsString(aty)) if (ArrayTypeIsString(aty))
return 1 + CPA->getNumOperands(); return 1 + CVA->getNumOperands();
} }
return target.findOptimalStorageSize(CV->getType()); return TypeToSize(CV->getType(), target);
} }
// Align data larger than one L1 cache line on L1 cache line boundaries. // Align data larger than one L1 cache line on L1 cache line boundaries.
// Align all smaller data on the next higher 2^x boundary (4, 8, ...). // Align all smaller data on the next higher 2^x boundary (4, 8, ...).
// //
@ -687,7 +694,7 @@ SizeToAlignment(unsigned int size, const TargetMachine& target)
inline unsigned int inline unsigned int
TypeToAlignment(const Type* type, const TargetMachine& target) TypeToAlignment(const Type* type, const TargetMachine& target)
{ {
return SizeToAlignment(target.findOptimalStorageSize(type), target); return SizeToAlignment(TypeToSize(type, target), target);
} }
// Get the size of the constant and then use SizeToAlignment. // Get the size of the constant and then use SizeToAlignment.
@ -695,9 +702,9 @@ TypeToAlignment(const Type* type, const TargetMachine& target)
inline unsigned int inline unsigned int
ConstantToAlignment(const Constant* CV, const TargetMachine& target) ConstantToAlignment(const Constant* CV, const TargetMachine& target)
{ {
if (const ConstantArray* CPA = dyn_cast<ConstantArray>(CV)) if (const ConstantArray* CVA = dyn_cast<ConstantArray>(CV))
if (ArrayTypeIsString(cast<ArrayType>(CPA->getType()))) if (ArrayTypeIsString(cast<ArrayType>(CVA->getType())))
return SizeToAlignment(1 + CPA->getNumOperands(), target); return SizeToAlignment(1 + CVA->getNumOperands(), target);
return TypeToAlignment(CV->getType(), target); return TypeToAlignment(CV->getType(), target);
} }
@ -705,7 +712,7 @@ ConstantToAlignment(const Constant* CV, const TargetMachine& target)
// Print a single constant value. // Print a single constant value.
void void
SparcModuleAsmPrinter::printSingleConstant(const Constant* CV) SparcModuleAsmPrinter::printSingleConstantValue(const Constant* CV)
{ {
assert(CV->getType() != Type::VoidTy && assert(CV->getType() != Type::VoidTy &&
CV->getType() != Type::TypeTy && CV->getType() != Type::TypeTy &&
@ -759,31 +766,68 @@ SparcModuleAsmPrinter::printSingleConstant(const Constant* CV)
} }
} }
// Print a constant value or values (it may be an aggregate).
// Uses printSingleConstant() to print each individual value.
void void
SparcModuleAsmPrinter::printConstantValueOnly(const Constant* CV) SparcModuleAsmPrinter::PrintZeroBytesToPad(int numBytes)
{ {
const ConstantArray *CPA = dyn_cast<ConstantArray>(CV); for ( ; numBytes >= 8; numBytes -= 8)
printSingleConstantValue(Constant::getNullValue(Type::ULongTy));
if (CPA && isStringCompatible(CPA))
if (numBytes >= 4)
{
printSingleConstantValue(Constant::getNullValue(Type::UIntTy));
numBytes -= 4;
}
while (numBytes--)
printSingleConstantValue(Constant::getNullValue(Type::UByteTy));
}
// Print a constant value or values (it may be an aggregate).
// Uses printSingleConstantValue() to print each individual value.
void
SparcModuleAsmPrinter::printConstantValueOnly(const Constant* CV,
int numPadBytes /* = 0*/)
{
const ConstantArray *CVA = dyn_cast<ConstantArray>(CV);
if (numPadBytes)
PrintZeroBytesToPad(numPadBytes);
if (CVA && isStringCompatible(CVA))
{ // print the string alone and return { // print the string alone and return
toAsm << "\t" << ".ascii" << "\t" << getAsCString(CPA) << "\n"; toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n";
} }
else if (CPA) else if (CVA)
{ // Not a string. Print the values in successive locations { // Not a string. Print the values in successive locations
const std::vector<Use> &constValues = CPA->getValues(); const std::vector<Use> &constValues = CVA->getValues();
for (unsigned i=0; i < constValues.size(); i++) for (unsigned i=0; i < constValues.size(); i++)
printConstantValueOnly(cast<Constant>(constValues[i].get())); printConstantValueOnly(cast<Constant>(constValues[i].get()));
} }
else if (const ConstantStruct *CPS = dyn_cast<ConstantStruct>(CV)) else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV))
{ // Print the fields in successive locations { // Print the fields in successive locations. Pad to align if needed!
const std::vector<Use>& constValues = CPS->getValues(); const StructLayout *cvsLayout =
for (unsigned i=0; i < constValues.size(); i++) Target.DataLayout.getStructLayout(CVS->getType());
printConstantValueOnly(cast<Constant>(constValues[i].get())); const std::vector<Use>& constValues = CVS->getValues();
unsigned sizeSoFar = 0;
for (unsigned i=0, N = constValues.size(); i < N; i++)
{
const Constant* field = cast<Constant>(constValues[i].get());
// Check if padding is needed and insert one or more 0s.
unsigned fieldSize = Target.DataLayout.getTypeSize(field->getType());
int padSize = ((i == N-1? cvsLayout->StructSize
: cvsLayout->MemberOffsets[i+1])
- cvsLayout->MemberOffsets[i]) - fieldSize;
sizeSoFar += (fieldSize + padSize);
// Now print the actual field value
printConstantValueOnly(field, padSize);
}
assert(sizeSoFar == cvsLayout->StructSize &&
"Layout of constant struct may be incorrect!");
} }
else else
printSingleConstant(CV); printSingleConstantValue(CV);
} }
// Print a constant (which may be an aggregate) prefixed by all the // Print a constant (which may be an aggregate) prefixed by all the
@ -798,11 +842,11 @@ SparcModuleAsmPrinter::printConstant(const Constant* CV, string valID)
toAsm << "\t.align\t" << ConstantToAlignment(CV, Target) << "\n"; toAsm << "\t.align\t" << ConstantToAlignment(CV, Target) << "\n";
// Print .size and .type only if it is not a string. // Print .size and .type only if it is not a string.
const ConstantArray *CPA = dyn_cast<ConstantArray>(CV); const ConstantArray *CVA = dyn_cast<ConstantArray>(CV);
if (CPA && isStringCompatible(CPA)) if (CVA && isStringCompatible(CVA))
{ // print it as a string and return { // print it as a string and return
toAsm << valID << ":\n"; toAsm << valID << ":\n";
toAsm << "\t" << ".ascii" << "\t" << getAsCString(CPA) << "\n"; toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n";
return; return;
} }
@ -833,14 +877,14 @@ void SparcModuleAsmPrinter::printGlobalVariable(const GlobalVariable* GV)
if (GV->hasExternalLinkage()) if (GV->hasExternalLinkage())
toAsm << "\t.global\t" << getID(GV) << "\n"; toAsm << "\t.global\t" << getID(GV) << "\n";
if (GV->hasInitializer()) if (GV->hasInitializer() && ! GV->getInitializer()->isNullValue())
printConstant(GV->getInitializer(), getID(GV)); printConstant(GV->getInitializer(), getID(GV));
else { else {
toAsm << "\t.align\t" << TypeToAlignment(GV->getType()->getElementType(), toAsm << "\t.align\t" << TypeToAlignment(GV->getType()->getElementType(),
Target) << "\n"; Target) << "\n";
toAsm << "\t.type\t" << getID(GV) << ",#object\n"; toAsm << "\t.type\t" << getID(GV) << ",#object\n";
toAsm << "\t.reserve\t" << getID(GV) << "," toAsm << "\t.reserve\t" << getID(GV) << ","
<< Target.findOptimalStorageSize(GV->getType()->getElementType()) << TypeToSize(GV->getType()->getElementType(), Target)
<< "\n"; << "\n";
} }
} }
@ -863,17 +907,18 @@ void SparcModuleAsmPrinter::emitGlobalsAndConstants(const Module &M) {
printConstant(*I); printConstant(*I);
// Output global variables... // Output global variables...
for (Module::const_giterator GI = M.gbegin(), GE = M.gend(); GI != GE; ++GI) { for (Module::const_giterator GI = M.gbegin(), GE = M.gend(); GI != GE; ++GI)
if (GI->hasInitializer() && GI->isConstant()) { if (! GI->isExternal()) {
enterSection(AsmPrinter::ReadOnlyData); // read-only, initialized data assert(GI->hasInitializer());
} else if (GI->hasInitializer() && !GI->isConstant()) { // read-write data if (GI->isConstant())
enterSection(AsmPrinter::InitRWData); enterSection(AsmPrinter::ReadOnlyData); // read-only, initialized data
} else { else if (GI->getInitializer()->isNullValue())
assert (!GI->hasInitializer() && "Unexpected global variable type found"); enterSection(AsmPrinter::ZeroInitRWData); // read-write zero data
enterSection(AsmPrinter::UninitRWData); // Uninitialized data else
enterSection(AsmPrinter::InitRWData); // read-write non-zero data
printGlobalVariable(GI);
} }
printGlobalVariable(GI);
}
toAsm << "\n"; toAsm << "\n";
} }