From 6fe7c8aa8c7546743ecd0ac0138c2cf5d8155386 Mon Sep 17 00:00:00 2001 From: Nate Begeman Date: Sun, 18 Jan 2009 06:42:49 +0000 Subject: [PATCH] Vector codegen improvements git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62458 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ASTContext.cpp | 6 +- lib/CodeGen/CGBuiltin.cpp | 2 + lib/CodeGen/CGExpr.cpp | 99 ++++++++++++++++++------------- lib/CodeGen/CGExprScalar.cpp | 24 ++++++-- lib/Sema/Sema.cpp | 2 +- test/CodeGen/ext-vector-shuffle.c | 15 +++++ 6 files changed, 102 insertions(+), 46 deletions(-) create mode 100644 test/CodeGen/ext-vector-shuffle.c diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7cb035b868..122ba270c6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/Serialize.h" #include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/MathExtras.h" using namespace clang; @@ -284,8 +285,11 @@ ASTContext::getTypeInfo(const Type *T) { std::pair EltInfo = getTypeInfo(cast(T)->getElementType()); Width = EltInfo.first*cast(T)->getNumElements(); - // FIXME: This isn't right for unusual vectors Align = Width; + // If the alignment is not a power of 2, round up to the next power of 2. + // This happens for non-power-of-2 length vectors. + // FIXME: this should probably be a target property. + Align = 1 << llvm::Log2_32_Ceil(Align); break; } diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 6877b317aa..6e140da732 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -631,6 +631,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_vec_ext_v2di: case X86::BI__builtin_ia32_vec_ext_v4sf: case X86::BI__builtin_ia32_vec_ext_v4si: + case X86::BI__builtin_ia32_vec_ext_v8hi: + case X86::BI__builtin_ia32_vec_ext_v4hi: case X86::BI__builtin_ia32_vec_ext_v2df: return Builder.CreateExtractElement(Ops[0], Ops[1], "result"); case X86::BI__builtin_ia32_cmpordss: diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2d51efa474..5c304d19a5 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -309,8 +309,8 @@ RValue CodeGenFunction::EmitLoadOfKVCRefLValue(LValue LV, return EmitObjCPropertyGet(LV.getKVCRefExpr()); } -// If this is a reference to a subset of the elements of a vector, either -// shuffle the input or extract/insert them as appropriate. +// If this is a reference to a subset of the elements of a vector, create an +// appropriate shufflevector. RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV, QualType ExprType) { llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(), @@ -326,41 +326,21 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV, llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp")); } - - // If the source and destination have the same number of elements, use a - // vector shuffle instead of insert/extracts. + + // Always use shuffle vector to try to retain the original program structure unsigned NumResultElts = ExprVT->getNumElements(); - unsigned NumSourceElts = - cast(Vec->getType())->getNumElements(); - if (NumResultElts == NumSourceElts) { - llvm::SmallVector Mask; - for (unsigned i = 0; i != NumResultElts; ++i) { - unsigned InIdx = getAccessedFieldNo(i, Elts); - Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx)); - } - - llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); - Vec = Builder.CreateShuffleVector(Vec, - llvm::UndefValue::get(Vec->getType()), - MaskV, "tmp"); - return RValue::get(Vec); - } - - // Start out with an undef of the result type. - llvm::Value *Result = llvm::UndefValue::get(ConvertType(ExprType)); - - // Extract/Insert each element of the result. + llvm::SmallVector Mask; for (unsigned i = 0; i != NumResultElts; ++i) { unsigned InIdx = getAccessedFieldNo(i, Elts); - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); - Elt = Builder.CreateExtractElement(Vec, Elt, "tmp"); - - llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - Result = Builder.CreateInsertElement(Result, Elt, OutIdx, "tmp"); + Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx)); } - return RValue::get(Result); + llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); + Vec = Builder.CreateShuffleVector(Vec, + llvm::UndefValue::get(Vec->getType()), + MaskV, "tmp"); + return RValue::get(Vec); } @@ -548,15 +528,54 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, if (const VectorType *VTy = Ty->getAsVectorType()) { unsigned NumSrcElts = VTy->getNumElements(); - - // Extract/Insert each element. - for (unsigned i = 0; i != NumSrcElts; ++i) { - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - Elt = Builder.CreateExtractElement(SrcVal, Elt, "tmp"); - - unsigned Idx = getAccessedFieldNo(i, Elts); - llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Idx); - Vec = Builder.CreateInsertElement(Vec, Elt, OutIdx, "tmp"); + unsigned NumDstElts = + cast(Vec->getType())->getNumElements(); + if (NumDstElts == NumSrcElts) { + // Use shuffle vector is the src and destination are the same number + // of elements + llvm::SmallVector Mask; + for (unsigned i = 0; i != NumSrcElts; ++i) { + unsigned InIdx = getAccessedFieldNo(i, Elts); + Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx)); + } + + llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); + Vec = Builder.CreateShuffleVector(SrcVal, + llvm::UndefValue::get(Vec->getType()), + MaskV, "tmp"); + } + else if (NumDstElts > NumSrcElts) { + // Extended the source vector to the same length and then shuffle it + // into the destination. + // FIXME: since we're shuffling with undef, can we just use the indices + // into that? This could be simpler. + llvm::SmallVector ExtMask; + unsigned i; + for (i = 0; i != NumSrcElts; ++i) + ExtMask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i)); + for (; i != NumDstElts; ++i) + ExtMask.push_back(llvm::UndefValue::get(llvm::Type::Int32Ty)); + llvm::Value *ExtMaskV = llvm::ConstantVector::get(&ExtMask[0], + ExtMask.size()); + llvm::Value *ExtSrcVal = Builder.CreateShuffleVector(SrcVal, + llvm::UndefValue::get(SrcVal->getType()), + ExtMaskV, "tmp"); + // build identity + llvm::SmallVector Mask; + for (unsigned i = 0; i != NumDstElts; ++i) { + Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i)); + } + // modify when what gets shuffled in + for (unsigned i = 0; i != NumSrcElts; ++i) { + unsigned Idx = getAccessedFieldNo(i, Elts); + Mask[Idx] =llvm::ConstantInt::get(llvm::Type::Int32Ty, i+NumDstElts); + } + llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); + Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp"); + } + else { + // We should never shorten the vector + assert(0 && "unexpected shorten vector length"); } } else { // If the Src is a scalar (not a vector) it must be updating one element. diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d6cc16c10a..e6eb9c0b65 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -409,10 +409,26 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, } // A scalar can be splatted to an extended vector of the same element type - if (DstType->isExtVectorType() && !isa(SrcType) && - cast(DstTy)->getElementType() == Src->getType()) - return CGF.EmitVector(&Src, DstType->getAsVectorType()->getNumElements(), - true); + if (DstType->isExtVectorType() && !isa(SrcType)) { + // Cast the scalar to element type + QualType EltTy = DstType->getAsExtVectorType()->getElementType(); + llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy); + + // Insert the element in element zero of an undef vector + llvm::Value *UnV = llvm::UndefValue::get(DstTy); + llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp"); + + // Splat the element across to all elements + llvm::SmallVector Args; + unsigned NumElements = cast(DstTy)->getNumElements(); + for (unsigned i = 0; i < NumElements; i++) + Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)); + + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements); + llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat"); + return Yay; + } // Allow bitcast from vector to integer/fp of the same size. if (isa(Src->getType()) || diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 33f146aad8..ea42dbff0f 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -151,7 +151,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer) /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. - /// If isLvalue, the result of the cast is an lvalue. +/// If isLvalue, the result of the cast is an lvalue. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); diff --git a/test/CodeGen/ext-vector-shuffle.c b/test/CodeGen/ext-vector-shuffle.c new file mode 100644 index 0000000000..dfeffac7a9 --- /dev/null +++ b/test/CodeGen/ext-vector-shuffle.c @@ -0,0 +1,15 @@ +// RUN: clang %s -emit-llvm -o - | not grep 'extractelement' +// RUN: clang %s -emit-llvm -o - | not grep 'insertelement' +// RUN: clang %s -emit-llvm -o - | grep 'shufflevector' + +typedef __attribute__(( ext_vector_type(2) )) float float2; +typedef __attribute__(( ext_vector_type(4) )) float float4; + +float2 test1(float4 V) { + return V.xy + V.wz; +} + +float4 test2(float4 V) { + float2 W = V.ww; + return W.xyxy + W.yxyx; +} -- 2.40.0