llvm::Value *CodeGenFunction::EmitUPCPointerDiff( llvm::Value *Pointer1, llvm::Value *Pointer2, const Expr *E) { const BinaryOperator *expr = cast<BinaryOperator>(E); Expr *LHSOperand = expr->getLHS(); QualType PtrTy = LHSOperand->getType(); llvm::Value *Phase1 = EmitUPCPointerGetPhase(Pointer1); llvm::Value *Thread1 = EmitUPCPointerGetThread(Pointer1); llvm::Value *Addr1 = EmitUPCPointerGetAddr(Pointer1); llvm::Value *Phase2 = EmitUPCPointerGetPhase(Pointer2); llvm::Value *Thread2 = EmitUPCPointerGetThread(Pointer2); llvm::Value *Addr2 = EmitUPCPointerGetAddr(Pointer2); QualType PointeeTy = PtrTy->getAs<PointerType>()->getPointeeType(); QualType ElemTy; llvm::Value *Dim; llvm::tie(ElemTy, Dim) = unwrapArray(*this, PointeeTy); Qualifiers Quals = ElemTy.getQualifiers(); llvm::Constant *ElemSize = llvm::ConstantInt::get(SizeTy, getContext().getTypeSizeInChars(ElemTy).getQuantity()); llvm::Value *AddrByteDiff = Builder.CreateSub(Addr1, Addr2, "addr.diff"); llvm::Value *AddrDiff = Builder.CreateExactSDiv(AddrByteDiff, ElemSize); llvm::Value *Result; if (Quals.getLayoutQualifier() == 0) { Result = AddrDiff; } else { llvm::Constant *B = llvm::ConstantInt::get(SizeTy, Quals.getLayoutQualifier()); llvm::Value *Threads = Builder.CreateZExt(EmitUPCThreads(), SizeTy); llvm::Value *ThreadDiff = Builder.CreateMul(Builder.CreateSub(Thread1, Thread2, "thread.diff"), B); llvm::Value *PhaseDiff = Builder.CreateSub(Phase1, Phase2, "phase.diff"); llvm::Value *BlockDiff = Builder.CreateMul(Builder.CreateSub(AddrDiff, PhaseDiff), Threads, "block.diff"); Result = Builder.CreateAdd(BlockDiff, Builder.CreateAdd(ThreadDiff, PhaseDiff), "ptr.diff"); } if (Dim) { Result = Builder.CreateExactSDiv(Result, Dim, "diff.dim"); } // FIXME: Divide by the array dimension return Result; }
llvm::Value *CodeGenFunction::EmitUPCPointerCompare( llvm::Value *Pointer1, llvm::Value *Pointer2, const BinaryOperator *E) { QualType PtrTy = E->getLHS()->getType(); QualType PointeeTy = PtrTy->getAs<PointerType>()->getPointeeType(); QualType ElemTy = PointeeTy; while (const ArrayType *AT = getContext().getAsArrayType(ElemTy)) ElemTy = AT->getElementType(); Qualifiers Quals = ElemTy.getQualifiers(); // Use the standard transformations so we only // have to implement < and ==. bool Flip = false; switch (E->getOpcode()) { case BO_EQ: break; case BO_NE: Flip = true; break; case BO_LT: break; case BO_GT: std::swap(Pointer1, Pointer2); break; case BO_LE: std::swap(Pointer1, Pointer2); Flip = true; break; case BO_GE: Flip = true; break; default: llvm_unreachable("expected a comparison operator"); } llvm::Value *Phase1 = EmitUPCPointerGetPhase(Pointer1); llvm::Value *Thread1 = EmitUPCPointerGetThread(Pointer1); llvm::Value *Addr1 = EmitUPCPointerGetAddr(Pointer1); llvm::Value *Phase2 = EmitUPCPointerGetPhase(Pointer2); llvm::Value *Thread2 = EmitUPCPointerGetThread(Pointer2); llvm::Value *Addr2 = EmitUPCPointerGetAddr(Pointer2); llvm::Value *Result; // Equality has to work correctly even if the pointers // are not in the same array. if (E->getOpcode() == BO_EQ || E->getOpcode() == BO_NE) { Result = Builder.CreateAnd(Builder.CreateICmpEQ(Addr1, Addr2), Builder.CreateICmpEQ(Thread1, Thread2)); } else if (Quals.getLayoutQualifier() == 0) { Result = Builder.CreateICmpULT(Addr1, Addr2); } else { llvm::IntegerType *BoolTy = llvm::Type::getInt1Ty(CGM.getLLVMContext()); llvm::Constant *LTResult = llvm::ConstantInt::get(BoolTy, 1); llvm::Constant *GTResult = llvm::ConstantInt::get(BoolTy, 0); llvm::Constant *ElemSize = llvm::ConstantInt::get(SizeTy, getContext().getTypeSizeInChars(ElemTy).getQuantity()); llvm::Value *AddrByteDiff = Builder.CreateSub(Addr1, Addr2, "addr.diff"); llvm::Value *PhaseDiff = Builder.CreateSub(Phase1, Phase2, "phase.diff"); llvm::Value *PhaseByteDiff = Builder.CreateMul(PhaseDiff, ElemSize); llvm::Value *TestBlockLT = Builder.CreateICmpSLT(AddrByteDiff, PhaseByteDiff); llvm::Value *TestBlockEQ = Builder.CreateICmpEQ(AddrByteDiff, PhaseByteDiff); llvm::Value *TestThreadLT = Builder.CreateICmpULT(Thread1, Thread2); llvm::Value *TestThreadEQ = Builder.CreateICmpEQ(Thread1, Thread2); // Compare the block first, then the thread, then the phase Result = Builder.CreateSelect(TestBlockLT, LTResult, Builder.CreateSelect(TestBlockEQ, Builder.CreateSelect(TestThreadLT, LTResult, Builder.CreateSelect(TestThreadEQ, Builder.CreateICmpULT(Phase1, Phase2), GTResult)), GTResult)); } if (Flip) Result = Builder.CreateNot(Result); return Result; }
llvm::Value *CodeGenFunction::EmitUPCPointerArithmetic( llvm::Value *Pointer, llvm::Value *Index, QualType PtrTy, QualType IndexTy, bool IsSubtraction) { llvm::Value *Phase = EmitUPCPointerGetPhase(Pointer); llvm::Value *Thread = EmitUPCPointerGetThread(Pointer); llvm::Value *Addr = EmitUPCPointerGetAddr(Pointer); bool isSigned = IndexTy->isSignedIntegerOrEnumerationType(); unsigned width = cast<llvm::IntegerType>(Index->getType())->getBitWidth(); if (width != PointerWidthInBits) { // Zero-extend or sign-extend the pointer value according to // whether the index is signed or not. Index = Builder.CreateIntCast(Index, PtrDiffTy, isSigned, "idx.ext"); } QualType PointeeTy = PtrTy->getAs<PointerType>()->getPointeeType(); QualType ElemTy; llvm::Value *Dim; llvm::tie(ElemTy, Dim) = unwrapArray(*this, PointeeTy); if (Dim) { Index = Builder.CreateMul(Index, Dim, "idx.dim", !isSigned, isSigned); } Qualifiers Quals = ElemTy.getQualifiers(); if (IsSubtraction) Index = Builder.CreateNeg(Index); if (Quals.getLayoutQualifier() == 0) { // UPC 1.2 6.4.2p2 // If the shared array is declared with indefinite block size, // the result of the pointer-to-shared arithmetic is identical // to that described for normal C pointers in [IOS/IEC00 Sec 6.5.2] // except that the thread of the new pointer shall be the // same as that of the original pointer and the phase // component is defined to always be zero. uint64_t ElemSize = getContext().getTypeSizeInChars(ElemTy).getQuantity(); llvm::Value *ByteIndex = Builder.CreateMul(Index, llvm::ConstantInt::get(SizeTy, ElemSize)); Addr = Builder.CreateAdd(Addr, ByteIndex, "add.addr"); } else { llvm::Value *OldPhase = Phase; llvm::Constant *B = llvm::ConstantInt::get(SizeTy, Quals.getLayoutQualifier()); llvm::Value *Threads = Builder.CreateZExt(EmitUPCThreads(), SizeTy); llvm::Value *GlobalBlockSize = Builder.CreateNUWMul(Threads, B); // Combine the Phase and Thread into a single unit llvm::Value *TmpPhaseThread = Builder.CreateNUWAdd(Builder.CreateNUWMul(Thread, B), Phase); TmpPhaseThread = Builder.CreateAdd(TmpPhaseThread, Index); // Div is the number of (B * THREADS) blocks that we need to jump // Rem is Thread * B + Phase llvm::Value *Div = Builder.CreateSDiv(TmpPhaseThread, GlobalBlockSize); llvm::Value *Rem = Builder.CreateSRem(TmpPhaseThread, GlobalBlockSize); // Fix the result of the division/modulus llvm::Value *Test = Builder.CreateICmpSLT(Rem, llvm::ConstantInt::get(SizeTy, 0)); Rem = Builder.CreateSelect(Test, Builder.CreateAdd(Rem, GlobalBlockSize), Rem); llvm::Value *DecDiv = Builder.CreateSub(Div, llvm::ConstantInt::get(SizeTy, 1)); Div = Builder.CreateSelect(Test, DecDiv, Div); // Split out the Phase and Thread components Thread = Builder.CreateUDiv(Rem, B); Phase = Builder.CreateURem(Rem, B); uint64_t ElemSize = getContext().getTypeSizeInChars(ElemTy).getQuantity(); // Compute the final Addr. llvm::Value *AddrInc = Builder.CreateMul(Builder.CreateAdd(Builder.CreateSub(Phase, OldPhase), Builder.CreateMul(Div, B)), llvm::ConstantInt::get(SizeTy, ElemSize)); Addr = Builder.CreateAdd(Addr, AddrInc); } return EmitUPCPointer(Phase, Thread, Addr); }