/* TargetIntrinsicLower - To handle builtins, we want to expand the
 * invocation into normal LLVM code.  If the target can handle the builtin, this
 * function should emit the expanded code and return true.
 */
bool TreeToLLVM::TargetIntrinsicLower(tree exp,
                                      unsigned FnCode,
                                      Value *DestLoc,
                                      Value *&Result,
                                      const Type *ResultType,
                                      std::vector<Value*> &Ops,
                                      SmallVector<tree, 8> &Args,
                                      BasicBlock *CurBB,
                                      bool ResIsSigned,
                                      bool ExpIsSigned) {
  switch (FnCode) {
  default: break;
  case ALTIVEC_BUILTIN_VADDFP:
  case ALTIVEC_BUILTIN_VADDUBM:
  case ALTIVEC_BUILTIN_VADDUHM:
  case ALTIVEC_BUILTIN_VADDUWM:
    Result = BinaryOperator::createAdd(Ops[0], Ops[1], "tmp", CurBB);
    return true;
  case ALTIVEC_BUILTIN_VSUBFP:
  case ALTIVEC_BUILTIN_VSUBUBM:
  case ALTIVEC_BUILTIN_VSUBUHM:
  case ALTIVEC_BUILTIN_VSUBUWM:
    Result = BinaryOperator::createSub(Ops[0], Ops[1], "tmp", CurBB);
    return true;
  case ALTIVEC_BUILTIN_VAND:
    Result = BinaryOperator::createAnd(Ops[0], Ops[1], "tmp", CurBB);
    return true;
  case ALTIVEC_BUILTIN_VANDC:
    Ops[1] = BinaryOperator::createNot(Ops[1], "tmp", CurBB);
    Result = BinaryOperator::createAnd(Ops[0], Ops[1], "tmp", CurBB);
    return true;
  case ALTIVEC_BUILTIN_VOR:
    Result = BinaryOperator::createOr(Ops[0], Ops[1], "tmp", CurBB);
    return true;
  case ALTIVEC_BUILTIN_VNOR:
    Result = BinaryOperator::createOr(Ops[0], Ops[1], "tmp", CurBB);
    Result = BinaryOperator::createNot(Result, "tmp", CurBB);
    return true;
  case ALTIVEC_BUILTIN_VXOR:
    Result = BinaryOperator::createXor(Ops[0], Ops[1], "tmp", CurBB);
    return true;
  case ALTIVEC_BUILTIN_LVSL: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 0, "llvm.ppc.altivec.lvsl",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_LVSR: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 0, "llvm.ppc.altivec.lvsr",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_LVX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 0, "llvm.ppc.altivec.lvx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_LVXL: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 0, "llvm.ppc.altivec.lvxl",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_LVEBX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 0, "llvm.ppc.altivec.lvebx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_LVEHX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 0, "llvm.ppc.altivec.lvehx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_LVEWX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 0, "llvm.ppc.altivec.lvewx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_STVX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 1, "llvm.ppc.altivec.stvx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_STVEBX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 1, "llvm.ppc.altivec.stvebx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_STVEHX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 1, "llvm.ppc.altivec.stvehx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_STVEWX: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 1, "llvm.ppc.altivec.stvewx",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_STVXL: {
      static Constant *Cache = NULL;
      MergeIntPtrOperand(this, Cache, 1, "llvm.ppc.altivec.stvxl",
                         ResultType, Ops, CurBB, Result);
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTISB:
    if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
      Elt = ConstantExpr::getIntegerCast(Elt, Type::Int8Ty, true);
      Result = BuildVector(Elt, Elt, Elt, Elt,  Elt, Elt, Elt, Elt,
                           Elt, Elt, Elt, Elt,  Elt, Elt, Elt, Elt, NULL);
    } else {
      error("%Helement must be an immediate", &EXPR_LOCATION(exp));
      Result = UndefValue::get(VectorType::get(Type::Int8Ty, 16));
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTISH:
    if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
      Elt = ConstantExpr::getIntegerCast(Elt, Type::Int16Ty, true);
      Result = BuildVector(Elt, Elt, Elt, Elt,  Elt, Elt, Elt, Elt, NULL);
    } else {
      error("%Helement must be an immediate", &EXPR_LOCATION(exp));
      Result = UndefValue::get(VectorType::get(Type::Int16Ty, 8));
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTISW:
    if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
      Elt = ConstantExpr::getIntegerCast(Elt, Type::Int32Ty, true);
      Result = BuildVector(Elt, Elt, Elt, Elt, NULL);
    } else {
      error("%Hmask must be an immediate", &EXPR_LOCATION(exp));
      Result = UndefValue::get(VectorType::get(Type::Int32Ty, 4));
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTB:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
      int EV = Elt->getZExtValue();
      Result = BuildVectorShuffle(Ops[0], Ops[0],
                                  EV, EV, EV, EV, EV, EV, EV, EV,
                                  EV, EV, EV, EV, EV, EV, EV, EV);
    } else {
      error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTH:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
      int EV = Elt->getZExtValue();
      Result = BuildVectorShuffle(Ops[0], Ops[0],
                                  EV, EV, EV, EV, EV, EV, EV, EV);
    } else {
      error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTW:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
      int EV = Elt->getZExtValue();
      Result = BuildVectorShuffle(Ops[0], Ops[0], EV, EV, EV, EV);
    } else {
      error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VSLDOI_16QI:
  case ALTIVEC_BUILTIN_VSLDOI_8HI:
  case ALTIVEC_BUILTIN_VSLDOI_4SI:
  case ALTIVEC_BUILTIN_VSLDOI_4SF:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[2])) {
      /* Map all of these to a shuffle. */
      unsigned Amt = Elt->getZExtValue() & 15;
      VectorType *v16i8 = VectorType::get(Type::Int8Ty, 16);
      Value *Op0 = Ops[0];
      Instruction::CastOps opc = CastInst::getCastOpcode(Op0,
        IntrinsicOpIsSigned(Args,0), ResultType, false);
      Ops[0] = CastToType(opc, Op0, v16i8);
      Value *Op1 = Ops[1];
      opc = CastInst::getCastOpcode(Op1,
        IntrinsicOpIsSigned(Args,1), ResultType, false);
      Ops[1] = CastToType(opc, Op1, v16i8);
      Result = BuildVectorShuffle(Ops[0], Ops[1],
                                  Amt, Amt+1, Amt+2, Amt+3,
                                  Amt+4, Amt+5, Amt+6, Amt+7,
                                  Amt+8, Amt+9, Amt+10, Amt+11,
                                  Amt+12, Amt+13, Amt+14, Amt+15);
    } else {
      error("%Hshift amount must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VPKUHUM: {
    Value *Op0 = Ops[0];
    Instruction::CastOps opc = CastInst::getCastOpcode(Op0,
        IntrinsicOpIsSigned(Args,0), ResultType, ExpIsSigned);
    Ops[0] = CastInst::create(opc, Op0, ResultType, Op0->getName(), CurBB);
    Value *Op1 = Ops[1];
    opc = CastInst::getCastOpcode(Op1,
        IntrinsicOpIsSigned(Args,1), ResultType, ExpIsSigned);
    Ops[1] = CastInst::create(opc, Op1, ResultType, Op1->getName(), CurBB);
    Result = BuildVectorShuffle(Ops[0], Ops[1], 1, 3, 5, 7, 9, 11, 13, 15,
                                17, 19, 21, 23, 25, 27, 29, 31);
    return true;
  }
  case ALTIVEC_BUILTIN_VPKUWUM: {
    Value *Op0 = Ops[0];
    Instruction::CastOps opc = CastInst::getCastOpcode(Op0,
        IntrinsicOpIsSigned(Args,0), ResultType, ExpIsSigned);
    Ops[0] = CastInst::create(opc, Op0, ResultType, Op0->getName(), CurBB);
    Value *Op1 = Ops[1];
    opc = CastInst::getCastOpcode(Op1,
        IntrinsicOpIsSigned(Args,1), ResultType, ExpIsSigned);
    Ops[1] = CastInst::create(opc, Op1, ResultType, Op1->getName(), CurBB);
    Result = BuildVectorShuffle(Ops[0], Ops[1], 1, 3, 5, 7, 9, 11, 13, 15);
    return true;
  }
  case ALTIVEC_BUILTIN_VMRGHB:
    Result = BuildVectorShuffle(Ops[0], Ops[1],
                                0, 16, 1, 17, 2, 18, 3, 19,
                                4, 20, 5, 21, 6, 22, 7, 23);
    return true;
  case ALTIVEC_BUILTIN_VMRGHH:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11);
    return true;
  case ALTIVEC_BUILTIN_VMRGHW:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 4, 1, 5);
    return true;
  case ALTIVEC_BUILTIN_VMRGLB:
    Result = BuildVectorShuffle(Ops[0], Ops[1],
                                 8, 24,  9, 25, 10, 26, 11, 27,
                                12, 28, 13, 29, 14, 30, 15, 31);
    return true;
  case ALTIVEC_BUILTIN_VMRGLH:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15);
    return true;
  case ALTIVEC_BUILTIN_VMRGLW:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 2, 6, 3, 7);
    return true;
  case ALTIVEC_BUILTIN_ABS_V4SF: {
    /* and out sign bits */
    VectorType *v4i32 = VectorType::get(Type::Int32Ty, 4);
    Ops[0] = new BitCastInst(Ops[0], v4i32, Ops[0]->getName(),CurBB);
    Constant *C = ConstantInt::get(Type::Int32Ty, 0x7FFFFFFF);
    C = ConstantVector::get(std::vector<Constant*>(4, C));
    Result = BinaryOperator::createAnd(Ops[0], C, "tmp", CurBB);
    TargetIntrinsicCastResult(Result, ResultType,
                              ResIsSigned, ExpIsSigned, CurBB);
    return true;
  }
  case ALTIVEC_BUILTIN_ABS_V4SI:
  case ALTIVEC_BUILTIN_ABS_V8HI:
  case ALTIVEC_BUILTIN_ABS_V16QI: { /* iabs(x) -> smax(x, 0-x) */
    Result = BinaryOperator::createNeg(Ops[0], "tmp", CurBB);
    /* get the right smax intrinsic. */
    static Constant *smax[3];
    const VectorType *PTy = cast<VectorType>(ResultType);
    unsigned N = GetAltivecTypeNumFromType(PTy->getElementType());
    if (smax[N] == 0) {
      Module *M = CurBB->getParent()->getParent();
      smax[N] = M->getOrInsertFunction(std::string("llvm.ppc.altivec.vmaxs")+
                         GetAltivecLetterFromType(PTy->getElementType()),
                                      ResultType, ResultType, ResultType, NULL);
    }
    Result = new CallInst(smax[N], Ops[0], Result, "tmp", CurBB);
    return true;
  }
  case ALTIVEC_BUILTIN_ABSS_V4SI:
  case ALTIVEC_BUILTIN_ABSS_V8HI:
  case ALTIVEC_BUILTIN_ABSS_V16QI: { /* iabss(x) -> smax(x, satsub(0,x)) */
    static Constant *sxs[3], *smax[3];
    /* get the right satsub intrinsic. */
    const VectorType *PTy = cast<VectorType>(ResultType);
    unsigned N = GetAltivecTypeNumFromType(PTy->getElementType());
    if (sxs[N] == 0) {
      Module *M = CurBB->getParent()->getParent();
      sxs[N] = M->getOrInsertFunction(std::string("llvm.ppc.altivec.vsubs")+
                     GetAltivecLetterFromType(PTy->getElementType())+"s",
                                      ResultType, ResultType, ResultType, NULL);
    }
    Result = Constant::getNullValue(ResultType);
    Result = new CallInst(sxs[N], Result, Ops[0], "tmp", CurBB);
    /* get the right smax intrinsic. */
    if (smax[N] == 0) {
      Module *M = CurBB->getParent()->getParent();
      smax[N] = M->getOrInsertFunction(std::string("llvm.ppc.altivec.vmaxs")+
                         GetAltivecLetterFromType(PTy->getElementType()),
                                      ResultType, ResultType, ResultType, NULL);
    }
    Result = new CallInst(smax[N], Ops[0], Result, "tmp", CurBB);
    return true;
  }
  }

  return false;
}
Exemple #2
0
// TargetIntrinsicLower - To handle builtins, we want to expand the
//invocation into normal LLVM code.  If the target can handle the builtin, this
//function should emit the expanded code and return true.
//
bool TreeToLLVM::TargetIntrinsicLower(tree exp,
                                      unsigned FnCode,
                                      const MemRef *DestLoc,
                                      Value *&Result,
                                      const Type *ResultType,
                                      std::vector<Value*> &Ops) {
  switch (FnCode) {
  default: break;
  case ALTIVEC_BUILTIN_VADDFP:
  case ALTIVEC_BUILTIN_VADDUBM:
  case ALTIVEC_BUILTIN_VADDUHM:
  case ALTIVEC_BUILTIN_VADDUWM:
    Result = Builder.CreateAdd(Ops[0], Ops[1], "tmp");
    return true;
  case ALTIVEC_BUILTIN_VSUBFP:
  case ALTIVEC_BUILTIN_VSUBUBM:
  case ALTIVEC_BUILTIN_VSUBUHM:
  case ALTIVEC_BUILTIN_VSUBUWM:
    Result = Builder.CreateSub(Ops[0], Ops[1], "tmp");
    return true;
  case ALTIVEC_BUILTIN_VAND:
    Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
    return true;
  case ALTIVEC_BUILTIN_VANDC:
    Ops[1] = Builder.CreateNot(Ops[1], "tmp");
    Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
    return true;
  case ALTIVEC_BUILTIN_VOR:
    Result = Builder.CreateOr(Ops[0], Ops[1], "tmp");
    return true;
  case ALTIVEC_BUILTIN_VNOR:
    Result = Builder.CreateOr(Ops[0], Ops[1], "tmp");
    Result = Builder.CreateNot(Result, "tmp");
    return true;
  case ALTIVEC_BUILTIN_VXOR:
    Result = Builder.CreateXor(Ops[0], Ops[1], "tmp");
    return true;
  case ALTIVEC_BUILTIN_LVSL:
    MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvsl,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_LVSR:
    MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvsr,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_LVX:
    MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_LVXL:
    MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvxl,
                         ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_LVEBX:
    MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvebx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_LVEHX:
    MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvehx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_LVEWX:
    MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvewx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_STVX:
    MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_STVEBX:
    MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvebx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_STVEHX:
    MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvehx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_STVEWX:
    MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvewx,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_STVXL:
    MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvxl,
                       ResultType, Ops, Builder, Result);
    return true;
  case ALTIVEC_BUILTIN_VSPLTISB:
    if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
      Elt = ConstantExpr::getIntegerCast(Elt, Type::Int8Ty, true);
      Result = BuildVector(Elt, Elt, Elt, Elt,  Elt, Elt, Elt, Elt,
                           Elt, Elt, Elt, Elt,  Elt, Elt, Elt, Elt, NULL);
    } else {
      error("%Helement must be an immediate", &EXPR_LOCATION(exp));
      Result = UndefValue::get(VectorType::get(Type::Int8Ty, 16));
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTISH:
    if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
      Elt = ConstantExpr::getIntegerCast(Elt, Type::Int16Ty, true);
      Result = BuildVector(Elt, Elt, Elt, Elt,  Elt, Elt, Elt, Elt, NULL);
    } else {
      error("%Helement must be an immediate", &EXPR_LOCATION(exp));
      Result = UndefValue::get(VectorType::get(Type::Int16Ty, 8));
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTISW:
    if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
      Elt = ConstantExpr::getIntegerCast(Elt, Type::Int32Ty, true);
      Result = BuildVector(Elt, Elt, Elt, Elt, NULL);
    } else {
      error("%Hmask must be an immediate", &EXPR_LOCATION(exp));
      Result = UndefValue::get(VectorType::get(Type::Int32Ty, 4));
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTB:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
      int EV = Elt->getZExtValue();
      Result = BuildVectorShuffle(Ops[0], Ops[0],
                                  EV, EV, EV, EV, EV, EV, EV, EV,
                                  EV, EV, EV, EV, EV, EV, EV, EV);
    } else {
      error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTH:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
      int EV = Elt->getZExtValue();
      // gcc accepts anything up to 31, and there is code that tests for it, 
      // although it doesn't seem to make sense.  Hardware behaves as if mod 8.
      if (EV>7 && EV<=31)
        EV = EV%8;
      Result = BuildVectorShuffle(Ops[0], Ops[0],
                                  EV, EV, EV, EV, EV, EV, EV, EV);
    } else {
      error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VSPLTW:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
      int EV = Elt->getZExtValue();
      // gcc accepts anything up to 31, and there is code that tests for it, 
      // although it doesn't seem to make sense.  Hardware behaves as if mod 4.
      if (EV>3 && EV<=31)
        EV = EV%4;
      Result = BuildVectorShuffle(Ops[0], Ops[0], EV, EV, EV, EV);
    } else {
      error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VSLDOI_16QI:
  case ALTIVEC_BUILTIN_VSLDOI_8HI:
  case ALTIVEC_BUILTIN_VSLDOI_4SI:
  case ALTIVEC_BUILTIN_VSLDOI_4SF:
    if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[2])) {
      /* Map all of these to a shuffle. */
      unsigned Amt = Elt->getZExtValue() & 15;
      VectorType *v16i8 = VectorType::get(Type::Int8Ty, 16);
      Ops[0] = Builder.CreateBitCast(Ops[0], v16i8, "tmp");
      Ops[1] = Builder.CreateBitCast(Ops[1], v16i8, "tmp");
      Result = BuildVectorShuffle(Ops[0], Ops[1],
                                  Amt, Amt+1, Amt+2, Amt+3,
                                  Amt+4, Amt+5, Amt+6, Amt+7,
                                  Amt+8, Amt+9, Amt+10, Amt+11,
                                  Amt+12, Amt+13, Amt+14, Amt+15);
    } else {
      error("%Hshift amount must be an immediate", &EXPR_LOCATION(exp));
      Result = Ops[0];
    }
    return true;
  case ALTIVEC_BUILTIN_VPKUHUM:
    Ops[0] = Builder.CreateBitCast(Ops[0], ResultType, "tmp");
    Ops[1] = Builder.CreateBitCast(Ops[1], ResultType, "tmp");
    Result = BuildVectorShuffle(Ops[0], Ops[1], 1, 3, 5, 7, 9, 11, 13, 15,
                                17, 19, 21, 23, 25, 27, 29, 31);
    return true;
  case ALTIVEC_BUILTIN_VPKUWUM:
    Ops[0] = Builder.CreateBitCast(Ops[0], ResultType, "tmp");
    Ops[1] = Builder.CreateBitCast(Ops[1], ResultType, "tmp");
    Result = BuildVectorShuffle(Ops[0], Ops[1], 1, 3, 5, 7, 9, 11, 13, 15);
    return true;
  case ALTIVEC_BUILTIN_VMRGHB:
    Result = BuildVectorShuffle(Ops[0], Ops[1],
                                0, 16, 1, 17, 2, 18, 3, 19,
                                4, 20, 5, 21, 6, 22, 7, 23);
    return true;
  case ALTIVEC_BUILTIN_VMRGHH:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11);
    return true;
  case ALTIVEC_BUILTIN_VMRGHW:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 4, 1, 5);
    return true;
  case ALTIVEC_BUILTIN_VMRGLB:
    Result = BuildVectorShuffle(Ops[0], Ops[1],
                                 8, 24,  9, 25, 10, 26, 11, 27,
                                12, 28, 13, 29, 14, 30, 15, 31);
    return true;
  case ALTIVEC_BUILTIN_VMRGLH:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15);
    return true;
  case ALTIVEC_BUILTIN_VMRGLW:
    Result = BuildVectorShuffle(Ops[0], Ops[1], 2, 6, 3, 7);
    return true;
  case ALTIVEC_BUILTIN_ABS_V4SF: {
    // and out sign bits
    VectorType *v4i32 = VectorType::get(Type::Int32Ty, 4);
    Ops[0] = Builder.CreateBitCast(Ops[0], v4i32, "tmp");
    Constant *C = ConstantInt::get(Type::Int32Ty, 0x7FFFFFFF);
    C = ConstantVector::get(std::vector<Constant*>(4, C));
    Result = Builder.CreateAnd(Ops[0], C, "tmp");
    Result = Builder.CreateBitCast(Result, ResultType, "tmp");
    return true;
  }
  case ALTIVEC_BUILTIN_ABS_V4SI:
  case ALTIVEC_BUILTIN_ABS_V8HI:
  case ALTIVEC_BUILTIN_ABS_V16QI: { // iabs(x) -> smax(x, 0-x)
    Result = Builder.CreateNeg(Ops[0], "tmp");
    // get the right smax intrinsic.
    static const Intrinsic::ID smax_iid[3] = {
      Intrinsic::ppc_altivec_vmaxsw,
      Intrinsic::ppc_altivec_vmaxsh,
      Intrinsic::ppc_altivec_vmaxsb
    };
    const VectorType *PTy = cast<VectorType>(ResultType);
    unsigned N = GetAltivecTypeNumFromType(PTy->getElementType());
    Function *smax = Intrinsic::getDeclaration(TheModule, smax_iid[N]);
    Value *ActualOps[] = { Ops[0], Result };
    Result = Builder.CreateCall(smax, ActualOps, ActualOps+2, "tmp");
    return true;
  }
  case ALTIVEC_BUILTIN_ABSS_V4SI:
  case ALTIVEC_BUILTIN_ABSS_V8HI:
  case ALTIVEC_BUILTIN_ABSS_V16QI: { // iabss(x) -> smax(x, satsub(0,x))
    // get the right smax/subs intrinsics.
    static const Intrinsic::ID smax_iid[3] = {
      Intrinsic::ppc_altivec_vmaxsw,
      Intrinsic::ppc_altivec_vmaxsh,
      Intrinsic::ppc_altivec_vmaxsb
    };
    static const Intrinsic::ID subss_iid[3] = {
      Intrinsic::ppc_altivec_vsubsws,
      Intrinsic::ppc_altivec_vsubshs,
      Intrinsic::ppc_altivec_vsubsbs
    };
    
    // get the right satsub intrinsic.
    const VectorType *PTy = cast<VectorType>(ResultType);
    unsigned N = GetAltivecTypeNumFromType(PTy->getElementType());
    Function *smax = Intrinsic::getDeclaration(TheModule, smax_iid[N]);
    Function *subss = Intrinsic::getDeclaration(TheModule, subss_iid[N]);

    Value *ActualOps[] = { Constant::getNullValue(ResultType), Ops[0] };
    Result = Builder.CreateCall(subss, ActualOps, ActualOps+2, "tmp");
    ActualOps[0] = Ops[0];
    ActualOps[1] = Result;
    Result = Builder.CreateCall(smax, ActualOps, ActualOps+2, "tmp");
    return true;
  }
  case ALTIVEC_BUILTIN_VPERM_4SI:
  case ALTIVEC_BUILTIN_VPERM_4SF:
  case ALTIVEC_BUILTIN_VPERM_8HI:
  case ALTIVEC_BUILTIN_VPERM_16QI: {
    // Operation is identical on all types; we have a single intrinsic.
    const Type *VecTy = VectorType::get(Type::Int32Ty, 4);
    Value *Op0 = CastToType(Instruction::BitCast, Ops[0], VecTy);
    Value *Op1 = CastToType(Instruction::BitCast, Ops[1], VecTy);
    Value *ActualOps[] = { Op0, Op1, Ops[2]};
    Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule, 
                                          Intrinsic::ppc_altivec_vperm), 
                                ActualOps, ActualOps+3, "tmp");
    Result = CastToType(Instruction::BitCast, Result, Ops[0]->getType());
    return true;
  }
  case ALTIVEC_BUILTIN_VSEL_4SI:
  case ALTIVEC_BUILTIN_VSEL_4SF:
  case ALTIVEC_BUILTIN_VSEL_8HI:
  case ALTIVEC_BUILTIN_VSEL_16QI: {
    // Operation is identical on all types; we have a single intrinsic.
    const Type *VecTy = VectorType::get(Type::Int32Ty, 4);
    Value *Op0 = CastToType(Instruction::BitCast, Ops[0], VecTy);
    Value *Op1 = CastToType(Instruction::BitCast, Ops[1], VecTy);
    Value *Op2 = CastToType(Instruction::BitCast, Ops[2], VecTy);
    Value *ActualOps[] = { Op0, Op1, Op2 };
    Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule, 
                                          Intrinsic::ppc_altivec_vsel), 
                                ActualOps, ActualOps+3, "tmp");
    Result = CastToType(Instruction::BitCast, Result, Ops[0]->getType());
    return true;
  }
  }

  return false;
}