Commit f61d5b22 by Jim Stichnoth

Fix x86 floating-point constant emission.

Previously, the basis of constant pooling was implemented, but two things were lacking: 1. The constant pools were not being emitted in the asm file. 2. A direct FP value was emitted in an FP instruction, e.g. "addss xmm0, 1.0000e00". Curiously, at least for some FP constants, llvm-mc was accepting this syntax. BUG= none R=jfb@chromium.org Review URL: https://codereview.chromium.org/291213003
parent bc643135
......@@ -61,6 +61,7 @@ typedef std::list<Inst *> InstList;
typedef std::list<InstPhi *> PhiList;
typedef std::vector<Variable *> VarList;
typedef std::vector<CfgNode *> NodeList;
typedef std::vector<Constant *> ConstantList;
// SizeT is for holding small-ish limits like number of source
// operands in an instruction. It is used instead of size_t (which
......
......@@ -34,16 +34,27 @@ class TypePool {
TypePool &operator=(const TypePool &) LLVM_DELETED_FUNCTION;
public:
TypePool() {}
TypePool() : NextPoolID(0) {}
ValueType *getOrAdd(GlobalContext *Ctx, Type Ty, KeyType Key) {
TupleType TupleKey = std::make_pair(Ty, Key);
typename ContainerType::const_iterator Iter = Pool.find(TupleKey);
if (Iter != Pool.end())
return Iter->second;
ValueType *Result = ValueType::create(Ctx, Ty, Key);
ValueType *Result = ValueType::create(Ctx, Ty, Key, NextPoolID++);
Pool[TupleKey] = Result;
return Result;
}
ConstantList getConstantPool() const {
ConstantList Constants;
Constants.reserve(Pool.size());
// TODO: replace the loop with std::transform + lambdas.
for (typename ContainerType::const_iterator I = Pool.begin(),
E = Pool.end();
I != E; ++I) {
Constants.push_back(I->second);
}
return Constants;
}
private:
typedef std::pair<Type, KeyType> TupleType;
......@@ -58,6 +69,7 @@ private:
};
typedef std::map<const TupleType, ValueType *, TupleCompare> ContainerType;
ContainerType Pool;
uint32_t NextPoolID;
};
// The global constant pool bundles individual pools of each type of
......@@ -171,6 +183,25 @@ Constant *GlobalContext::getConstantSym(Type Ty, int64_t Offset,
this, Ty, RelocatableTuple(Offset, Name, SuppressMangling));
}
ConstantList GlobalContext::getConstantPool(Type Ty) const {
switch (Ty) {
case IceType_i1:
case IceType_i8:
case IceType_i16:
case IceType_i32:
case IceType_i64:
return ConstPool->Integers.getConstantPool();
case IceType_f32:
return ConstPool->Floats.getConstantPool();
case IceType_f64:
return ConstPool->Doubles.getConstantPool();
case IceType_void:
case IceType_NUM:
break;
}
llvm_unreachable("Unknown type");
}
void Timer::printElapsedUs(GlobalContext *Ctx, const IceString &Tag) const {
if (Ctx->isVerbose(IceV_Timing)) {
// Prefixing with '#' allows timing strings to be included
......
......@@ -77,6 +77,9 @@ public:
// Returns a symbolic constant.
Constant *getConstantSym(Type Ty, int64_t Offset, const IceString &Name = "",
bool SuppressMangling = false);
// getConstantPool() returns a copy of the constant pool for
// constants of a given type.
ConstantList getConstantPool(Type Ty) const;
// Allocate data of type T using the global allocator.
template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
......
......@@ -80,6 +80,7 @@ private:
// constants are allocated from a global arena and are pooled.
class Constant : public Operand {
public:
uint32_t getPoolEntryID() const { return PoolEntryID; }
virtual void emit(const Cfg *Func) const = 0;
virtual void dump(const Cfg *Func) const = 0;
......@@ -89,11 +90,16 @@ public:
}
protected:
Constant(OperandKind Kind, Type Ty) : Operand(Kind, Ty) {
Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID)
: Operand(Kind, Ty), PoolEntryID(PoolEntryID) {
Vars = NULL;
NumVars = 0;
}
virtual ~Constant() {}
// PoolEntryID is an integer that uniquely identifies the constant
// within its constant pool. It is used for building the constant
// pool in the object code and for referencing its entries.
const uint32_t PoolEntryID;
private:
Constant(const Constant &) LLVM_DELETED_FUNCTION;
......@@ -104,9 +110,10 @@ private:
template <typename T, Operand::OperandKind K>
class ConstantPrimitive : public Constant {
public:
static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value) {
static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value,
uint32_t PoolEntryID) {
return new (Ctx->allocate<ConstantPrimitive>())
ConstantPrimitive(Ty, Value);
ConstantPrimitive(Ty, Value, PoolEntryID);
}
T getValue() const { return Value; }
virtual void emit(const Cfg *Func) const {
......@@ -123,7 +130,8 @@ public:
}
private:
ConstantPrimitive(Type Ty, T Value) : Constant(K, Ty), Value(Value) {}
ConstantPrimitive(Type Ty, T Value, uint32_t PoolEntryID)
: Constant(K, Ty, PoolEntryID), Value(Value) {}
ConstantPrimitive(const ConstantPrimitive &) LLVM_DELETED_FUNCTION;
ConstantPrimitive &operator=(const ConstantPrimitive &) LLVM_DELETED_FUNCTION;
virtual ~ConstantPrimitive() {}
......@@ -161,9 +169,10 @@ bool operator<(const RelocatableTuple &A, const RelocatableTuple &B);
class ConstantRelocatable : public Constant {
public:
static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty,
const RelocatableTuple &Tuple) {
const RelocatableTuple &Tuple,
uint32_t PoolEntryID) {
return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable(
Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling);
Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling, PoolEntryID);
}
int64_t getOffset() const { return Offset; }
IceString getName() const { return Name; }
......@@ -179,9 +188,9 @@ public:
private:
ConstantRelocatable(Type Ty, int64_t Offset, const IceString &Name,
bool SuppressMangling)
: Constant(kConstRelocatable, Ty), Offset(Offset), Name(Name),
SuppressMangling(SuppressMangling) {}
bool SuppressMangling, uint32_t PoolEntryID)
: Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset),
Name(Name), SuppressMangling(SuppressMangling) {}
ConstantRelocatable(const ConstantRelocatable &) LLVM_DELETED_FUNCTION;
ConstantRelocatable &
operator=(const ConstantRelocatable &) LLVM_DELETED_FUNCTION;
......
......@@ -149,6 +149,8 @@ public:
virtual void addProlog(CfgNode *Node) = 0;
virtual void addEpilog(CfgNode *Node) = 0;
virtual void emitConstants() const = 0;
virtual ~TargetLowering() {}
protected:
......
......@@ -562,6 +562,71 @@ void TargetX8632::addEpilog(CfgNode *Node) {
}
}
template <typename T> struct PoolTypeConverter {};
template <> struct PoolTypeConverter<float> {
typedef float PrimitiveFpType;
typedef uint32_t PrimitiveIntType;
typedef ConstantFloat IceType;
static const Type Ty = IceType_f32;
static const char *TypeName;
static const char *AsmTag;
static const char *PrintfString;
};
const char *PoolTypeConverter<float>::TypeName = "float";
const char *PoolTypeConverter<float>::AsmTag = ".long";
const char *PoolTypeConverter<float>::PrintfString = "0x%x";
template <> struct PoolTypeConverter<double> {
typedef double PrimitiveFpType;
typedef uint64_t PrimitiveIntType;
typedef ConstantDouble IceType;
static const Type Ty = IceType_f64;
static const char *TypeName;
static const char *AsmTag;
static const char *PrintfString;
};
const char *PoolTypeConverter<double>::TypeName = "double";
const char *PoolTypeConverter<double>::AsmTag = ".quad";
const char *PoolTypeConverter<double>::PrintfString = "0x%llx";
template <typename T> void TargetX8632::emitConstantPool() const {
Ostream &Str = Ctx->getStrEmit();
Type Ty = T::Ty;
SizeT Align = typeAlignInBytes(Ty);
ConstantList Pool = Ctx->getConstantPool(Ty);
Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align
<< "\n";
Str << "\t.align\t" << Align << "\n";
for (ConstantList::const_iterator I = Pool.begin(), E = Pool.end(); I != E;
++I) {
typename T::IceType *Const = llvm::cast<typename T::IceType>(*I);
typename T::PrimitiveFpType Value = Const->getValue();
// Use memcpy() to copy bits from Value into RawValue in a way
// that avoids breaking strict-aliasing rules.
typename T::PrimitiveIntType RawValue;
memcpy(&RawValue, &Value, sizeof(Value));
char buf[30];
int CharsPrinted =
snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue);
assert(CharsPrinted >= 0 &&
(size_t)CharsPrinted < llvm::array_lengthof(buf));
(void)CharsPrinted; // avoid warnings if asserts are disabled
Str << "L$" << Ty << "$" << Const->getPoolEntryID() << ":\n";
Str << "\t" << T::AsmTag << "\t" << buf << "\t# " << T::TypeName << " "
<< Value << "\n";
}
}
void TargetX8632::emitConstants() const {
emitConstantPool<PoolTypeConverter<float> >();
emitConstantPool<PoolTypeConverter<double> >();
// No need to emit constants from the int pool since (for x86) they
// are embedded as immediates in the instructions.
}
void TargetX8632::split64(Variable *Var) {
switch (Var->getType()) {
default:
......@@ -1878,4 +1943,16 @@ void TargetX8632::postLower() {
}
}
template <> void ConstantFloat::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit();
// It would be better to prefix with ".L$" instead of "L$", but
// llvm-mc doesn't parse "dword ptr [.L$foo]".
Str << "dword ptr [L$" << IceType_f32 << "$" << getPoolEntryID() << "]";
}
template <> void ConstantDouble::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit();
Str << "qword ptr [L$" << IceType_f64 << "$" << getPoolEntryID() << "]";
}
} // end of namespace Ice
......@@ -47,6 +47,7 @@ public:
virtual void emitVariable(const Variable *Var, const Cfg *Func) const;
virtual void addProlog(CfgNode *Node);
virtual void addEpilog(CfgNode *Node);
virtual void emitConstants() const;
SizeT makeNextLabelNumber() { return NextLabelNumber++; }
// Ensure that a 64-bit Variable has been split into 2 32-bit
// Variables, creating them if necessary. This is needed for all
......@@ -261,8 +262,12 @@ private:
TargetX8632(const TargetX8632 &) LLVM_DELETED_FUNCTION;
TargetX8632 &operator=(const TargetX8632 &) LLVM_DELETED_FUNCTION;
virtual ~TargetX8632() {}
template <typename T> void emitConstantPool() const;
};
template <> void ConstantFloat::emit(const Cfg *Func) const;
template <> void ConstantDouble::emit(const Cfg *Func) const;
} // end of namespace Ice
#endif // SUBZERO_SRC_ICETARGETLOWERINGX8632_H
......@@ -19,6 +19,7 @@
#include "IceGlobalContext.h"
#include "IceInst.h"
#include "IceOperand.h"
#include "IceTargetLowering.h"
#include "IceTypes.h"
#include "llvm/IR/Constant.h"
......@@ -63,6 +64,7 @@ public:
SubzeroPointerType = Ice::IceType_i32;
}
// Caller is expected to delete the returned Ice::Cfg object.
Ice::Cfg *convertFunction(const Function *F) {
VarMap.clear();
NodeMap.clear();
......@@ -618,14 +620,11 @@ DisableTranslation("notranslate", cl::desc("Disable Subzero translation"));
static cl::opt<bool> SubzeroTimingEnabled(
"timing", cl::desc("Enable breakdown timing of Subzero translation"));
static cl::opt<NaClFileFormat>
InputFileFormat(
"bitcode-format",
cl::desc("Define format of input file:"),
cl::values(
clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
clEnumValEnd),
static cl::opt<NaClFileFormat> InputFileFormat(
"bitcode-format", cl::desc("Define format of input file:"),
cl::values(clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
clEnumValEnd),
cl::init(LLVMFormat));
int main(int argc, char **argv) {
......@@ -670,6 +669,15 @@ int main(int argc, char **argv) {
raw_os_ostream *Ls = new raw_os_ostream(LogFilename == "-" ? std::cout : Lfs);
Ls->SetUnbuffered();
// Ideally, Func would be declared inside the loop and its object
// would be automatically deleted at the end of the loop iteration.
// However, emitting the constant pool requires a valid Cfg object,
// so we need to defer deleting the last non-empty Cfg object until
// outside the loop and after emitting the constant pool. TODO:
// Since all constants are globally pooled in the Ice::GlobalContext
// object, change all Ice::Constant related functions to use
// GlobalContext instead of Cfg, and then clean up this loop.
OwningPtr<Ice::Cfg> Func;
Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix);
for (Module::const_iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
......@@ -678,7 +686,7 @@ int main(int argc, char **argv) {
LLVM2ICEConverter FunctionConverter(&Ctx);
Ice::Timer TConvert;
Ice::Cfg *Func = FunctionConverter.convertFunction(I);
Func.reset(FunctionConverter.convertFunction(I));
if (DisableInternal)
Func->setInternal(false);
......@@ -713,5 +721,8 @@ int main(int argc, char **argv) {
}
}
if (!DisableTranslation && Func)
Func->getTarget()->emitConstants();
return ExitStatus;
}
......@@ -6,6 +6,7 @@
; number in a reasonable number of digits". See
; http://llvm.org/docs/LangRef.html#simple-constants .
; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s
; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
......@@ -534,5 +535,16 @@ return: ; preds = %entry, %sw.bb65, %s
ret double %retval.0
}
; The FP constant pool entries for each type are dumped in some
; implementation-dependent order. So for the purposes of lit, we just
; pick one value for each type, and make sure it appears exactly once.
; Check for float 0.5
; CHECK: .long 0x3f000000
; CHECK-NOT: .long 0x3f000000
; Check for double 0.5
; CHECK: .quad 0x3fe0000000000000
; CHECK-NOT: .quad 0x3fe0000000000000
; ERRORS-NOT: ICE translation error
; DUMP-NOT: SZ
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment