函数总是返回1

时间:2019-01-01 00:09:24

标签: c++ function

我正在尝试编写一个简单的分支预测变量,该变量应该根据int中存储的历史记录输出TAKEN(1)或NOT_TAKEN(0)。但是,它始终输出TAKEN而不是动态更改预测。

#define PHT_CTR_MAX  3
#define PHT_CTR_INIT 2

class PREDICTOR{

  private:
    UINT32  counter;

  public:

    PREDICTOR(void);

    bool    GetPrediction(UINT64 PC);  
    void    UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget);
};



PREDICTOR::PREDICTOR(void){
  counter = PHT_CTR_INIT;
}


bool   PREDICTOR::GetPrediction(UINT64 PC){
  if(counter > (PHT_CTR_MAX/2)){ 
    return TAKEN;
  }else{
    return NOT_TAKEN;
  }
}



void  PREDICTOR::UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget){

  if(resolveDir == TAKEN){
      SatIncrement(counter, PHT_CTR_MAX);
  }else{
      SatDecrement(counter);
  }
}

PREDICTOR :: PREDICTOR用于“构建”预测变量(创建数组,设置初始值...),它从一开始就被调用。

PREDICTOR :: GetPrediction应该返回TAKEN(当计数器= 3或2时)或NOT_TAKEN(当计数器= 0或1时)。

在GetPrediction之后调用

PREDICTOR :: UpdatePredictor。它通过resolveDir更新预测变量-resolveDir是分支的实际方向。 如果resolveDir = 1,它将使计数器饱和增加(饱和意味着它永远不会超过PHT_CTR_MAX)。 如果resolveDir = 0,则计数器递减。

尽管此预测变量确实很简单,但它不起作用。它抛出的结果与我刚刚执行GetPrediction {return TAKEN}完全相同,这显然是错误的。我的编码技能不是很好,所以我可能做错了一些事情-可能是在GetPrediction或UpdatePredictor函数中。

这是一个很好的预测变量示例,尽管这有点复杂:

#define PHT_CTR_MAX  3
#define PHT_CTR_INIT 2
#define HIST_LEN   17

class PREDICTOR{

  private:
UINT32  ghr;           // global history register
UINT32  *pht;          // pattern history table
UINT32  historyLength; // history length
UINT32  numPhtEntries; // entries in pht 

public:

  PREDICTOR(void);
   bool    GetPrediction(UINT64 PC);  
   void    UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget);



PREDICTOR::PREDICTOR(void){

  historyLength    = HIST_LEN;
  ghr              = 0;
  numPhtEntries    = (1<< HIST_LEN);


    pht = new UINT32[numPhtEntries];

    for(UINT32 ii=0; ii< numPhtEntries; ii++){
    pht[ii]=PHT_CTR_INIT; 
}
}

bool   PREDICTOR::GetPrediction(UINT64 PC){

  UINT32 phtIndex   = (PC^ghr) % (numPhtEntries);
  UINT32 phtCounter = pht[phtIndex];


  if(phtCounter > (PHT_CTR_MAX/2)){ 
    return TAKEN; 
  }
  else{
    return NOT_TAKEN; 
  }
  }


void  PREDICTOR::UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget){

  UINT32 phtIndex   = (PC^ghr) % (numPhtEntries);
  UINT32 phtCounter = pht[phtIndex];

  if(resolveDir == TAKEN){
    pht[phtIndex] = SatIncrement(phtCounter, PHT_CTR_MAX);
  }else{
    pht[phtIndex] = SatDecrement(phtCounter);
  }

  // update the GHR
   ghr = (ghr << 1);

   if(resolveDir == TAKEN){
   ghr++; 
   }
 }

此预测器的工作方式与我的简单预测器相同,不同之处在于它使用计数器数组而不是单个计数器。调用GetPrediction时,将通过与PC(当前分支的地址)进行XOR运算的resolveDir(分支历史记录,全局历史记录寄存器或ghr)的后17位对数组进行索引。这将从数组中选择适当的计数器,然后将其用于进行预测。 UpdatePredictor以相同的方式工作,对数组建立索引,然后选择计数器。计数器使用来自resolveDir的信息更新。最后,全局历史记录缓冲区(ghr,分支历史记录,也可以根据需要对其进行命名)也已更新。

SatIncrementSatDecrement函数的代码:

static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
  if(x<max) return x+1;
  return x;
}

static inline UINT32 SatDecrement(UINT32 x)
{
  if(x>0) return x-1;
  return x;
}

感谢帮助。

1 个答案:

答案 0 :(得分:2)

代码无法按预期运行的原因是SatIncrementSatDecrement接受参数值并返回新值,然后必须将新值分配回应该被认为是递增/递减。

SatIncrement(counter, PHT_CTR_MAX);

将传递counter的值,但不会修改counter本身。不使用带有新值的返回值,因此该行实际上不执行任何操作。 SatDecrement(counter);也是如此。

因此,分支预测变量永远不会更改状态,并且始终返回相同的预测。

按照其他代码示例修复它:

counter = SatIncrement(counter, PHT_CTR_MAX);

counter = SatDecrement(counter);

鉴于这是一种练习,您可能无法更改SatIncrementSatDecrement,但是在实践中,可能会让这些函数按引用引用参数,以便它们可以直接修改传递的变量,避免在呼叫站点重复counter

static inline void SatIncrement(UINT32& x, UINT32 max)
{
  if(x<max) x++;
}

如果选择了原始签名,则由于C ++ 17,可以在函数中添加[[nodiscard]]属性,以使编译器在不使用返回值的情况下显示警告:

[[nodiscard]] static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
  if(x<max) return x+1;
  return x;
}

它会在这里警告您,并使问题更加清楚。