Implement count leading zeros (ctlz), count trailing zeros (cttz), and count

population (ctpop).  Generic lowering is implemented, however only promotion
is implemented for SelectionDAG at the moment.

More coming soon.

llvm-svn: 21676
This commit is contained in:
Andrew Lenharth 2005-05-03 17:19:30 +00:00
parent f436286cf6
commit 5e177826fd
14 changed files with 326 additions and 14 deletions

View File

@ -44,6 +44,10 @@ class SelectionDAG {
// AllNodes - All of the nodes in the DAG
std::vector<SDNode*> AllNodes;
// ValueNodes - track SrcValue nodes
std::map<std::pair<const Value*, int>, SDNode*> ValueNodes;
public:
SelectionDAG(TargetLowering &tli, MachineFunction &mf) : TLI(tli), MF(mf) {
EntryNode = Root = getNode(ISD::EntryToken, MVT::Other);
@ -183,7 +187,7 @@ public:
SDOperand getLoad(MVT::ValueType VT, SDOperand Chain, SDOperand Ptr, SDOperand SV);
// getSrcValue - construct a node to track a Value* through the backend
SDOperand getSrcValue(const Value* I);
SDOperand getSrcValue(const Value* I, int offset = 0);
void replaceAllUsesWith(SDOperand Old, SDOperand New) {
assert(Old != New && "RAUW self!");

View File

@ -100,6 +100,9 @@ namespace ISD {
// Bitwise operators.
AND, OR, XOR, SHL, SRA, SRL,
// Counting operators
CTTZ, CTLZ, CTPOP,
// Select operator.
SELECT,
@ -546,7 +549,7 @@ protected:
ND = N4.Val->getNodeDepth();
NodeDepth = ND+1;
Operands.reserve(3); Operands.push_back(N1); Operands.push_back(N2);
Operands.reserve(4); Operands.push_back(N1); Operands.push_back(N2);
Operands.push_back(N3); Operands.push_back(N4);
N1.Val->Uses.push_back(this); N2.Val->Uses.push_back(this);
N3.Val->Uses.push_back(this); N4.Val->Uses.push_back(this);
@ -748,13 +751,15 @@ public:
class SrcValueSDNode : public SDNode {
const Value *V;
int offset;
protected:
friend class SelectionDAG;
SrcValueSDNode(const Value* v)
: SDNode(ISD::SRCVALUE, MVT::Other), V(v) {}
SrcValueSDNode(const Value* v, int o)
: SDNode(ISD::SRCVALUE, MVT::Other), V(v), offset(o) {}
public:
const Value *getValue() const { return V; }
int getOffset() const { return offset; }
static bool classof(const SrcValueSDNode *) { return true; }
static bool classof(const SDNode *N) {

View File

@ -63,13 +63,17 @@ namespace Intrinsic {
// libm related functions.
isunordered, // Return true if either argument is a NaN
sqrt,
ctpop, //count population
ctlz, //count leading zeros
cttz, //count trailing zeros
sqrt, //square root
// Input/Output intrinsics.
readport,
writeport,
readio,
writeio
};
} // End Intrinsic namespace

View File

@ -16,6 +16,7 @@
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include <iostream>
using namespace llvm;
@ -164,6 +165,201 @@ void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
AbortFCache);
break;
}
case Intrinsic::ctpop: {
Value *Src = CI->getOperand(1);
switch (CI->getOperand(0)->getType()->getTypeID())
{
case Type::SByteTyID:
case Type::UByteTyID:
{
Value* SA = ConstantUInt::get(Type::UByteTy, 1);
Value* MA = ConstantUInt::get(Type::UIntTy, 0x55);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 2);
MA = ConstantUInt::get(Type::UIntTy, 0x33);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 4);
MA = ConstantUInt::get(Type::UIntTy, 0x0F);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA), "ctpop");
}
break;
case Type::ShortTyID:
case Type::UShortTyID:
{
Value* SA = ConstantUInt::get(Type::UByteTy, 1);
Value* MA = ConstantUInt::get(Type::UIntTy, 0x5555);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 2);
MA = ConstantUInt::get(Type::UIntTy, 0x3333);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 4);
MA = ConstantUInt::get(Type::UIntTy, 0x0F0F);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 8);
MA = ConstantUInt::get(Type::UIntTy, 0x00FF);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA), "ctpop");
}
break;
case Type::IntTyID:
case Type::UIntTyID:
{
Value* SA = ConstantUInt::get(Type::UByteTy, 1);
Value* MA = ConstantUInt::get(Type::UIntTy, 0x55555555);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 2);
MA = ConstantUInt::get(Type::UIntTy, 0x33333333);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 4);
MA = ConstantUInt::get(Type::UIntTy, 0x0F0F0F0F);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 8);
MA = ConstantUInt::get(Type::UIntTy, 0x00FF00FF);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 8);
MA = ConstantUInt::get(Type::UIntTy, 0x0000FFFF);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA), "ctpop");
}
break;
case Type::LongTyID:
case Type::ULongTyID:
{
Value* SA = ConstantUInt::get(Type::UByteTy, 1);
Value* MA = ConstantUInt::get(Type::ULongTy, 0x5555555555555555ULL);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 2);
MA = ConstantUInt::get(Type::ULongTy, 0x3333333333333333ULL);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 4);
MA = ConstantUInt::get(Type::ULongTy, 0x0F0F0F0F0F0F0F0FULL);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 8);
MA = ConstantUInt::get(Type::ULongTy, 0x00FF00FF00FF00FFULL);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA));
SA = ConstantUInt::get(Type::UByteTy, 16);
MA = ConstantUInt::get(Type::ULongTy, 0x00000000FFFFFFFFULL);
Src = BinaryOperator::create(Instruction::Add,
BinaryOperator::create(Instruction::And, Src, MA),
BinaryOperator::create(Instruction::And,
new ShiftInst(Instruction::Shr, Src, SA),
MA), "ctpop");
}
break;
default:
abort();
}
CI->replaceAllUsesWith(Src);
break;
}
case Intrinsic::ctlz: {
Value *Src = CI->getOperand(1);
Value* SA;
switch (CI->getOperand(0)->getType()->getTypeID())
{
case Type::LongTyID:
case Type::ULongTyID:
SA = ConstantUInt::get(Type::UByteTy, 32);
Src = BinaryOperator::create(Instruction::Or, Src, new ShiftInst(Instruction::Shr, Src, SA));
case Type::IntTyID:
case Type::UIntTyID:
SA = ConstantUInt::get(Type::UByteTy, 16);
Src = BinaryOperator::create(Instruction::Or, Src, new ShiftInst(Instruction::Shr, Src, SA));
case Type::ShortTyID:
case Type::UShortTyID:
SA = ConstantUInt::get(Type::UByteTy, 8);
Src = BinaryOperator::create(Instruction::Or, Src, new ShiftInst(Instruction::Shr, Src, SA));
default:
SA = ConstantUInt::get(Type::UByteTy, 1);
Src = BinaryOperator::create(Instruction::Or, Src, new ShiftInst(Instruction::Shr, Src, SA));
SA = ConstantUInt::get(Type::UByteTy, 2);
Src = BinaryOperator::create(Instruction::Or, Src, new ShiftInst(Instruction::Shr, Src, SA));
SA = ConstantUInt::get(Type::UByteTy, 4);
Src = BinaryOperator::create(Instruction::Or, Src, new ShiftInst(Instruction::Shr, Src, SA));
};
Src = BinaryOperator::createNot(Src);
Src = new CallInst(new Function(CI->getCalledFunction()->getFunctionType(),
CI->getCalledFunction()->getLinkage(),
"llvm.ctpop"), Src);
CI->replaceAllUsesWith(Src);
break;
}
case Intrinsic::cttz: {
Value *Src = CI->getOperand(1);
Src = BinaryOperator::create(Instruction::And, BinaryOperator::createNot(Src),
BinaryOperator::create(Instruction::Sub, Src,
ConstantUInt::get(CI->getOperand(0)->getType(), 1)));
Src = new CallInst(new Function(CI->getCalledFunction()->getFunctionType(),
CI->getCalledFunction()->getLinkage(),
"llvm.ctpop"), Src);
CI->replaceAllUsesWith(Src);
break;
}
case Intrinsic::returnaddress:
case Intrinsic::frameaddress:

