Как получить инструкцию в MachineInstr?

Я хотел знать переменную зависимость в реальном регистре (например, X86:EAX, EBX ...). Итак, я создал IR-PASS, который может идентифицировать зависимости от IR. Этот проход использует недавно добавленные переменные unsigned HasDependency: 1; а также unsigned HasMaybeDependency: 1; в Value учебный класс.

      .
      .
// Use the same type as the bitfield above so that MSVC will pack them.
unsigned IsUsedByMD : 1;
unsigned HasName : 1;
unsigned HasHungOffUses : 1;
unsigned HasDescriptor : 1;
unsigned HasDependency : 1;
unsigned HasMaybeDependency : 1;
      .
      .
      .
void setDependency() { HasDependency = true; }
void setMaybeDependency() { HasMaybeDependency = true; }
bool hasDependency() const { return HasDependency; }
bool hasMaybeDependency() const { return HasMaybeDependency; }

  //static_assert(sizeof(Value) == 2 * sizeof(void *) + 2 * sizeof(unsigned),
  //              "Value too big");

Когда применяется к фрагменту кода, как это:

extern int foo_called(int a);

int foo(int k)
{
    int __attribute__((annotate("xxx"))) a;
    for (int i = 0; i < k; i++)
    {
        int c = a + k;
        a += foo_called(c);
    }
    return 0;
}

который производит этот битовый код:

define i32 @"\01?foo@@YAHH@Z"(i32 %k) local_unnamed_addr #0 {
entry:
  %a = alloca i32, align 4
  %0 = bitcast i32* %a to i8*
  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) #2
  call void @llvm.var.annotation(i8* nonnull %0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 17)
  %cmp7 = icmp sgt i32 %k, 0
  br i1 %cmp7, label %for.body.lr.ph, label %for.cond.cleanup

for.body.lr.ph:                                   ; preds = %entry
  %.pre = load i32, i32* %a, align 4, !tbaa !3
  br label %for.body

for.cond.cleanup:                                 ; preds = %for.body, %entry
  call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) #2
  ret i32 0

for.body:                                         ; preds = %for.body, %for.body.lr.ph
  %1 = phi i32 [ %.pre, %for.body.lr.ph ], [ %add2, %for.body ]
  %i.08 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
  %add = add nsw i32 %1, %k
  %call = call i32 @"\01?foo_called@@YAHH@Z"(i32 %add)
  %2 = load i32, i32* %a, align 4, !tbaa !3
  %add2 = add nsw i32 %2, %call
  store i32 %add2, i32* %a, align 4, !tbaa !3
  %inc = add nuw nsw i32 %i.08, 1
  %exitcond = icmp eq i32 %inc, %k
  br i1 %exitcond, label %for.cond.cleanup, label %for.body
}

declare i32 @"\01?foo_called@@YAHH@Z"(i32) local_unnamed_addr #3

Результат передачи указанного битового кода:

Function - ?foo@@YAHH@Z
    Annotated Variable List :
        - Annotated : a(message: xxx)

    Annotated-Variable : a
        (Perpect)  %add2 = add nsw i32 %2, %call
        (Perpect)  %2 = load i32, i32* %a, align 4, !tbaa !3
        (Perpect)  %a = alloca i32, align 4
        (Perpect)  %cmp7 = icmp sgt i32 %k, 0
        (Maybe)  %exitcond = icmp eq i32 %inc, %k
        (Maybe)  %inc = add nuw nsw i32 %i.08, 1
        (Maybe)  %i.08 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
        (Perpect)  %call = call i32 @"\01?foo_called@@YAHH@Z"(i32 %add)
        (Perpect)  %add = add nsw i32 %1, %k
        (Perpect)  %1 = phi i32 [ %.pre, %for.body.lr.ph ], [ %add2, %for.body ]
        (Perpect)  %.pre = load i32, i32* %a, align 4, !tbaa !3

Я следовал за SelectionDAGISel.cpp: SelectAllBasicBlocks функция для получения информации от бэкэнда, но я смог получить только AllocaInst, StoreInst, а также LoadInst используя следующим образом:

for (MachineBasicBlock &MBB : mf) {
  for (MachineInstr& I : MBB) {
    for (MachineInstr::mmo_iterator i = I.memoperands_begin(), 
      e = I.memoperands_end();
      i != e; ++i) {
      if (const Value *V = (*i)->getValue())
        errs() << *V << "\n";
    }
  }
}

Как мне узнать соотношение между MachineInstr а также Instruction? Если это не предусмотрено в LLVM, какие детали необходимо исправить?

1 ответ

Решение

Это не нормально. Это трюк. Но я использую этот метод очень полезно. Если вы знаете нормальный способ, пожалуйста, дайте мне комментарий.

Я решил эту проблему, используя DebugLoc, Он используется для представления строки-столбца-строки, имени функции и т. Д.... информации о .c, .cpp файлы. Эта информация останется со времени ;;vm-ir до тех пор MachineInstr,

