From f72fb679eff7de84e3e18b75d63a18cb3510bcdd Mon Sep 17 00:00:00 2001
From: Dan Gohman
Date: Tue, 9 Sep 2008 01:02:47 +0000
Subject: [PATCH] Extend the vcmp/fcmp LLVM IR instructions to take vectors as
arguments and, if so, to return a vector of boolean as a result;
Extend the select LLVM IR instruction to allow you to specify a result
type which is a vector of boolean, in which case the result will be an
element-wise selection instead of choosing one vector or the other; and
Update LangRef.html to describe these changes.
This patch was contributed by Preston Gurd!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@55969 91177308-0d34-0410-b5e6-96231b3b80d8
---
docs/LangRef.html | 71 ++++++++++++++++++++--------
include/llvm/Bitcode/LLVMBitCodes.h | 4 +-
include/llvm/InstrTypes.h | 8 ++++
include/llvm/Instructions.h | 22 +++++----
lib/AsmParser/llvmAsmParser.y | 29 ++++++++----
lib/Bitcode/Reader/BitcodeReader.cpp | 29 +++++++++++-
lib/Bitcode/Writer/BitcodeWriter.cpp | 18 ++++++-
lib/VMCore/Verifier.cpp | 21 ++++++--
test/Assembler/vbool-cmp.ll | 15 ++++++
test/Assembler/vector-select.ll | 11 +++++
10 files changed, 181 insertions(+), 47 deletions(-)
create mode 100644 test/Assembler/vbool-cmp.ll
create mode 100644 test/Assembler/vector-select.ll
diff --git a/docs/LangRef.html b/docs/LangRef.html
index 1beb670765d..4921707338c 100644
--- a/docs/LangRef.html
+++ b/docs/LangRef.html
@@ -3846,11 +3846,12 @@ instructions, which defy better classification.
Syntax:
-
<result> = icmp <cond> <ty> <op1>, <op2> ; yields {i1}:result
+ <result> = icmp <cond> <ty> <op1>, <op2> ; yields {i1} or {<N x i1>}:result
Overview:
-The 'icmp' instruction returns a boolean value based on comparison
-of its two integer or pointer operands.
+The 'icmp' instruction returns a boolean value or
+a vector of boolean values based on comparison
+of its two integer, integer vector, or pointer operands.
Arguments:
The 'icmp' instruction takes three operands. The first operand is
the condition code indicating the kind of comparison to perform. It is not
@@ -3868,11 +3869,13 @@ a value, just a keyword. The possible condition code are:
sle: signed less or equal
The remaining two arguments must be integer or
-pointer typed. They must also be identical types.
+
pointer
+or integer
vector typed.
+They must also be identical types.
Semantics:
The 'icmp' compares op1 and op2 according to
the condition code given as cond. The comparison performed always
-yields a i1 result, as follows:
+yields either an i1 or vector of i1 result, as follows:
- eq: yields true if the operands are equal,
false otherwise. No sign interpretation is necessary or performed.
@@ -3898,6 +3901,11 @@ yields a i1 result, as follows:
If the operands are pointer typed, the pointer
values are compared as if they were integers.
+
If the operands are integer vectors, then they are compared
+element by element. The result is an i1 vector with
+the same number of elements as the values being compared.
+Otherwise, the result is an i1.
+
Example:
<result> = icmp eq i32 4, 5 ; yields: result=false
@@ -3914,11 +3922,19 @@ values are compared as if they were integers.
Syntax:
-
<result> = fcmp <cond> <ty> <op1>, <op2> ; yields {i1}:result
+ <result> = fcmp <cond> <ty> <op1>, <op2> ; yields {i1} or {<N x i1>}:result
Overview:
-The 'fcmp' instruction returns a boolean value based on comparison
-of its floating point operands.
+The 'fcmp' instruction returns a boolean value
+or vector of boolean values based on comparison
+of its operands.
+
+If the operands are floating point scalars, then the result
+type is a boolean (i1).
+
+If the operands are floating point vectors, then the result type
+is a vector of boolean with the same number of elements as the
+operands being compared.
Arguments:
The 'fcmp' instruction takes three operands. The first operand is
the condition code indicating the kind of comparison to perform. It is not
@@ -3943,13 +3959,17 @@ a value, just a keyword. The possible condition code are:
Ordered means that neither operand is a QNAN while
unordered means that either operand may be a QNAN.
-The val1 and val2 arguments must be
-floating point typed. They must have identical
-types.
+Each of val1 and val2 arguments must be
+either a floating point type
+or a vector of floating point type.
+They must have identical types.
Semantics:
The 'fcmp' instruction compares op1 and op2
-according to the condition code given as cond. The comparison performed
-always yields a i1 result, as follows:
+according to the condition code given as cond.
+If the operands are vectors, then the vectors are compared
+element by element.
+Each comparison performed
+always yields an i1 result, as follows:
- false: always yields false, regardless of operands.
- oeq: yields true if both operands are not a QNAN and
@@ -3983,9 +4003,9 @@ always yields a i1 result, as follows:
Example:
<result> = fcmp oeq float 4.0, 5.0 ; yields: result=false
- <result> = icmp one float 4.0, 5.0 ; yields: result=true
- <result> = icmp olt float 4.0, 5.0 ; yields: result=true
- <result> = icmp ueq double 1.0, 2.0 ; yields: result=false
+ <result> = fcmp one float 4.0, 5.0 ; yields: result=true
+ <result> = fcmp olt float 4.0, 5.0 ; yields: result=true
+ <result> = fcmp ueq double 1.0, 2.0 ; yields: result=false
@@ -4016,7 +4036,7 @@ a value, just a keyword. The possible condition code are:
slt: signed less than
sle: signed less or equal
-The remaining two arguments must be vector of
+
The remaining two arguments must be vector or
integer typed. They must also be identical types.
Semantics:
The 'vicmp' instruction compares op1 and op2
@@ -4140,7 +4160,9 @@ Loop: ; Infinite loop that counts from 0 on up...
Syntax:
- <result> = select i1 <cond>, <ty> <val1>, <ty> <val2> ; yields ty
+ <result> = select selty <cond>, <ty> <val1>, <ty> <val2> ; yields ty
+
+ selty is either i1 or {<N x i1>}
Overview:
@@ -4154,18 +4176,25 @@ condition, without branching.
Arguments:
-The 'select' instruction requires an 'i1' value indicating the
+The 'select' instruction requires an 'i1' value or
+a vector of 'i1' values indicating the
condition, and two values of the same first class
-type. If the val1/val2 are vectors, the entire vectors are selected, not
+type. If the val1/val2 are vectors and
+the condition is a scalar, then entire vectors are selected, not
individual elements.
Semantics:
-If the i1 condition evaluates is 1, the instruction returns the first
+If the condition is an i1 and it evaluates to 1, the instruction returns the first
value argument; otherwise, it returns the second value argument.
+
+If the condition is a vector of i1, then the value arguments must
+be vectors of the same size, and the selection is done element
+by element.
+
Example:
diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h
index 12607dcd324..d1dcc74437d 100644
--- a/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/include/llvm/Bitcode/LLVMBitCodes.h
@@ -205,7 +205,9 @@ namespace bitc {
// FIXME: Remove GETRESULT in favor of EXTRACTVAL in LLVM 3.0
FUNC_CODE_INST_GETRESULT = 25, // GETRESULT: [ty, opval, n]
FUNC_CODE_INST_EXTRACTVAL = 26, // EXTRACTVAL: [n x operands]
- FUNC_CODE_INST_INSERTVAL = 27 // INSERTVAL: [n x operands]
+ FUNC_CODE_INST_INSERTVAL = 27, // INSERTVAL: [n x operands]
+ // fcmp/icmp returning vector of Int1Ty, NOT for vicmp/vfcmp
+ FUNC_CODE_INST_VCMP = 28 // VCMP: [opty, opval, opval, pred]
};
} // End bitc namespace
} // End llvm namespace
diff --git a/include/llvm/InstrTypes.h b/include/llvm/InstrTypes.h
index 430c772aec4..74bb6f53bdd 100644
--- a/include/llvm/InstrTypes.h
+++ b/include/llvm/InstrTypes.h
@@ -18,6 +18,7 @@
#include "llvm/Instruction.h"
#include "llvm/OperandTraits.h"
+#include "llvm/DerivedTypes.h"
namespace llvm {
@@ -732,6 +733,13 @@ public:
static inline bool classof(const Value *V) {
return isa(V) && classof(cast(V));
}
+ /// @brief Create a result type for fcmp/icmp (but not vicmp/vfcmp)
+ static const Type* makeCmpResultType(const Type* opnd_type) {
+ if (const VectorType* vt = dyn_cast(opnd_type)) {
+ return VectorType::get(Type::Int1Ty, vt->getNumElements());
+ }
+ return Type::Int1Ty;
+ }
/// Backward-compatible interfaces
/// @deprecated in 2.4, do not use, will disappear soon
static CmpInst *create(OtherOps Op, unsigned short predicate, Value *S1,
diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h
index 355103cfa64..8ae9c375fb7 100644
--- a/include/llvm/Instructions.h
+++ b/include/llvm/Instructions.h
@@ -621,7 +621,8 @@ public:
Value *RHS, ///< The right-hand-side of the expression
const std::string &NameStr = "", ///< Name of the instruction
Instruction *InsertBefore = 0 ///< Where to insert
- ) : CmpInst(Type::Int1Ty, Instruction::ICmp, pred, LHS, RHS, NameStr,
+ ) : CmpInst(makeCmpResultType(LHS->getType()),
+ Instruction::ICmp, pred, LHS, RHS, NameStr,
InsertBefore) {
assert(pred >= CmpInst::FIRST_ICMP_PREDICATE &&
pred <= CmpInst::LAST_ICMP_PREDICATE &&
@@ -629,7 +630,7 @@ public:
assert(getOperand(0)->getType() == getOperand(1)->getType() &&
"Both operands to ICmp instruction are not of the same type!");
// Check that the operands are the right type
- assert((getOperand(0)->getType()->isInteger() ||
+ assert((getOperand(0)->getType()->isIntOrIntVector() ||
isa(getOperand(0)->getType())) &&
"Invalid operand types for ICmp instruction");
}
@@ -641,7 +642,8 @@ public:
Value *RHS, ///< The right-hand-side of the expression
const std::string &NameStr, ///< Name of the instruction
BasicBlock *InsertAtEnd ///< Block to insert into.
- ) : CmpInst(Type::Int1Ty, Instruction::ICmp, pred, LHS, RHS, NameStr,
+ ) : CmpInst(makeCmpResultType(LHS->getType()),
+ Instruction::ICmp, pred, LHS, RHS, NameStr,
InsertAtEnd) {
assert(pred >= CmpInst::FIRST_ICMP_PREDICATE &&
pred <= CmpInst::LAST_ICMP_PREDICATE &&
@@ -649,7 +651,7 @@ public:
assert(getOperand(0)->getType() == getOperand(1)->getType() &&
"Both operands to ICmp instruction are not of the same type!");
// Check that the operands are the right type
- assert((getOperand(0)->getType()->isInteger() ||
+ assert((getOperand(0)->getType()->isIntOrIntVector() ||
isa(getOperand(0)->getType())) &&
"Invalid operand types for ICmp instruction");
}
@@ -754,6 +756,7 @@ public:
static inline bool classof(const Value *V) {
return isa(V) && classof(cast(V));
}
+
};
//===----------------------------------------------------------------------===//
@@ -773,14 +776,15 @@ public:
Value *RHS, ///< The right-hand-side of the expression
const std::string &NameStr = "", ///< Name of the instruction
Instruction *InsertBefore = 0 ///< Where to insert
- ) : CmpInst(Type::Int1Ty, Instruction::FCmp, pred, LHS, RHS, NameStr,
+ ) : CmpInst(makeCmpResultType(LHS->getType()),
+ Instruction::FCmp, pred, LHS, RHS, NameStr,
InsertBefore) {
assert(pred <= FCmpInst::LAST_FCMP_PREDICATE &&
"Invalid FCmp predicate value");
assert(getOperand(0)->getType() == getOperand(1)->getType() &&
"Both operands to FCmp instruction are not of the same type!");
// Check that the operands are the right type
- assert(getOperand(0)->getType()->isFloatingPoint() &&
+ assert(getOperand(0)->getType()->isFPOrFPVector() &&
"Invalid operand types for FCmp instruction");
}
@@ -791,14 +795,15 @@ public:
Value *RHS, ///< The right-hand-side of the expression
const std::string &NameStr, ///< Name of the instruction
BasicBlock *InsertAtEnd ///< Block to insert into.
- ) : CmpInst(Type::Int1Ty, Instruction::FCmp, pred, LHS, RHS, NameStr,
+ ) : CmpInst(makeCmpResultType(LHS->getType()),
+ Instruction::FCmp, pred, LHS, RHS, NameStr,
InsertAtEnd) {
assert(pred <= FCmpInst::LAST_FCMP_PREDICATE &&
"Invalid FCmp predicate value");
assert(getOperand(0)->getType() == getOperand(1)->getType() &&
"Both operands to FCmp instruction are not of the same type!");
// Check that the operands are the right type
- assert(getOperand(0)->getType()->isFloatingPoint() &&
+ assert(getOperand(0)->getType()->isFPOrFPVector() &&
"Invalid operand types for FCmp instruction");
}
@@ -837,6 +842,7 @@ public:
static inline bool classof(const Value *V) {
return isa(V) && classof(cast(V));
}
+
};
//===----------------------------------------------------------------------===//
diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y
index 5db76429b51..edc84c1fa14 100644
--- a/lib/AsmParser/llvmAsmParser.y
+++ b/lib/AsmParser/llvmAsmParser.y
@@ -1102,7 +1102,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
%token ADD SUB MUL UDIV SDIV FDIV UREM SREM FREM AND OR XOR
%token SHL LSHR ASHR
-%token ICMP FCMP VICMP VFCMP
+%token ICMP FCMP VICMP VFCMP
%type IPredicates
%type FPredicates
%token EQ NE SLT SGT SLE SGE ULT UGT ULE UGE
@@ -3097,8 +3097,6 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
| ICMP IPredicates Types ValueRef ',' ValueRef {
if (!UpRefs.empty())
GEN_ERROR("Invalid upreference in type: " + (*$3)->getDescription());
- if (isa((*$3).get()))
- GEN_ERROR("Vector types not supported by icmp instruction");
Value* tmpVal1 = getVal(*$3, $4);
CHECK_FOR_ERROR
Value* tmpVal2 = getVal(*$3, $6);
@@ -3111,8 +3109,6 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
| FCMP FPredicates Types ValueRef ',' ValueRef {
if (!UpRefs.empty())
GEN_ERROR("Invalid upreference in type: " + (*$3)->getDescription());
- if (isa((*$3).get()))
- GEN_ERROR("Vector types not supported by fcmp instruction");
Value* tmpVal1 = getVal(*$3, $4);
CHECK_FOR_ERROR
Value* tmpVal2 = getVal(*$3, $6);
@@ -3133,7 +3129,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
CHECK_FOR_ERROR
$$ = CmpInst::Create($1, $2, tmpVal1, tmpVal2);
if ($$ == 0)
- GEN_ERROR("icmp operator returned null");
+ GEN_ERROR("vicmp operator returned null");
delete $3;
}
| VFCMP FPredicates Types ValueRef ',' ValueRef {
@@ -3147,7 +3143,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
CHECK_FOR_ERROR
$$ = CmpInst::Create($1, $2, tmpVal1, tmpVal2);
if ($$ == 0)
- GEN_ERROR("fcmp operator returned null");
+ GEN_ERROR("vfcmp operator returned null");
delete $3;
}
| CastOps ResolvedVal TO Types {
@@ -3163,10 +3159,23 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
delete $4;
}
| SELECT ResolvedVal ',' ResolvedVal ',' ResolvedVal {
- if ($2->getType() != Type::Int1Ty)
- GEN_ERROR("select condition must be boolean");
+ if (isa($2->getType())) {
+ // vector select
+ if (!isa($4->getType())
+ || !isa($6->getType()) )
+ GEN_ERROR("vector select value types must be vector types");
+ const VectorType* cond_type = cast($2->getType());
+ const VectorType* select_type = cast($4->getType());
+ if (cond_type->getElementType() != Type::Int1Ty)
+ GEN_ERROR("vector select condition element type must be boolean");
+ if (cond_type->getNumElements() != select_type->getNumElements())
+ GEN_ERROR("vector select number of elements must be the same");
+ } else {
+ if ($2->getType() != Type::Int1Ty)
+ GEN_ERROR("select condition must be boolean");
+ }
if ($4->getType() != $6->getType())
- GEN_ERROR("select value types should match");
+ GEN_ERROR("select value types must match");
$$ = SelectInst::Create($2, $4, $6);
CHECK_FOR_ERROR
}
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index 0d6b6f2edbe..eeba0e5ed81 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1499,8 +1499,19 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
Value *TrueVal, *FalseVal, *Cond;
if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) ||
getValue(Record, OpNum, TrueVal->getType(), FalseVal) ||
- getValue(Record, OpNum, Type::Int1Ty, Cond))
+ getValue(Record, OpNum, 0 /*skip type check*/, Cond))
return Error("Invalid SELECT record");
+
+ // select condition can be either i1 or [N x i1]
+ if (const VectorType* vector_type = dyn_cast(Cond->getType())) {
+ // expect
+ if (vector_type->getElementType() != Type::Int1Ty)
+ return Error("Invalid SELECT condition type");
+ } else {
+ // expect i1
+ if (Cond->getType() != Type::Int1Ty)
+ return Error("Invalid SELECT condition type");
+ }
I = SelectInst::Create(Cond, TrueVal, FalseVal);
break;
@@ -1563,6 +1574,22 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
I = new VICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS);
break;
}
+ case bitc::FUNC_CODE_INST_VCMP: { // VCMP: [opty, opval, opval, pred]
+ // Fcmp/ICmp returning vector of bool
+ unsigned OpNum = 0;
+ Value *LHS, *RHS;
+ if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
+ getValue(Record, OpNum, LHS->getType(), RHS) ||
+ OpNum+1 != Record.size())
+ return Error("Invalid VCMP record");
+
+ // will always be vector
+ if (LHS->getType()->isFPOrFPVector())
+ I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS);
+ else
+ I = new ICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS);
+ break;
+ }
case bitc::FUNC_CODE_INST_GETRESULT: { // GETRESULT: [ty, val, n]
if (Record.size() != 2)
return Error("Invalid GETRESULT record");
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index b8aab5acc19..19f5beaf19f 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -641,7 +641,14 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal,
case Instruction::FCmp:
case Instruction::VICmp:
case Instruction::VFCmp:
- Code = bitc::CST_CODE_CE_CMP;
+ if (isa(C->getOperand(0)->getType())
+ && (CE->getOpcode() == Instruction::ICmp
+ || CE->getOpcode() == Instruction::FCmp)) {
+ // compare returning vector of Int1Ty
+ assert(0 && "Unsupported constant!");
+ } else {
+ Code = bitc::CST_CODE_CE_CMP;
+ }
Record.push_back(VE.getTypeID(C->getOperand(0)->getType()));
Record.push_back(VE.getValueID(C->getOperand(0)));
Record.push_back(VE.getValueID(C->getOperand(1)));
@@ -765,7 +772,14 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
case Instruction::FCmp:
case Instruction::VICmp:
case Instruction::VFCmp:
- Code = bitc::FUNC_CODE_INST_CMP;
+ if (isa(I.getOperand(0)->getType())
+ && (I.getOpcode() == Instruction::ICmp
+ || I.getOpcode() == Instruction::FCmp)) {
+ // compare returning vector of Int1Ty
+ Code = bitc::FUNC_CODE_INST_VCMP;
+ } else {
+ Code = bitc::FUNC_CODE_INST_CMP;
+ }
PushValueAndType(I.getOperand(0), InstID, Vals, VE);
Vals.push_back(VE.getValueID(I.getOperand(1)));
Vals.push_back(cast(I).getPredicate());
diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp
index 805fb2564a4..af11fce5e72 100644
--- a/lib/VMCore/Verifier.cpp
+++ b/lib/VMCore/Verifier.cpp
@@ -659,8 +659,21 @@ void Verifier::visitSwitchInst(SwitchInst &SI) {
}
void Verifier::visitSelectInst(SelectInst &SI) {
- Assert1(SI.getCondition()->getType() == Type::Int1Ty,
- "Select condition type must be bool!", &SI);
+ if (const VectorType* vt
+ = dyn_cast(SI.getCondition()->getType())) {
+ Assert1( vt->getElementType() == Type::Int1Ty,
+ "Select condition type must be vector of bool!", &SI);
+ if (const VectorType* val_vt
+ = dyn_cast(SI.getTrueValue()->getType())) {
+ Assert1( vt->getNumElements() == val_vt->getNumElements(),
+ "Select vector size != value vector size", &SI);
+ } else {
+ Assert1(0, "Vector select values must have vector types", &SI);
+ }
+ } else {
+ Assert1(SI.getCondition()->getType() == Type::Int1Ty,
+ "Select condition type must be bool!", &SI);
+ }
Assert1(SI.getTrueValue()->getType() == SI.getFalseValue()->getType(),
"Select values must have identical types!", &SI);
Assert1(SI.getTrueValue()->getType() == SI.getType(),
@@ -1028,7 +1041,7 @@ void Verifier::visitICmpInst(ICmpInst& IC) {
Assert1(Op0Ty == Op1Ty,
"Both operands to ICmp instruction are not of the same type!", &IC);
// Check that the operands are the right type
- Assert1(Op0Ty->isInteger() || isa(Op0Ty),
+ Assert1(Op0Ty->isIntOrIntVector() || isa(Op0Ty),
"Invalid operand types for ICmp instruction", &IC);
visitInstruction(IC);
}
@@ -1040,7 +1053,7 @@ void Verifier::visitFCmpInst(FCmpInst& FC) {
Assert1(Op0Ty == Op1Ty,
"Both operands to FCmp instruction are not of the same type!", &FC);
// Check that the operands are the right type
- Assert1(Op0Ty->isFloatingPoint(),
+ Assert1(Op0Ty->isFPOrFPVector(),
"Invalid operand types for FCmp instruction", &FC);
visitInstruction(FC);
}
diff --git a/test/Assembler/vbool-cmp.ll b/test/Assembler/vbool-cmp.ll
new file mode 100644
index 00000000000..ac8fb29362f
--- /dev/null
+++ b/test/Assembler/vbool-cmp.ll
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | grep {icmp slt}
+; rudimentary test of fcmp/icmp on vectors returning vector of bool
+
+define <4 x i1> @ffoo(<4 x float> %a, <4 x float> %b) nounwind {
+entry:
+ %cmp = fcmp olt <4 x float> %a, %b ; <4 x i1> [#uses=1]
+ ret <4 x i1> %cmp
+}
+
+define <4 x i1> @ifoo(<4 x i32> %a, <4 x i32> %b) nounwind {
+entry:
+ %cmp = icmp slt <4 x i32> %a, %b ; <4 x i1> [#uses=1]
+ ret <4 x i1> %cmp
+}
+
diff --git a/test/Assembler/vector-select.ll b/test/Assembler/vector-select.ll
new file mode 100644
index 00000000000..87af602aaf5
--- /dev/null
+++ b/test/Assembler/vector-select.ll
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | grep select
+; rudimentary test of select on vectors returning vector of bool
+
+define <4 x i32> @foo(<4 x i32> %a, <4 x i32> %b,
+ <4 x i1> %cond) nounwind {
+entry:
+ %cmp = select <4 x i1> %cond, <4 x i32> %a, <4 x i32> %b
+ ; <4 x i32> [#uses=1]
+ ret <4 x i32> %cmp
+}
+