Chromium Code Reviews| Index: src/IceTargetLoweringX8632.cpp |
| diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp |
| index ef9bc22f525087d8ac85bd66b4824871ba58fbab..a358ad53bf8251be27c83a2869c7d4aa435cefad 100644 |
| --- a/src/IceTargetLoweringX8632.cpp |
| +++ b/src/IceTargetLoweringX8632.cpp |
| @@ -85,6 +85,19 @@ InstX8632Br::BrCond getIcmp32Mapping(InstIcmp::ICond Cond) { |
| return TableIcmp32[Index].Mapping; |
| } |
| +// Returns the type name as a valid assembly label. |
| +IceString typeAsmLabel(Type Ty) { |
| + IceString Result; |
| + llvm::raw_string_ostream BaseOS(Result); |
|
Jim Stichnoth
2014/06/27 18:30:16
I'd like to avoid unnecessarily building LLVM stre
wala
2014/06/27 21:09:19
To avoid snprintf, this function could emit the va
Karl
2014/07/01 20:31:55
I find this statement about not using raw_string_o
|
| + Ostream OS(&BaseOS); |
| + unsigned NumElements = typeNumElements(Ty); |
| + if (NumElements > 1) { |
| + OS << "v" << NumElements; |
| + } |
| + OS << typeElementType(Ty); |
| + return BaseOS.str(); |
| +} |
| + |
| // 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 +173,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 +186,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 +696,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 +725,74 @@ template <typename T> void TargetX8632::emitConstantPool() const { |
| } |
| } |
| +void TargetX8632::emitVectorConstantPool() const { |
| + Ostream &Str = Ctx->getStrEmit(); |
|
jvoung (off chromium)
2014/06/26 23:33:46
You could just make a local variable "Align = 16"
Jim Stichnoth
2014/06/27 18:30:16
Is it appropriate to reuse VECT128_BYTES for this
wala
2014/06/27 21:09:19
I'll do this, and then explain that we naturally a
|
| + Str << "\t.section\t.rodata.cst" << 16 << ",\"aM\",@progbits," << 16 << "\n"; |
| + Str << "\t.align\t" << 16 << "\n"; |
| + |
| + // Emit each (128 bit) vector. |
| + ConstantList Vectors = Ctx->getConstantPool(IceType_v8i16); |
|
jvoung (off chromium)
2014/06/26 23:33:46
Could add a comment that all non-i1 vectors are in
wala
2014/06/27 21:09:19
I will add the comment. I'm unsure how to avoid th
|
| + 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$" << typeAsmLabel(Vector->getType()) << "$" |
| + << 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. |
| + 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$" << typeAsmLabel(BitVector->getType()) << "$" |
| + << 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 +1377,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 +2358,8 @@ void TargetX8632::lowerRet(const InstRet *Inst) { |
| } else if (Src0->getType() == IceType_f32 || |
| Src0->getType() == IceType_f64) { |
| _fld(Src0); |
| + } else if (typeNumElements(Src0->getType()) > 1) { |
| + Reg = legalizeToVar(Src0, false, Reg_xmm0); |
| } else { |
| _mov(Reg, Src0, Reg_eax); |
| } |
| @@ -2392,6 +2481,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 (typeNumElements(Ty) > 1) { |
|
jvoung (off chromium)
2014/06/26 23:33:46
Maybe there should be some inlineable "isVectorTyp
wala
2014/06/27 21:09:19
I agree.
|
| + _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 +2526,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 +2547,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 || |
| + typeNumElements(From->getType()) > 1)); |
| if (NeedsReg) { |
| - Variable *Reg = makeReg(From->getType(), RegNum); |
| - _mov(Reg, From); |
| - From = Reg; |
| + From = copyToReg(From, RegNum); |
| } |
| return From; |
| } |
| @@ -2463,11 +2563,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 +2668,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 +2685,16 @@ 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$" << typeAsmLabel(getType()) << "$" << getPoolEntryID() |
| + << "]"; |
| +} |
| + |
| +template <> void ConstantBitVector::emit(GlobalContext *Ctx) const { |
| + Ostream &Str = Ctx->getStrEmit(); |
| + Str << "xmmword ptr [L$" << typeAsmLabel(getType()) << "$" << getPoolEntryID() |
| + << "]"; |
| +} |
| + |
| } // end of namespace Ice |