Так что, если гарантируется, что DebugLoc не используется в вашей обработке компилятором, вы можете поместить адрес класса, который содержит информацию, необходимую для информации о строке. Это позволит вам разыграть DebugLoc грести в нужный класс в нужное время. (Вы можете использовать столбец, потому что столбец должен быть меньше, чем 2^16.)

Ниже подробно описывается метод, который я использовал.

Измените файл и перестройте свой проект.

Несколько макетов дизайна были использованы для максимальной эффективности памяти, поэтому я не мог легко изменить класс.

Сначала измените DebugLoc-print рутина. ИДТИ К DebugLoc.cpp и удалить DIScope распечатка рутины как это Эта обработка спасет вас от времени выполнения ошибки.

void DebugLoc::print(raw_ostream &OS) const {
  if (!Loc)
    return;

  // Print source line info.
  //auto *Scope = cast<DIScope>(getScope());
  //OS << Scope->getFilename();
  OS << ':' << getLine();
  if (getCol() != 0)
    OS << ':' << getCol();

Во-вторых, верификатор должен быть изменен. Этот синтаксис будет полезен.

void Verifier::visitDILocation(const DILocation &N) {
-  AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
-           "location requires a valid scope", &N, N.getRawScope());
+  //AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
+  //         "location requires a valid scope", &N, N.getRawScope());
   if (auto *IA = N.getRawInlinedAt())
     AssertDI(isa<DILocation>(IA), "inlined-at should be a location", &N, IA);
}

В-третьих, есть несколько формальных шагов для регистрации класса в DebugLoc, Создайте функцию инициализации для этого.

static LLVMContext cnt;
static MDNode *md;

md = MDNode::get(cnt, DILocation::get(cnt, 100, 100, DIScope::get(cnt, nullptr)));

Наконец, создайте функцию регистрации.

static DebugLoc getDebugLoc(DependencyInstrInfoManager *info)
{
  return DebugLoc::get(reinterpret_cast<unsigned> (info), (uint16_t)-1, md);
}

static void setDebugLoc(Instruction *I, ...)
{
  DependencyInstrInfoManager *mgr;
  if (I->getDebugLoc()) {
    mgr = reinterpret_cast<DependencyInstrInfoManager *>
      (I->getDebugLoc()->getLine());
  } else {
    mgr = new DependencyInstrInfoManager();
    I->setDebugLoc(getDebugLoc(mgr));
  }
  mgr->addInfo(new DependencyInstrInfo(I, S, T, ...));
}

DependencyInstrInfoManager класс для ответа на вышеуказанные вопросы.

Наконец, вы можете распечатать свою собственную информацию в XXXMCInstLower.cpp:EmitInstruction();(например, X86MCInstLower.cpp). Следующее утверждение является примером вывода моего случая.

void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
  X86MCInstLower MCInstLowering(*MF, *this);
  const X86RegisterInfo *RI = MF->getSubtarget<X86Subtarget>().getRegisterInfo();

  if (MI->getDebugLoc()) {
    DependencyInstrInfoManager *mgr = reinterpret_cast<DependencyInstrInfoManager *>
      (MI->getDebugLoc()->getLine());
    mgr->doFolding();
    for (auto DI : *mgr)
      OutStreamer->AddComment(DI->getInfo());
  }

Маркировка зависимостей

Я сделал маркировку зависимостей, используя этот метод.

int foo(int k)
{
  int ANNORATE("b") b = 0;
  int ANNORATE("a") a = 0;

  for (int i = 0; i < k; i++)
  {
    int c = a + k;
    int d = b + k;
    a += foo_called(c);
    b += foo_called2(c);
  }

  return a + foo_called(b);
}

в

# BB#1:                                 # %for.body.preheader
movl    %esi, %ebx
.p2align    4, 0x90
LBB0_2 : # %for.body
# =>This Inner Loop Header: Depth=1
  addl  %esi, %edi              # [Perpect, Source:b]
# [Perpect, Source: a]
  pushl %edi                    # [Maybe, Source:b]
# [Perpect, Source: a]
  calll "?foo_called@@YAHH@Z"   # [Maybe, Source:b]
# [Perpect, Source: a]
  addl  $4, %esp                # [Maybe, Source:b]
# [Perpect, Source: a]
  addl  %eax, 4(%esp)
  pushl %edi                    # [Perpect, Source:b]
  calll "?foo_called2@@YAHH@Z"  # [Perpect, Source:b]
  addl  $4, %esp                # [Perpect, Source:b]
  addl(%esp), %eax            # [Annotated, Source:b]
  movl  4(%esp), %edi           # [Perpect, Source:b]
# [Perpect, Source: a]
  decl  %ebx                    # [Maybe, Source:b]
  movl  %eax, (%esp)
  jne   LBB0_2
  jmp   LBB0_4
Другие вопросы по тегам