View File

@ -987,6 +987,51 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
}
break;
case ISD::CTPOP:
case ISD::CTTZ:
case ISD::CTLZ:
Tmp1 = LegalizeOp(Node->getOperand(0)); // Op
switch (TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0))) {
case TargetLowering::Legal:
if (Tmp1 != Node->getOperand(0))
Result = DAG.getNode(Node->getOpcode(), Node->getValueType(0), Tmp1);
break;
case TargetLowering::Promote: {
MVT::ValueType OVT = Tmp1.getValueType();
MVT::ValueType NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), OVT);
//Zero extend the argument
Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, NVT, Tmp1);
// Perform the larger operation, then subtract if needed.
Tmp1 = DAG.getNode(Node->getOpcode(), Node->getValueType(0), Tmp1);
switch(Node->getOpcode())
{
case ISD::CTPOP:
Result = Tmp1;
break;
case ISD::CTTZ:
//if Tmp1 == sizeinbits(NVT) then Tmp1 = sizeinbits(Old VT)
Tmp2 = DAG.getSetCC(ISD::SETEQ, MVT::i1, Tmp1,
DAG.getConstant(getSizeInBits(NVT), NVT));
Result = DAG.getNode(ISD::SELECT, NVT, Tmp2,
DAG.getConstant(getSizeInBits(OVT),NVT), Tmp1);
break;
case ISD::CTLZ:
//Tmp1 = Tmp1 - (sizeinbits(NVT) - sizeinbits(Old VT))
Result = DAG.getNode(ISD::SUB, NVT, Tmp1,
DAG.getConstant(getSizeInBits(NVT) -
getSizeInBits(OVT), NVT));
break;
}
break;
}
case TargetLowering::Custom:
assert(0 && "Cannot custom handle this yet!");
case TargetLowering::Expand:
assert(0 && "Cannot expand this yet!");
break;
}
break;
// Unary operators
case ISD::FABS:
case ISD::FNEG:

