More varied support for constant vectors from C++ backend.
If we have a vector of all zeros, a __setzero_* function call is emitted, permitting calling specialized intrinsics for this. Undefined values are reflected with an __undef_* call, which similarly allows passing that information along. This change also includes a cleanup to the signature of the __smear_* functions; since they already have different names depending on the scalar value type, we don't need to use the trick of passing an undefined value of the return vector type as the first parameter as an indirect way to overload by return value. Issue #317.
This commit is contained in:
144
cbackend.cpp
144
cbackend.cpp
@@ -1098,22 +1098,31 @@ bool CWriter::printCast(unsigned opc, llvm::Type *SrcTy, llvm::Type *DstTy) {
|
||||
}
|
||||
|
||||
|
||||
// FIXME: generalize this/make it not so hard-coded?
|
||||
static const char *lGetSmearFunc(llvm::Type *matchType) {
|
||||
/** Construct the name of a function with the given base and returning a
|
||||
vector of a given type. For example, if base is "foo" and matchType is
|
||||
i16, this will return the string "__foo_i16".
|
||||
*/
|
||||
static const char *
|
||||
lGetTypedFunc(const char *base, llvm::Type *matchType) {
|
||||
char buf[64];
|
||||
sprintf(buf, "__%s_", base);
|
||||
switch (matchType->getTypeID()) {
|
||||
case llvm::Type::FloatTyID: return "__smear_float";
|
||||
case llvm::Type::DoubleTyID: return "__smear_double";
|
||||
case llvm::Type::FloatTyID: strcat(buf, "float"); break;
|
||||
case llvm::Type::DoubleTyID: strcat(buf, "double"); break;
|
||||
case llvm::Type::IntegerTyID: {
|
||||
switch (llvm::cast<llvm::IntegerType>(matchType)->getBitWidth()) {
|
||||
case 1: return "__smear_i1";
|
||||
case 8: return "__smear_i8";
|
||||
case 16: return "__smear_i16";
|
||||
case 32: return "__smear_i32";
|
||||
case 64: return "__smear_i64";
|
||||
case 1: strcat(buf, "i1"); break;
|
||||
case 8: strcat(buf, "i8"); break;
|
||||
case 16: strcat(buf, "i16"); break;
|
||||
case 32: strcat(buf, "i32"); break;
|
||||
case 64: strcat(buf, "i64"); break;
|
||||
default: return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: return NULL;
|
||||
}
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -1458,64 +1467,63 @@ void CWriter::printConstant(llvm::Constant *CPV, bool Static) {
|
||||
}
|
||||
case llvm::Type::VectorTyID: {
|
||||
llvm::VectorType *VT = llvm::dyn_cast<llvm::VectorType>(CPV->getType());
|
||||
const char *smearFunc = lGetSmearFunc(VT->getElementType());
|
||||
|
||||
if (llvm::isa<llvm::ConstantAggregateZero>(CPV)) {
|
||||
assert(smearFunc != NULL);
|
||||
|
||||
llvm::Constant *CZ = llvm::Constant::getNullValue(VT->getElementType());
|
||||
Out << smearFunc << "(";
|
||||
printType(Out, VT);
|
||||
Out << "(), ";
|
||||
printConstant(CZ, Static);
|
||||
Out << ")";
|
||||
// All zeros; call the __setzero_* function.
|
||||
const char *setZeroFunc = lGetTypedFunc("setzero", VT->getElementType());
|
||||
assert(setZeroFunc != NULL);
|
||||
Out << setZeroFunc << "()";
|
||||
}
|
||||
else if (llvm::ConstantVector *CV = llvm::dyn_cast<llvm::ConstantVector>(CPV)) {
|
||||
llvm::Constant *splatValue = CV->getSplatValue();
|
||||
if (splatValue != NULL && smearFunc != NULL) {
|
||||
Out << smearFunc << "(";
|
||||
printType(Out, VT);
|
||||
Out << "(), ";
|
||||
printConstant(splatValue, Static);
|
||||
Out << ")";
|
||||
}
|
||||
else {
|
||||
printType(Out, CPV->getType());
|
||||
Out << "(";
|
||||
printConstantVector(CV, Static);
|
||||
Out << ")";
|
||||
}
|
||||
else if (llvm::isa<llvm::UndefValue>(CPV)) {
|
||||
// Undefined value; call __undef_* so that we can potentially pass
|
||||
// this information along..
|
||||
const char *undefFunc = lGetTypedFunc("undef", VT->getElementType());
|
||||
assert(undefFunc != NULL);
|
||||
Out << undefFunc << "()";
|
||||
}
|
||||
#ifndef LLVM_3_0
|
||||
else if (llvm::ConstantDataVector *CDV = llvm::dyn_cast<llvm::ConstantDataVector>(CPV)) {
|
||||
llvm::Constant *splatValue = CDV->getSplatValue();
|
||||
if (splatValue != NULL && smearFunc != NULL) {
|
||||
Out << smearFunc << "(";
|
||||
printType(Out, VT);
|
||||
Out << "(), ";
|
||||
printConstant(splatValue, Static);
|
||||
Out << ")";
|
||||
}
|
||||
else {
|
||||
printType(Out, CPV->getType());
|
||||
Out << "(";
|
||||
printConstantDataSequential(CDV, Static);
|
||||
Out << ")";
|
||||
}
|
||||
}
|
||||
#endif // !LLVM_3_0
|
||||
else {
|
||||
assert(llvm::isa<llvm::UndefValue>(CPV));
|
||||
llvm::Constant *CZ = llvm::Constant::getNullValue(VT->getElementType());
|
||||
printType(Out, CPV->getType());
|
||||
Out << "(";
|
||||
printConstant(CZ, Static);
|
||||
for (unsigned i = 1, e = VT->getNumElements(); i != e; ++i) {
|
||||
Out << ", ";
|
||||
printConstant(CZ, Static);
|
||||
}
|
||||
Out << ")";
|
||||
const char *smearFunc = lGetTypedFunc("smear", VT->getElementType());
|
||||
|
||||
if (llvm::ConstantVector *CV = llvm::dyn_cast<llvm::ConstantVector>(CPV)) {
|
||||
llvm::Constant *splatValue = CV->getSplatValue();
|
||||
if (splatValue != NULL && smearFunc != NULL) {
|
||||
// If it's a basic type and has a __smear_* function, then
|
||||
// call that.
|
||||
Out << smearFunc << "(";
|
||||
printConstant(splatValue, Static);
|
||||
Out << ")";
|
||||
}
|
||||
else {
|
||||
// Otherwise call the constructor for the type
|
||||
printType(Out, CPV->getType());
|
||||
Out << "(";
|
||||
printConstantVector(CV, Static);
|
||||
Out << ")";
|
||||
}
|
||||
}
|
||||
#ifndef LLVM_3_0
|
||||
// LLVM 3.1 and beyond have a different representation of constant vectors..
|
||||
else if (llvm::ConstantDataVector *CDV =
|
||||
llvm::dyn_cast<llvm::ConstantDataVector>(CPV)) {
|
||||
llvm::Constant *splatValue = CDV->getSplatValue();
|
||||
if (splatValue != NULL && smearFunc != NULL) {
|
||||
Out << smearFunc << "(";
|
||||
printConstant(splatValue, Static);
|
||||
Out << ")";
|
||||
}
|
||||
else {
|
||||
printType(Out, CPV->getType());
|
||||
Out << "(";
|
||||
printConstantDataSequential(CDV, Static);
|
||||
Out << ")";
|
||||
}
|
||||
}
|
||||
#endif // !LLVM_3_0
|
||||
else {
|
||||
llvm::report_fatal_error("Unexpected vector type");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case llvm::Type::StructTyID:
|
||||
@@ -4194,7 +4202,7 @@ char SmearCleanupPass::ID = 0;
|
||||
|
||||
|
||||
static int
|
||||
lChainLength(llvm::InsertElementInst *inst) {
|
||||
lChainLength(llvm::InsertElementInst *inst) {
|
||||
int length = 0;
|
||||
while (inst != NULL) {
|
||||
++length;
|
||||
@@ -4242,24 +4250,26 @@ SmearCleanupPass::runOnBasicBlock(llvm::BasicBlock &bb) {
|
||||
|
||||
{
|
||||
llvm::Type *matchType = toMatch->getType();
|
||||
const char *smearFuncName = lGetSmearFunc(matchType);
|
||||
const char *smearFuncName = lGetTypedFunc("smear", matchType);
|
||||
|
||||
if (smearFuncName != NULL) {
|
||||
llvm::Function *smearFunc = module->getFunction(smearFuncName);
|
||||
if (smearFunc == NULL) {
|
||||
// Declare the smar function if needed; it takes a single
|
||||
// scalar parameter and returns a vector of the same
|
||||
// parameter type.
|
||||
llvm::Constant *sf =
|
||||
module->getOrInsertFunction(smearFuncName, iter->getType(),
|
||||
iter->getType(), matchType, NULL);
|
||||
matchType, NULL);
|
||||
smearFunc = llvm::dyn_cast<llvm::Function>(sf);
|
||||
assert(smearFunc != NULL);
|
||||
smearFunc->setDoesNotThrow(true);
|
||||
smearFunc->setDoesNotAccessMemory(true);
|
||||
}
|
||||
|
||||
llvm::Value *undefResult = llvm::UndefValue::get(vt);
|
||||
assert(smearFunc != NULL);
|
||||
llvm::Value *args[2] = { undefResult, toMatch };
|
||||
llvm::ArrayRef<llvm::Value *> argArray(&args[0], &args[2]);
|
||||
llvm::Value *args[1] = { toMatch };
|
||||
llvm::ArrayRef<llvm::Value *> argArray(&args[0], &args[1]);
|
||||
llvm::Instruction *smearCall =
|
||||
llvm::CallInst::Create(smearFunc, argArray, LLVMGetName(toMatch, "_smear"),
|
||||
(llvm::Instruction *)NULL);
|
||||
|
||||
Reference in New Issue
Block a user