예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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);
}