View File

@ -1328,10 +1328,13 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
return SDOperand(N, 0);
}
SDOperand SelectionDAG::getSrcValue(const Value* v) {
SDNode *N = new SrcValueSDNode(v);
SDOperand SelectionDAG::getSrcValue(const Value* v, int offset) {
if (v && ValueNodes[std::make_pair(v,offset)])
return SDOperand(ValueNodes[std::make_pair(v,offset)], 0);
SDNode *N = new SrcValueSDNode(v, offset);
N->setValueTypes(MVT::Other);
// FIXME: memoize NODES
if (v) //only track non-null values
ValueNodes[std::make_pair(v,offset)] = N;
AllNodes.push_back(N);
return SDOperand(N, 0);
}

View File

@ -707,6 +707,21 @@ void SelectionDAGLowering::visitCall(CallInst &I) {
DAG.setRoot(DAG.getNode(ISD::PCMARKER, MVT::Other, getRoot(), Num));
return;
}
case Intrinsic::cttz:
setValue(&I, DAG.getNode(ISD::CTTZ,
getValue(I.getOperand(1)).getValueType(),
getValue(I.getOperand(1))));
return;
case Intrinsic::ctlz:
setValue(&I, DAG.getNode(ISD::CTLZ,
getValue(I.getOperand(1)).getValueType(),
getValue(I.getOperand(1))));
return;
case Intrinsic::ctpop:
setValue(&I, DAG.getNode(ISD::CTPOP,
getValue(I.getOperand(1)).getValueType(),
getValue(I.getOperand(1))));
return;
}
SDOperand Callee;

View File

