Commit 5aeed955 by John Porto

Changes the TargetX8632 to inherit from TargetX86Base<TargetX8632>.

Previously, TargetX8632 was defined as class TargetX8632 : public TargetLowering; and its create method would do TargetX8632 *TargetX8632::create() { return TargetX86Base<TargetX8632>::create() } TargetX86Base<M> was defined was template <class M> class TargetX86Base : public M; which meant TargetX8632 had no way to access methods defined in TargetX86Base<M>. This used to not be a problem, but with the X8664 backend around the corner it became obvious that the actual TargetX86 targets (e.g., X8632. X8664SysV, X8664Win) would need access to some methods in TargetX86Base (e.g., _mov, _fld, _fstp etc.) This CL changes the class hierarchy to something like TargetLowering <-- TargetX86Base<X8632> <-- X8632 <-- TargetX86Base<X8664SysV> <-- X8664SysV (TODO) <-- TargetX86Base<X8664Win> <-- X8664Win (TODO) One problem with this new design is that TargetX86Base<M> needs to be able to invoke methods in the actual backends. For example, each backend will have its own way of lowering llvm.nacl.read.tp. This creates a chicken/egg problem that is solved with (you guessed) template machinery (some would call it voodoo.) In this CL, as a proof of concept, we introduce the TargetX86Base::dispatchToConcrete template method. It is a very simple method: it downcasts "this" from the template base class (TargetX86Base<TargetX8664>) to the actual (concrete) class (TargetX8632), and then it invokes the requested method. It uses perfect forwarding for passing arguments to the method being invoked, and returns whatever that method returns. A simple proof-of-concept for using dispatchToConcrete is introduced with this CL: it is used to invoke createNaClReadTPSrcOperand on the concrete target class. In a way, dispatchToConcrete is a poor man's virtual method call, without the virtual method call overhead. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4077 R=jvoung@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1217443024.
parent 8c8f3bc1
...@@ -81,10 +81,6 @@ const char *MachineTraits<TargetX8632>::TargetName = "X8632"; ...@@ -81,10 +81,6 @@ const char *MachineTraits<TargetX8632>::TargetName = "X8632";
} // end of namespace X86Internal } // end of namespace X86Internal
TargetX8632 *TargetX8632::create(Cfg *Func) {
return X86Internal::TargetX86Base<TargetX8632>::create(Func);
}
TargetDataX8632::TargetDataX8632(GlobalContext *Ctx) TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {} : TargetDataLowering(Ctx) {}
......
...@@ -23,10 +23,12 @@ ...@@ -23,10 +23,12 @@
#include "IceRegistersX8632.h" #include "IceRegistersX8632.h"
#include "IceTargetLowering.h" #include "IceTargetLowering.h"
#include "IceTargetLoweringX8632Traits.h" #include "IceTargetLoweringX8632Traits.h"
#include "IceTargetLoweringX86Base.h"
namespace Ice { namespace Ice {
class TargetX8632 : public TargetLowering { class TargetX8632 final
: public ::Ice::X86Internal::TargetX86Base<TargetX8632> {
TargetX8632() = delete; TargetX8632() = delete;
TargetX8632(const TargetX8632 &) = delete; TargetX8632(const TargetX8632 &) = delete;
TargetX8632 &operator=(const TargetX8632 &) = delete; TargetX8632 &operator=(const TargetX8632 &) = delete;
...@@ -34,13 +36,20 @@ class TargetX8632 : public TargetLowering { ...@@ -34,13 +36,20 @@ class TargetX8632 : public TargetLowering {
public: public:
using X86InstructionSet = X8632::Traits::InstructionSet; using X86InstructionSet = X8632::Traits::InstructionSet;
static TargetX8632 *create(Cfg *Func); static TargetX8632 *create(Cfg *Func) { return new TargetX8632(Func); }
virtual X8632::Traits::Address
stackVarToAsmOperand(const Variable *Var) const = 0;
virtual X86InstructionSet getInstructionSet() const = 0;
protected: protected:
explicit TargetX8632(Cfg *Func) : TargetLowering(Func) {} Operand *createNaClReadTPSrcOperand() {
Constant *Zero = Ctx->getConstantZero(IceType_i32);
return Traits::X86OperandMem::create(Func, IceType_i32, nullptr, Zero,
nullptr, 0,
Traits::X86OperandMem::SegReg_GS);
}
private:
friend class ::Ice::X86Internal::TargetX86Base<TargetX8632>;
explicit TargetX8632(Cfg *Func) : TargetX86Base(Func) {}
}; };
class TargetDataX8632 final : public TargetDataLowering { class TargetDataX8632 final : public TargetDataLowering {
......
...@@ -37,6 +37,7 @@ namespace X86Internal { ...@@ -37,6 +37,7 @@ namespace X86Internal {
template <class Machine> struct Insts; template <class Machine> struct Insts;
template <class Machine> struct MachineTraits; template <class Machine> struct MachineTraits;
template <class Machine> class TargetX86Base;
template <> struct MachineTraits<TargetX8632> { template <> struct MachineTraits<TargetX8632> {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
...@@ -518,7 +519,7 @@ template <> struct MachineTraits<TargetX8632> { ...@@ -518,7 +519,7 @@ template <> struct MachineTraits<TargetX8632> {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
using Insts = ::Ice::X86Internal::Insts<TargetX8632>; using Insts = ::Ice::X86Internal::Insts<TargetX8632>;
using TargetLowering = TargetX8632; using TargetLowering = ::Ice::X86Internal::TargetX86Base<TargetX8632>;
using Assembler = X8632::AssemblerX8632; using Assembler = X8632::AssemblerX8632;
/// X86Operand extends the Operand hierarchy. Its subclasses are /// X86Operand extends the Operand hierarchy. Its subclasses are
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <utility>
namespace Ice { namespace Ice {
namespace X86Internal { namespace X86Internal {
...@@ -32,76 +33,30 @@ template <class MachineTraits> class BoolFolding; ...@@ -32,76 +33,30 @@ template <class MachineTraits> class BoolFolding;
template <class Machine> struct MachineTraits {}; template <class Machine> struct MachineTraits {};
template <class Machine> class TargetX86Base : public Machine { /// TargetX86Base is a template for all X86 Targets, and it relies on the CRT
static_assert(std::is_base_of<::Ice::TargetLowering, Machine>::value, /// pattern for generating code, delegating to actual backends target-specific
"Machine template parameter must be a TargetLowering."); /// lowerings (e.g., call, ret, and intrinsics.) Backends are expected to
/// implement the following methods (which should be accessible from
/// TargetX86Base):
///
/// Operand *createNaClReadTPSrcOperand()
///
/// Note: Ideally, we should be able to
///
/// static_assert(std::is_base_of<TargetX86Base<Machine>, Machine>::value);
///
/// but that does not work: the compiler does not know that Machine inherits
/// from TargetX86Base at this point in translation.
template <class Machine> class TargetX86Base : public TargetLowering {
TargetX86Base() = delete; TargetX86Base() = delete;
TargetX86Base(const TargetX86Base &) = delete; TargetX86Base(const TargetX86Base &) = delete;
TargetX86Base &operator=(const TargetX86Base &) = delete; TargetX86Base &operator=(const TargetX86Base &) = delete;
protected:
using Machine::H_bitcast_16xi1_i16;
using Machine::H_bitcast_8xi1_i8;
using Machine::H_bitcast_i16_16xi1;
using Machine::H_bitcast_i8_8xi1;
using Machine::H_call_ctpop_i32;
using Machine::H_call_ctpop_i64;
using Machine::H_call_longjmp;
using Machine::H_call_memcpy;
using Machine::H_call_memmove;
using Machine::H_call_memset;
using Machine::H_call_read_tp;
using Machine::H_call_setjmp;
using Machine::H_fptosi_f32_i64;
using Machine::H_fptosi_f64_i64;
using Machine::H_fptoui_4xi32_f32;
using Machine::H_fptoui_f32_i32;
using Machine::H_fptoui_f32_i64;
using Machine::H_fptoui_f64_i32;
using Machine::H_fptoui_f64_i64;
using Machine::H_frem_f32;
using Machine::H_frem_f64;
using Machine::H_sdiv_i64;
using Machine::H_sitofp_i64_f32;
using Machine::H_sitofp_i64_f64;
using Machine::H_srem_i64;
using Machine::H_udiv_i64;
using Machine::H_uitofp_4xi32_4xf32;
using Machine::H_uitofp_i32_f32;
using Machine::H_uitofp_i32_f64;
using Machine::H_uitofp_i64_f32;
using Machine::H_uitofp_i64_f64;
using Machine::H_urem_i64;
using Machine::alignStackSpillAreas;
using Machine::assignVarStackSlots;
using Machine::inferTwoAddress;
using Machine::makeHelperCall;
using Machine::getVarStackSlotParams;
public: public:
using Traits = MachineTraits<Machine>; using Traits = MachineTraits<Machine>;
using BoolFolding = ::Ice::X86Internal::BoolFolding<Traits>; using BoolFolding = ::Ice::X86Internal::BoolFolding<Traits>;
using Machine::RegSet_All; ~TargetX86Base() override = default;
using Machine::RegSet_CalleeSave;
using Machine::RegSet_CallerSave;
using Machine::RegSet_FramePointer;
using Machine::RegSet_None;
using Machine::RegSet_StackPointer;
using Machine::Context;
using Machine::Ctx;
using Machine::Func;
using RegSetMask = typename Machine::RegSetMask;
using Machine::_bundle_lock;
using Machine::_bundle_unlock;
using Machine::_set_dest_nonkillable;
using Machine::getContext;
using Machine::getStackAdjustment;
using Machine::regAlloc;
using Machine::resetStackAdjustment;
static TargetX86Base *create(Cfg *Func) { return new TargetX86Base(Func); } static TargetX86Base *create(Cfg *Func) { return new TargetX86Base(Func); }
...@@ -156,10 +111,9 @@ public: ...@@ -156,10 +111,9 @@ public:
Operand *hiOperand(Operand *Operand); Operand *hiOperand(Operand *Operand);
void finishArgumentLowering(Variable *Arg, Variable *FramePtr, void finishArgumentLowering(Variable *Arg, Variable *FramePtr,
size_t BasicFrameOffset, size_t &InArgsSizeBytes); size_t BasicFrameOffset, size_t &InArgsSizeBytes);
typename Traits::Address typename Traits::Address stackVarToAsmOperand(const Variable *Var) const;
stackVarToAsmOperand(const Variable *Var) const final;
typename Traits::InstructionSet getInstructionSet() const final { typename Traits::InstructionSet getInstructionSet() const {
return InstructionSet; return InstructionSet;
} }
Operand *legalizeUndef(Operand *From, int32_t RegNum = Variable::NoRegister); Operand *legalizeUndef(Operand *From, int32_t RegNum = Variable::NoRegister);
...@@ -628,7 +582,28 @@ protected: ...@@ -628,7 +582,28 @@ protected:
bool RandomizationPoolingPaused = false; bool RandomizationPoolingPaused = false;
private: private:
~TargetX86Base() override {} /// dispatchToConcrete is the template voodoo that allows TargetX86Base to
/// invoke methods in Machine (which inherits from TargetX86Base) without
/// having to rely on virtual method calls. There are two overloads, one for
/// non-void types, and one for void types. We need this becase, for non-void
/// types, we need to return the method result, where as for void, we don't.
/// While it is true that the code compiles without the void "version", there
/// used to be a time when compilers would reject such code.
///
/// This machinery is far from perfect. Note that, in particular, the
/// arguments provided to dispatchToConcrete() need to match the arguments for
/// Method **exactly** (i.e., no argument promotion is performed.)
template <typename Ret, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
dispatchToConcrete(Ret (Machine::*Method)(Args...), Args &&... args) {
return (static_cast<Machine *>(this)->*Method)(std::forward<Args>(args)...);
}
template <typename... Args>
void dispatchToConcrete(void (Machine::*Method)(Args...), Args &&... args) {
(static_cast<Machine *>(this)->*Method)(std::forward<Args>(args)...);
}
BoolFolding FoldingInfo; BoolFolding FoldingInfo;
}; };
} // end of namespace X86Internal } // end of namespace X86Internal
......
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