// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Instruction* AddressLowering::LowerIndex(IndexInstr* instr) { __int64 elemSize = Size(instr->GetElementType()); auto addrOp = ComputeAddress(instr->BaseOp(), instr->IndexOp(), elemSize, instr); auto castOp = CastToType(addrOp, instr->ResultOp()->GetType(), addrOp->DefiningInstruction()); // Replace all uses with the new result operand and delete the original instruction. instr->ResultOp()->ReplaceWith(castOp); instr->RemoveFromBlock(true /* free */); return castOp->DefiningInstruction(); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Instruction* AddressLowering::LowerElement(ElementInstr* instr) { // The offset is always a constant in this case. __int64 fieldOffset = instr->GetField().FieldOffset; auto oneConst = irGen_.GetIntConst(irGen_.GetInt32(), 1); auto addrOp = ComputeAddress(instr->BaseOp(), oneConst, fieldOffset, instr); auto castOp = CastToType(addrOp, instr->ResultOp()->GetType(), addrOp->DefiningInstruction()); // Replace all uses with the new result operand and delete the original instruction. instr->ResultOp()->ReplaceWith(castOp); instr->RemoveFromBlock(true /* free */); return castOp->DefiningInstruction(); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Instruction* AddressLowering::LowerAddress(AddressInstr* instr) { // Nothing to do if the pointee has 'int8' type. if(instr->GetPointeeType()->IsInt8()) { return instr->NextInstruction(); } __int64 pointeeSize = Size(instr->GetPointeeType()); auto addrOp = ComputeAddress(instr->BaseOp(), instr->IndexOp(), pointeeSize, instr); auto castOp = CastToType(addrOp, instr->ResultOp()->GetType(), addrOp->DefiningInstruction()); // Replace all uses with the new result operand and delete the original instruction. instr->ResultOp()->ReplaceWith(castOp); instr->RemoveFromBlock(true /* free */); return castOp->DefiningInstruction(); }
/* 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; }
// 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; }