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 |