| Index: src/IceTargetLoweringX8632.cpp
|
| diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
|
| index ef9bc22f525087d8ac85bd66b4824871ba58fbab..539adf30498cb7807701c05fd21e0dbaab5b8b44 100644
|
| --- a/src/IceTargetLoweringX8632.cpp
|
| +++ b/src/IceTargetLoweringX8632.cpp
|
| @@ -85,6 +85,17 @@ InstX8632Br::BrCond getIcmp32Mapping(InstIcmp::ICond Cond) {
|
| return TableIcmp32[Index].Mapping;
|
| }
|
|
|
| +// Output a valid assembly identifier for the specified type. This is
|
| +// needed for representing vector types because the default Ostream
|
| +// operator<< implementation does not output a valid assembly identifier
|
| +// when the argument is a vector type.
|
| +void emitAsmLabelForType(Ostream &OS, Type Ty) {
|
| + if (isVectorType(Ty)) {
|
| + OS << "v" << typeNumElements(Ty);
|
| + }
|
| + OS << typeElementType(Ty);
|
| +}
|
| +
|
| // In some cases, there are x-macros tables for both high-level and
|
| // low-level instructions/operands that use the same enum key value.
|
| // The tables are kept separate to maintain a proper separation
|
| @@ -160,7 +171,8 @@ void xMacroIntegrityCheck() {
|
| _num
|
| };
|
| // Define a set of constants based on high-level table entries.
|
| -#define X(tag, size, align, str) static const int _table1_##tag = tag;
|
| +#define X(tag, size, align, elts, elty, str) \
|
| + static const int _table1_##tag = tag;
|
| ICETYPE_TABLE;
|
| #undef X
|
| // Define a set of constants based on low-level table entries,
|
| @@ -172,7 +184,8 @@ void xMacroIntegrityCheck() {
|
| #undef X
|
| // Repeat the static asserts with respect to the high-level
|
| // table entries in case the high-level table has extra entries.
|
| -#define X(tag, size, align, str) STATIC_ASSERT(_table1_##tag == _table2_##tag);
|
| +#define X(tag, size, align, elts, elty, str) \
|
| + STATIC_ASSERT(_table1_##tag == _table2_##tag);
|
| ICETYPE_TABLE;
|
| #undef X
|
| }
|
| @@ -681,7 +694,7 @@ 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 {
|
| +template <typename T> void TargetX8632::emitScalarConstantPool() const {
|
| Ostream &Str = Ctx->getStrEmit();
|
| Type Ty = T::Ty;
|
| SizeT Align = typeAlignInBytes(Ty);
|
| @@ -710,9 +723,84 @@ template <typename T> void TargetX8632::emitConstantPool() const {
|
| }
|
| }
|
|
|
| +void TargetX8632::emitVectorConstantPool() const {
|
| + Ostream &Str = Ctx->getStrEmit();
|
| +
|
| + // Although the PNaCl ABI doesn't require it, all vector constants are
|
| + // aligned to 16 bytes to allow for aligned loads.
|
| + const unsigned Align = VECT128_BYTES;
|
| +
|
| + Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align
|
| + << "\n";
|
| + Str << "\t.align\t" << Align << "\n";
|
| +
|
| + // Emit each (128 bit) vector.
|
| + // Non-I1 vectors are all in the same constant pool.
|
| + ConstantList Vectors = Ctx->getConstantPool(IceType_v8i16);
|
| + for (ConstantList::const_iterator I = Vectors.begin(), E = Vectors.end();
|
| + I != E; ++I) {
|
| + ConstantVector *Vector = llvm::cast<ConstantVector>(*I);
|
| + Vect128 Value = Vector->getValue();
|
| + assert(Value.size() == VECT128_BYTES);
|
| + const char *Data = Value.data();
|
| + Str << "L$";
|
| + emitAsmLabelForType(Str, Vector->getType());
|
| + Str << "$" << Vector->getPoolEntryID() << ":\n";
|
| + for (unsigned Element = 0; Element < 4; ++Element) {
|
| + uint32_t RawValue;
|
| + memcpy(&RawValue, &Data[4 * Element], 4);
|
| + char buf[30];
|
| + int CharsPrinted =
|
| + snprintf(buf, llvm::array_lengthof(buf), "0x%x", RawValue);
|
| + assert(CharsPrinted >= 0 &&
|
| + (size_t)CharsPrinted < llvm::array_lengthof(buf));
|
| + Str << "\t"
|
| + << ".long"
|
| + << "\t" << buf << "\t"
|
| + << "\n";
|
| + }
|
| + }
|
| +
|
| + // Emit each I1 vector expanded to a 128 bit constant.
|
| + // All I1 vectors are in the same constant pool.
|
| + ConstantList BitVectors = Ctx->getConstantPool(IceType_v4i1);
|
| + for (ConstantList::const_iterator I = BitVectors.begin(),
|
| + E = BitVectors.end();
|
| + I != E; ++I) {
|
| + ConstantBitVector *BitVector = llvm::cast<ConstantBitVector>(*I);
|
| + BitVect Value = BitVector->getValue();
|
| + Str << "L$";
|
| + emitAsmLabelForType(Str, BitVector->getType());
|
| + Str << "$" << BitVector->getPoolEntryID() << ":\n";
|
| + const char *AsmString = NULL;
|
| + switch (BitVector->getType()) {
|
| + default:
|
| + llvm_unreachable("Unknown type");
|
| + case IceType_v4i1:
|
| + AsmString = ".long";
|
| + break;
|
| + case IceType_v8i1:
|
| + AsmString = ".short";
|
| + break;
|
| + case IceType_v16i1:
|
| + AsmString = ".byte";
|
| + break;
|
| + }
|
| + unsigned NumElements = Value.size();
|
| + for (unsigned Element = 0; Element < NumElements; ++Element) {
|
| + Str << "\t" << AsmString << "\t"
|
| + << "0x";
|
| + Str << (Value[Element] ? "1" : "0");
|
| + Str << "\t"
|
| + << "\n";
|
| + }
|
| + }
|
| +}
|
| +
|
| void TargetX8632::emitConstants() const {
|
| - emitConstantPool<PoolTypeConverter<float> >();
|
| - emitConstantPool<PoolTypeConverter<double> >();
|
| + emitScalarConstantPool<PoolTypeConverter<float> >();
|
| + emitScalarConstantPool<PoolTypeConverter<double> >();
|
| + emitVectorConstantPool();
|
|
|
| // No need to emit constants from the int pool since (for x86) they
|
| // are embedded as immediates in the instructions.
|
| @@ -1297,6 +1385,13 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
|
| Variable *edx = NULL;
|
| if (Dest) {
|
| switch (Dest->getType()) {
|
| + case IceType_v4i1:
|
| + case IceType_v8i1:
|
| + case IceType_v16i1:
|
| + case IceType_v16i8:
|
| + case IceType_v8i16:
|
| + case IceType_v4i32:
|
| + case IceType_v4f32:
|
| case IceType_NUM:
|
| llvm_unreachable("Invalid Call dest type");
|
| break;
|
| @@ -2271,6 +2366,8 @@ void TargetX8632::lowerRet(const InstRet *Inst) {
|
| } else if (Src0->getType() == IceType_f32 ||
|
| Src0->getType() == IceType_f64) {
|
| _fld(Src0);
|
| + } else if (isVectorType(Src0->getType())) {
|
| + Reg = legalizeToVar(Src0, false, Reg_xmm0);
|
| } else {
|
| _mov(Reg, Src0, Reg_eax);
|
| }
|
| @@ -2392,6 +2489,19 @@ void TargetX8632::lowerUnreachable(const InstUnreachable * /*Inst*/) {
|
| lowerCall(Call);
|
| }
|
|
|
| +// Helper for legalize() to emit the right code to lower an operand to a
|
| +// register of the appropriate type.
|
| +Variable *TargetX8632::copyToReg(Operand *Src, int32_t RegNum) {
|
| + Type Ty = Src->getType();
|
| + Variable *Reg = makeReg(Ty, RegNum);
|
| + if (isVectorType(Src->getType())) {
|
| + _movp(Reg, Src);
|
| + } else {
|
| + _mov(Reg, Src);
|
| + }
|
| + return Reg;
|
| +}
|
| +
|
| Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
|
| bool AllowOverlap, int32_t RegNum) {
|
| // Assert that a physical register is allowed. To date, all calls
|
| @@ -2424,9 +2534,7 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
|
| }
|
|
|
| if (!(Allowed & Legal_Mem)) {
|
| - Variable *Reg = makeReg(From->getType(), RegNum);
|
| - _mov(Reg, From, RegNum);
|
| - From = Reg;
|
| + From = copyToReg(From, RegNum);
|
| }
|
| return From;
|
| }
|
| @@ -2447,13 +2555,13 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
|
| }
|
| bool NeedsReg =
|
| !(Allowed & Legal_Imm) ||
|
| - // ConstantFloat and ConstantDouble are actually memory operands.
|
| + // ConstantFloat, ConstantDouble, and vector constants are
|
| + // actually memory operands.
|
| (!(Allowed & Legal_Mem) &&
|
| - (From->getType() == IceType_f32 || From->getType() == IceType_f64));
|
| + (From->getType() == IceType_f32 || From->getType() == IceType_f64 ||
|
| + isVectorType(From->getType())));
|
| if (NeedsReg) {
|
| - Variable *Reg = makeReg(From->getType(), RegNum);
|
| - _mov(Reg, From);
|
| - From = Reg;
|
| + From = copyToReg(From, RegNum);
|
| }
|
| return From;
|
| }
|
| @@ -2463,11 +2571,10 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
|
| // RegNum is required and Var->getRegNum() doesn't match.
|
| if ((!(Allowed & Legal_Mem) && !Var->hasReg()) ||
|
| (RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) {
|
| - Variable *Reg = makeReg(From->getType(), RegNum);
|
| + Variable *Reg = copyToReg(From, RegNum);
|
| if (RegNum == Variable::NoRegister) {
|
| Reg->setPreferredRegister(Var, AllowOverlap);
|
| }
|
| - _mov(Reg, From);
|
| From = Reg;
|
| }
|
| return From;
|
| @@ -2569,6 +2676,11 @@ void TargetX8632::postLower() {
|
| }
|
| }
|
|
|
| +template <> void ConstantInteger::emit(GlobalContext *Ctx) const {
|
| + Ostream &Str = Ctx->getStrEmit();
|
| + Str << getValue();
|
| +}
|
| +
|
| template <> void ConstantFloat::emit(GlobalContext *Ctx) const {
|
| Ostream &Str = Ctx->getStrEmit();
|
| // It would be better to prefix with ".L$" instead of "L$", but
|
| @@ -2581,4 +2693,18 @@ template <> void ConstantDouble::emit(GlobalContext *Ctx) const {
|
| Str << "qword ptr [L$" << IceType_f64 << "$" << getPoolEntryID() << "]";
|
| }
|
|
|
| +template <> void ConstantVector::emit(GlobalContext *Ctx) const {
|
| + Ostream &Str = Ctx->getStrEmit();
|
| + Str << "xmmword ptr [L$";
|
| + emitAsmLabelForType(Str, getType());
|
| + Str << "$" << getPoolEntryID() << "]";
|
| +}
|
| +
|
| +template <> void ConstantBitVector::emit(GlobalContext *Ctx) const {
|
| + Ostream &Str = Ctx->getStrEmit();
|
| + Str << "xmmword ptr [L$";
|
| + emitAsmLabelForType(Str, getType());
|
| + Str << "$" << getPoolEntryID() << "]";
|
| +}
|
| +
|
| } // end of namespace Ice
|
|
|