mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-17 03:24:34 +00:00
intended to save size (and does on small programs), but on big programs it actually increases the size of the program slightly. The deal is that many functions end up using the characters that the string contained, and the characters are no longer in the global constant table, so they have to be emitted in function specific constant pools. This pessimization will be fixed in subsequent patches. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10864 91177308-0d34-0410-b5e6-96231b3b80d8
258 lines
8.1 KiB
C++
258 lines
8.1 KiB
C++
//===-- ConstantWriter.cpp - Functions for writing constants --------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file was developed by the LLVM research group and is distributed under
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the routines for encoding constants to a bytecode
|
|
// stream.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "WriterInternals.h"
|
|
#include "llvm/Constants.h"
|
|
#include "llvm/SymbolTable.h"
|
|
#include "llvm/DerivedTypes.h"
|
|
#include "Support/Statistic.h"
|
|
using namespace llvm;
|
|
|
|
static Statistic<>
|
|
TypeBytes("bytecodewriter", "Bytes of types");
|
|
static Statistic<>
|
|
ConstantBytes("bytecodewriter", "Bytes of constants");
|
|
static Statistic<>
|
|
NumConstants("bytecodewriter", "Number of constants");
|
|
|
|
static Statistic<>
|
|
NumStrConstants("bytecodewriter", "Number of string constants");
|
|
static Statistic<>
|
|
NumStrBytes("bytecodewriter", "Number of string constant bytes");
|
|
|
|
|
|
void BytecodeWriter::outputType(const Type *T) {
|
|
TypeBytes -= Out.size();
|
|
output_vbr((unsigned)T->getPrimitiveID(), Out);
|
|
|
|
// That's all there is to handling primitive types...
|
|
if (T->isPrimitiveType()) {
|
|
TypeBytes += Out.size();
|
|
return; // We might do this if we alias a prim type: %x = type int
|
|
}
|
|
|
|
switch (T->getPrimitiveID()) { // Handle derived types now.
|
|
case Type::FunctionTyID: {
|
|
const FunctionType *MT = cast<FunctionType>(T);
|
|
int Slot = Table.getSlot(MT->getReturnType());
|
|
assert(Slot != -1 && "Type used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
|
|
// Output the number of arguments to method (+1 if varargs):
|
|
output_vbr((unsigned)MT->getParamTypes().size()+MT->isVarArg(), Out);
|
|
|
|
// Output all of the arguments...
|
|
FunctionType::ParamTypes::const_iterator I = MT->getParamTypes().begin();
|
|
for (; I != MT->getParamTypes().end(); ++I) {
|
|
Slot = Table.getSlot(*I);
|
|
assert(Slot != -1 && "Type used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
}
|
|
|
|
// Terminate list with VoidTy if we are a varargs function...
|
|
if (MT->isVarArg())
|
|
output_vbr((unsigned)Type::VoidTy->getPrimitiveID(), Out);
|
|
break;
|
|
}
|
|
|
|
case Type::ArrayTyID: {
|
|
const ArrayType *AT = cast<ArrayType>(T);
|
|
int Slot = Table.getSlot(AT->getElementType());
|
|
assert(Slot != -1 && "Type used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
//std::cerr << "Type slot = " << Slot << " Type = " << T->getName() << endl;
|
|
|
|
output_vbr(AT->getNumElements(), Out);
|
|
break;
|
|
}
|
|
|
|
case Type::StructTyID: {
|
|
const StructType *ST = cast<StructType>(T);
|
|
|
|
// Output all of the element types...
|
|
StructType::ElementTypes::const_iterator I = ST->getElementTypes().begin();
|
|
for (; I != ST->getElementTypes().end(); ++I) {
|
|
int Slot = Table.getSlot(*I);
|
|
assert(Slot != -1 && "Type used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
}
|
|
|
|
// Terminate list with VoidTy
|
|
output_vbr((unsigned)Type::VoidTy->getPrimitiveID(), Out);
|
|
break;
|
|
}
|
|
|
|
case Type::PointerTyID: {
|
|
const PointerType *PT = cast<PointerType>(T);
|
|
int Slot = Table.getSlot(PT->getElementType());
|
|
assert(Slot != -1 && "Type used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
break;
|
|
}
|
|
|
|
case Type::OpaqueTyID: {
|
|
// No need to emit anything, just the count of opaque types is enough.
|
|
break;
|
|
}
|
|
|
|
//case Type::PackedTyID:
|
|
default:
|
|
std::cerr << __FILE__ << ":" << __LINE__ << ": Don't know how to serialize"
|
|
<< " Type '" << T->getDescription() << "'\n";
|
|
break;
|
|
}
|
|
TypeBytes += Out.size();
|
|
}
|
|
|
|
void BytecodeWriter::outputConstant(const Constant *CPV) {
|
|
ConstantBytes -= Out.size();
|
|
assert((CPV->getType()->isPrimitiveType() || !CPV->isNullValue()) &&
|
|
"Shouldn't output null constants!");
|
|
|
|
++NumConstants;
|
|
|
|
// We must check for a ConstantExpr before switching by type because
|
|
// a ConstantExpr can be of any type, and has no explicit value.
|
|
//
|
|
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CPV)) {
|
|
// FIXME: Encoding of constant exprs could be much more compact!
|
|
assert(CE->getNumOperands() > 0 && "ConstantExpr with 0 operands");
|
|
output_vbr(CE->getNumOperands(), Out); // flags as an expr
|
|
output_vbr(CE->getOpcode(), Out); // flags as an expr
|
|
|
|
for (User::const_op_iterator OI = CE->op_begin(); OI != CE->op_end(); ++OI){
|
|
int Slot = Table.getSlot(*OI);
|
|
assert(Slot != -1 && "Unknown constant used in ConstantExpr!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
Slot = Table.getSlot((*OI)->getType());
|
|
output_vbr((unsigned)Slot, Out);
|
|
}
|
|
ConstantBytes += Out.size();
|
|
return;
|
|
} else {
|
|
output_vbr(0U, Out); // flag as not a ConstantExpr
|
|
}
|
|
|
|
switch (CPV->getType()->getPrimitiveID()) {
|
|
case Type::BoolTyID: // Boolean Types
|
|
if (cast<ConstantBool>(CPV)->getValue())
|
|
output_vbr(1U, Out);
|
|
else
|
|
output_vbr(0U, Out);
|
|
break;
|
|
|
|
case Type::UByteTyID: // Unsigned integer types...
|
|
case Type::UShortTyID:
|
|
case Type::UIntTyID:
|
|
case Type::ULongTyID:
|
|
output_vbr(cast<ConstantUInt>(CPV)->getValue(), Out);
|
|
break;
|
|
|
|
case Type::SByteTyID: // Signed integer types...
|
|
case Type::ShortTyID:
|
|
case Type::IntTyID:
|
|
case Type::LongTyID:
|
|
output_vbr(cast<ConstantSInt>(CPV)->getValue(), Out);
|
|
break;
|
|
|
|
case Type::TypeTyID: // Serialize type type
|
|
assert(0 && "Types should not be in the Constant!");
|
|
break;
|
|
|
|
case Type::ArrayTyID: {
|
|
const ConstantArray *CPA = cast<ConstantArray>(CPV);
|
|
assert(!CPA->isString() && "Constant strings should be handled specially!");
|
|
|
|
for (unsigned i = 0; i != CPA->getNumOperands(); ++i) {
|
|
int Slot = Table.getSlot(CPA->getOperand(i));
|
|
assert(Slot != -1 && "Constant used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Type::StructTyID: {
|
|
const ConstantStruct *CPS = cast<ConstantStruct>(CPV);
|
|
const std::vector<Use> &Vals = CPS->getValues();
|
|
|
|
for (unsigned i = 0; i < Vals.size(); ++i) {
|
|
int Slot = Table.getSlot(Vals[i]);
|
|
assert(Slot != -1 && "Constant used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Type::PointerTyID: {
|
|
const ConstantPointerRef *CPR = cast<ConstantPointerRef>(CPV);
|
|
int Slot = Table.getSlot((Value*)CPR->getValue());
|
|
assert(Slot != -1 && "Global used but not available!!");
|
|
output_vbr((unsigned)Slot, Out);
|
|
break;
|
|
}
|
|
|
|
case Type::FloatTyID: { // Floating point types...
|
|
float Tmp = (float)cast<ConstantFP>(CPV)->getValue();
|
|
output_data(&Tmp, &Tmp+1, Out);
|
|
break;
|
|
}
|
|
case Type::DoubleTyID: {
|
|
double Tmp = cast<ConstantFP>(CPV)->getValue();
|
|
output_data(&Tmp, &Tmp+1, Out);
|
|
break;
|
|
}
|
|
|
|
case Type::VoidTyID:
|
|
case Type::LabelTyID:
|
|
default:
|
|
std::cerr << __FILE__ << ":" << __LINE__ << ": Don't know how to serialize"
|
|
<< " type '" << CPV->getType()->getName() << "'\n";
|
|
break;
|
|
}
|
|
ConstantBytes += Out.size();
|
|
return;
|
|
}
|
|
|
|
void BytecodeWriter::outputConstantStrings() {
|
|
SlotCalculator::string_iterator I = Table.string_begin();
|
|
SlotCalculator::string_iterator E = Table.string_end();
|
|
if (I == E) return; // No strings to emit
|
|
|
|
// If we have != 0 strings to emit, output them now. Strings are emitted into
|
|
// the 'void' type plane.
|
|
output_vbr(unsigned(E-I), Out);
|
|
output_vbr(Type::VoidTyID, Out);
|
|
|
|
ConstantBytes -= Out.size();
|
|
NumStrBytes -= Out.size();;
|
|
|
|
// Emit all of the strings.
|
|
for (I = Table.string_begin(); I != E; ++I) {
|
|
const ConstantArray *Str = *I;
|
|
int Slot = Table.getSlot(Str->getType());
|
|
assert(Slot != -1 && "Constant string of unknown type?");
|
|
output_vbr((unsigned)Slot, Out);
|
|
|
|
// Now that we emitted the type (which indicates the size of the string),
|
|
// emit all of the characters.
|
|
std::string Val = Str->getAsString();
|
|
output_data(Val.c_str(), Val.c_str()+Val.size(), Out);
|
|
|
|
++NumConstants;
|
|
++NumStrConstants;
|
|
}
|
|
ConstantBytes += Out.size();
|
|
NumStrBytes += Out.size();;
|
|
}
|