@ -76,6 +76,10 @@ namespace {
setOperationAction(ISD::SREM , MVT::f32 , Expand);
setOperationAction(ISD::SREM , MVT::f64 , Expand);
// setOperationAction(ISD::CTPOP , MVT::i64 , Expand);
// setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
// setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
//If this didn't legalize into a div....
// setOperationAction(ISD::SREM , MVT::i64, Expand);
// setOperationAction(ISD::UREM , MVT::i64, Expand);
@ -1215,6 +1219,15 @@ unsigned ISel::SelectExpr(SDOperand N) {
Node->dump();
assert(0 && "Node not handled!\n");
case ISD::CTPOP:
case ISD::CTTZ:
case ISD::CTLZ:
Opc = opcode == ISD::CTPOP ? Alpha::CTPOP :
(opcode == ISD::CTTZ ? Alpha::CTTZ : Alpha::CTLZ);
Tmp1 = SelectExpr(N.getOperand(0));
BuildMI(BB, Opc, 1, Result).addReg(Tmp1);
return Result;
case ISD::MULHU:
Tmp1 = SelectExpr(N.getOperand(0));
Tmp2 = SelectExpr(N.getOperand(1));

View File

@ -186,12 +186,9 @@ def BIC : OForm< 0x11, 0x08, (ops GPRC:$RC, GPRC:$RA, GPRC:$RB), "bic $RA,$
def BICi : OFormL<0x11, 0x08, (ops GPRC:$RC, GPRC:$RA, u8imm:$L), "bic $RA,$L,$RC">; //Bit clear
def BIS : OForm< 0x11, 0x20, (ops GPRC:$RC, GPRC:$RA, GPRC:$RB), "bis $RA,$RB,$RC">; //Logical sum
def BISi : OFormL<0x11, 0x20, (ops GPRC:$RC, GPRC:$RA, u8imm:$L), "bis $RA,$L,$RC">; //Logical sum
def CTLZ : OForm< 0x1C, 0x32, (ops GPRC:$RC, GPRC:$RA, GPRC:$RB), "CTLZ $RA,$RB,$RC">; //Count leading zero
def CTLZi : OFormL<0x1C, 0x32, (ops GPRC:$RC, GPRC:$RA, u8imm:$L), "CTLZ $RA,$L,$RC">; //Count leading zero
def CTPOP : OForm< 0x1C, 0x30, (ops GPRC:$RC, GPRC:$RA, GPRC:$RB), "CTPOP $RA,$RB,$RC">; //Count population
def CTPOPi : OFormL<0x1C, 0x30, (ops GPRC:$RC, GPRC:$RA, u8imm:$L), "CTPOP $RA,$L,$RC">; //Count population
def CTTZ : OForm< 0x1C, 0x33, (ops GPRC:$RC, GPRC:$RA, GPRC:$RB), "CTTZ $RA,$RB,$RC">; //Count trailing zero
def CTTZi : OFormL<0x1C, 0x33, (ops GPRC:$RC, GPRC:$RA, u8imm:$L), "CTTZ $RA,$L,$RC">; //Count trailing zero
def CTLZ : OForm< 0x1C, 0x32, (ops GPRC:$RC, GPRC:$RB), "CTLZ $RB,$RC">; //Count leading zero
def CTPOP : OForm< 0x1C, 0x30, (ops GPRC:$RC, GPRC:$RB), "CTPOP $RB,$RC">; //Count population
def CTTZ : OForm< 0x1C, 0x33, (ops GPRC:$RC, GPRC:$RB), "CTTZ $RB,$RC">; //Count trailing zero
def EQV : OForm< 0x11, 0x48, (ops GPRC:$RC, GPRC:$RA, GPRC:$RB), "eqv $RA,$RB,$RC">; //Logical equivalence
def EQVi : OFormL<0x11, 0x48, (ops GPRC:$RC, GPRC:$RA, u8imm:$L), "eqv $RA,$L,$RC">; //Logical equivalence
def EXTBL : OForm< 0x12, 0x06, (ops GPRC:$RC, GPRC:$RA, GPRC:$RB), "EXTBL $RA,$RB,$RC">; //Extract byte low

View File

@ -69,6 +69,11 @@ namespace {
setOperationAction(ISD::FCOS , MVT::f32, Expand);
setOperationAction(ISD::FSQRT, MVT::f32, Expand);
//PowerPC has these, but they are not implemented
setOperationAction(ISD::CTPOP, MVT::i32 , Expand);
setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
setSetCCResultContents(ZeroOrOneSetCCResult);
addLegalFPImmediate(+0.0); // Necessary for FSEL
addLegalFPImmediate(-0.0); //

View File

@ -68,6 +68,11 @@ namespace {
setOperationAction(ISD::SREM, MVT::i64, Expand);
setOperationAction(ISD::UREM, MVT::i64, Expand);
// PowerPC has these, but they are not implemented
setOperationAction(ISD::CTPOP, MVT::i64, Expand);
setOperationAction(ISD::CTTZ , MVT::i64, Expand);
setOperationAction(ISD::CTTZ , MVT::i64, Expand);
setShiftAmountFlavor(Extend); // shl X, 32 == 0
addLegalFPImmediate(+0.0); // Necessary for FSEL
addLegalFPImmediate(-0.0); //

View File

@ -64,6 +64,9 @@ namespace {
setOperationAction(ISD::FP_ROUND_INREG , MVT::f32 , Expand);
setOperationAction(ISD::SEXTLOAD , MVT::i1 , Expand);
setOperationAction(ISD::SREM , MVT::f64 , Expand);
setOperationAction(ISD::CTPOP , MVT::i32 , Expand);
setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
if (!UnsafeFPMath) {
setOperationAction(ISD::FSIN , MVT::f64 , Expand);

View File

@ -206,6 +206,11 @@ unsigned Function::getIntrinsicID() const {
assert(getName().size() != 5 && "'llvm.' is an invalid intrinsic name!");
switch (getName()[5]) {
case 'c':
if (getName() == "llvm.ctpop") return Intrinsic::ctpop;
if (getName() == "llvm.cttz") return Intrinsic::cttz;
if (getName() == "llvm.ctlz") return Intrinsic::ctlz;
break;
case 'd':
if (getName() == "llvm.dbg.stoppoint") return Intrinsic::dbg_stoppoint;
if (getName() == "llvm.dbg.region.start")return Intrinsic::dbg_region_start;

View File

@ -723,6 +723,18 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
NumArgs = 2;
break;
case Intrinsic::ctpop:
case Intrinsic::ctlz:
case Intrinsic::cttz:
Assert1(FT->getNumParams() == 1,
"Illegal # arguments for intrinsic function!", IF);
Assert1(FT->getReturnType() == FT->getParamType(0),
"Return type does not match source type", IF);
Assert1(FT->getParamType(0)->isIntegral(),
"Argument must be of an int type!", IF);
NumArgs = 1;
break;
case Intrinsic::sqrt:
Assert1(FT->getNumParams() == 1,
"Illegal # arguments for intrinsic function!", IF);