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; ...@@ -61,6 +61,7 @@ typedef std::list<Inst *> InstList;
typedef std::list<InstPhi *> PhiList; typedef std::list<InstPhi *> PhiList;
typedef std::vector<Variable *> VarList; typedef std::vector<Variable *> VarList;
typedef std::vector<CfgNode *> NodeList; typedef std::vector<CfgNode *> NodeList;
typedef std::vector<Constant *> ConstantList;
// SizeT is for holding small-ish limits like number of source // SizeT is for holding small-ish limits like number of source
// operands in an instruction. It is used instead of size_t (which // operands in an instruction. It is used instead of size_t (which
......
...@@ -34,16 +34,27 @@ class TypePool { ...@@ -34,16 +34,27 @@ class TypePool {
TypePool &operator=(const TypePool &) LLVM_DELETED_FUNCTION; TypePool &operator=(const TypePool &) LLVM_DELETED_FUNCTION;
public: public:
TypePool() {} TypePool() : NextPoolID(0) {}
ValueType *getOrAdd(GlobalContext *Ctx, Type Ty, KeyType Key) { ValueType *getOrAdd(GlobalContext *Ctx, Type Ty, KeyType Key) {
TupleType TupleKey = std::make_pair(Ty, Key); TupleType TupleKey = std::make_pair(Ty, Key);
typename ContainerType::const_iterator Iter = Pool.find(TupleKey); typename ContainerType::const_iterator Iter = Pool.find(TupleKey);
if (Iter != Pool.end()) if (Iter != Pool.end())
return Iter->second; return Iter->second;
ValueType *Result = ValueType::create(Ctx, Ty, Key); ValueType *Result = ValueType::create(Ctx, Ty, Key, NextPoolID++);
Pool[TupleKey] = Result; Pool[TupleKey] = Result;
return 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: private:
typedef std::pair<Type, KeyType> TupleType; typedef std::pair<Type, KeyType> TupleType;
...@@ -58,6 +69,7 @@ private: ...@@ -58,6 +69,7 @@ private:
}; };
typedef std::map<const TupleType, ValueType *, TupleCompare> ContainerType; typedef std::map<const TupleType, ValueType *, TupleCompare> ContainerType;
ContainerType Pool; ContainerType Pool;
uint32_t NextPoolID;
}; };
// The global constant pool bundles individual pools of each type of // The global constant pool bundles individual pools of each type of
...@@ -171,6 +183,25 @@ Constant *GlobalContext::getConstantSym(Type Ty, int64_t Offset, ...@@ -171,6 +183,25 @@ Constant *GlobalContext::getConstantSym(Type Ty, int64_t Offset,
this, Ty, RelocatableTuple(Offset, Name, SuppressMangling)); 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 { void Timer::printElapsedUs(GlobalContext *Ctx, const IceString &Tag) const {
if (Ctx->isVerbose(IceV_Timing)) { if (Ctx->isVerbose(IceV_Timing)) {
// Prefixing with '#' allows timing strings to be included // Prefixing with '#' allows timing strings to be included
......
...@@ -77,6 +77,9 @@ public: ...@@ -77,6 +77,9 @@ public:
// Returns a symbolic constant. // Returns a symbolic constant.
Constant *getConstantSym(Type Ty, int64_t Offset, const IceString &Name = "", Constant *getConstantSym(Type Ty, int64_t Offset, const IceString &Name = "",
bool SuppressMangling = false); 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. // Allocate data of type T using the global allocator.
template <typename T> T *allocate() { return Allocator.Allocate<T>(); } template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
......
...@@ -80,6 +80,7 @@ private: ...@@ -80,6 +80,7 @@ private:
// constants are allocated from a global arena and are pooled. // constants are allocated from a global arena and are pooled.
class Constant : public Operand { class Constant : public Operand {
public: public:
uint32_t getPoolEntryID() const { return PoolEntryID; }
virtual void emit(const Cfg *Func) const = 0; virtual void emit(const Cfg *Func) const = 0;
virtual void dump(const Cfg *Func) const = 0; virtual void dump(const Cfg *Func) const = 0;
...@@ -89,11 +90,16 @@ public: ...@@ -89,11 +90,16 @@ public:
} }
protected: protected:
Constant(OperandKind Kind, Type Ty) : Operand(Kind, Ty) { Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID)
: Operand(Kind, Ty), PoolEntryID(PoolEntryID) {
Vars = NULL; Vars = NULL;
NumVars = 0; NumVars = 0;
} }
virtual ~Constant() {} 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: private:
Constant(const Constant &) LLVM_DELETED_FUNCTION; Constant(const Constant &) LLVM_DELETED_FUNCTION;
...@@ -104,9 +110,10 @@ private: ...@@ -104,9 +110,10 @@ private:
template <typename T, Operand::OperandKind K> template <typename T, Operand::OperandKind K>
class ConstantPrimitive : public Constant { class ConstantPrimitive : public Constant {
public: 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>()) return new (Ctx->allocate<ConstantPrimitive>())
ConstantPrimitive(Ty, Value); ConstantPrimitive(Ty, Value, PoolEntryID);
} }
T getValue() const { return Value; } T getValue() const { return Value; }
virtual void emit(const Cfg *Func) const { virtual void emit(const Cfg *Func) const {
...@@ -123,7 +130,8 @@ public: ...@@ -123,7 +130,8 @@ public:
} }
private: 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(const ConstantPrimitive &) LLVM_DELETED_FUNCTION;
ConstantPrimitive &operator=(const ConstantPrimitive &) LLVM_DELETED_FUNCTION; ConstantPrimitive &operator=(const ConstantPrimitive &) LLVM_DELETED_FUNCTION;
virtual ~ConstantPrimitive() {} virtual ~ConstantPrimitive() {}
...@@ -161,9 +169,10 @@ bool operator<(const RelocatableTuple &A, const RelocatableTuple &B); ...@@ -161,9 +169,10 @@ bool operator<(const RelocatableTuple &A, const RelocatableTuple &B);
class ConstantRelocatable : public Constant { class ConstantRelocatable : public Constant {
public: public:
static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty, static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty,
const RelocatableTuple &Tuple) { const RelocatableTuple &Tuple,
uint32_t PoolEntryID) {
return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable( 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; } int64_t getOffset() const { return Offset; }
IceString getName() const { return Name; } IceString getName() const { return Name; }
...@@ -179,9 +188,9 @@ public: ...@@ -179,9 +188,9 @@ public:
private: private:
ConstantRelocatable(Type Ty, int64_t Offset, const IceString &Name, ConstantRelocatable(Type Ty, int64_t Offset, const IceString &Name,
bool SuppressMangling) bool SuppressMangling, uint32_t PoolEntryID)
: Constant(kConstRelocatable, Ty), Offset(Offset), Name(Name), : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset),
SuppressMangling(SuppressMangling) {} Name(Name), SuppressMangling(SuppressMangling) {}
ConstantRelocatable(const ConstantRelocatable &) LLVM_DELETED_FUNCTION; ConstantRelocatable(const ConstantRelocatable &) LLVM_DELETED_FUNCTION;
ConstantRelocatable & ConstantRelocatable &
operator=(const ConstantRelocatable &) LLVM_DELETED_FUNCTION; operator=(const ConstantRelocatable &) LLVM_DELETED_FUNCTION;
......
...@@ -149,6 +149,8 @@ public: ...@@ -149,6 +149,8 @@ public:
virtual void addProlog(CfgNode *Node) = 0; virtual void addProlog(CfgNode *Node) = 0;
virtual void addEpilog(CfgNode *Node) = 0; virtual void addEpilog(CfgNode *Node) = 0;
virtual void emitConstants() const = 0;
virtual ~TargetLowering() {} virtual ~TargetLowering() {}
protected: protected:
......
...@@ -562,6 +562,71 @@ void TargetX8632::addEpilog(CfgNode *Node) { ...@@ -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) { void TargetX8632::split64(Variable *Var) {
switch (Var->getType()) { switch (Var->getType()) {
default: default:
...@@ -1878,4 +1943,16 @@ void TargetX8632::postLower() { ...@@ -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 } // end of namespace Ice
...@@ -47,6 +47,7 @@ public: ...@@ -47,6 +47,7 @@ public:
virtual void emitVariable(const Variable *Var, const Cfg *Func) const; virtual void emitVariable(const Variable *Var, const Cfg *Func) const;
virtual void addProlog(CfgNode *Node); virtual void addProlog(CfgNode *Node);
virtual void addEpilog(CfgNode *Node); virtual void addEpilog(CfgNode *Node);
virtual void emitConstants() const;
SizeT makeNextLabelNumber() { return NextLabelNumber++; } SizeT makeNextLabelNumber() { return NextLabelNumber++; }
// Ensure that a 64-bit Variable has been split into 2 32-bit // Ensure that a 64-bit Variable has been split into 2 32-bit
// Variables, creating them if necessary. This is needed for all // Variables, creating them if necessary. This is needed for all
...@@ -261,8 +262,12 @@ private: ...@@ -261,8 +262,12 @@ private:
TargetX8632(const TargetX8632 &) LLVM_DELETED_FUNCTION; TargetX8632(const TargetX8632 &) LLVM_DELETED_FUNCTION;
TargetX8632 &operator=(const TargetX8632 &) LLVM_DELETED_FUNCTION; TargetX8632 &operator=(const TargetX8632 &) LLVM_DELETED_FUNCTION;
virtual ~TargetX8632() {} 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 } // end of namespace Ice
#endif // SUBZERO_SRC_ICETARGETLOWERINGX8632_H #endif // SUBZERO_SRC_ICETARGETLOWERINGX8632_H
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "IceGlobalContext.h" #include "IceGlobalContext.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceTargetLowering.h"
#include "IceTypes.h" #include "IceTypes.h"
#include "llvm/IR/Constant.h" #include "llvm/IR/Constant.h"
...@@ -63,6 +64,7 @@ public: ...@@ -63,6 +64,7 @@ public:
SubzeroPointerType = Ice::IceType_i32; SubzeroPointerType = Ice::IceType_i32;
} }
// Caller is expected to delete the returned Ice::Cfg object.
Ice::Cfg *convertFunction(const Function *F) { Ice::Cfg *convertFunction(const Function *F) {
VarMap.clear(); VarMap.clear();
NodeMap.clear(); NodeMap.clear();
...@@ -618,14 +620,11 @@ DisableTranslation("notranslate", cl::desc("Disable Subzero translation")); ...@@ -618,14 +620,11 @@ DisableTranslation("notranslate", cl::desc("Disable Subzero translation"));
static cl::opt<bool> SubzeroTimingEnabled( static cl::opt<bool> SubzeroTimingEnabled(
"timing", cl::desc("Enable breakdown timing of Subzero translation")); "timing", cl::desc("Enable breakdown timing of Subzero translation"));
static cl::opt<NaClFileFormat> static cl::opt<NaClFileFormat> InputFileFormat(
InputFileFormat( "bitcode-format", cl::desc("Define format of input file:"),
"bitcode-format", cl::values(clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
cl::desc("Define format of input file:"), clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
cl::values( clEnumValEnd),
clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
clEnumValEnd),
cl::init(LLVMFormat)); cl::init(LLVMFormat));
int main(int argc, char **argv) { int main(int argc, char **argv) {
...@@ -670,6 +669,15 @@ 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); raw_os_ostream *Ls = new raw_os_ostream(LogFilename == "-" ? std::cout : Lfs);
Ls->SetUnbuffered(); 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); Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix);
for (Module::const_iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { for (Module::const_iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
...@@ -678,7 +686,7 @@ int main(int argc, char **argv) { ...@@ -678,7 +686,7 @@ int main(int argc, char **argv) {
LLVM2ICEConverter FunctionConverter(&Ctx); LLVM2ICEConverter FunctionConverter(&Ctx);
Ice::Timer TConvert; Ice::Timer TConvert;
Ice::Cfg *Func = FunctionConverter.convertFunction(I); Func.reset(FunctionConverter.convertFunction(I));
if (DisableInternal) if (DisableInternal)
Func->setInternal(false); Func->setInternal(false);
...@@ -713,5 +721,8 @@ int main(int argc, char **argv) { ...@@ -713,5 +721,8 @@ int main(int argc, char **argv) {
} }
} }
if (!DisableTranslation && Func)
Func->getTarget()->emitConstants();
return ExitStatus; return ExitStatus;
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
; number in a reasonable number of digits". See ; number in a reasonable number of digits". See
; http://llvm.org/docs/LangRef.html#simple-constants . ; 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: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \ ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
...@@ -534,5 +535,16 @@ return: ; preds = %entry, %sw.bb65, %s ...@@ -534,5 +535,16 @@ return: ; preds = %entry, %sw.bb65, %s
ret double %retval.0 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 ; ERRORS-NOT: ICE translation error
; DUMP-NOT: SZ ; 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