llvm/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp

// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - -triple=x86_64-- | FileCheck %s

extern volatile bool b;
extern volatile int i;
extern bool A();
extern bool B();

// CHECK-LABEL: @_Z1fv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2:![0-9]+]], !range [[RNG6:![0-9]+]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 true)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Av()
// CHECK-NEXT:    store i1 [[CALL]], ptr [[RETVAL]], align 1
// CHECK-NEXT:    br label [[RETURN:%.*]]
// CHECK:       if.end:
// CHECK-NEXT:    [[CALL1:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    store i1 [[CALL1]], ptr [[RETVAL]], align 1
// CHECK-NEXT:    br label [[RETURN]]
// CHECK:       return:
// CHECK-NEXT:    [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 1
// CHECK-NEXT:    ret i1 [[TMP1]]
//
bool f() {
  if (b)
    [[likely]] {
      return A();
    }
  return B();
}

// CHECK-LABEL: @_Z1gv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Av()
// CHECK-NEXT:    store i1 [[CALL]], ptr [[RETVAL]], align 1
// CHECK-NEXT:    br label [[RETURN:%.*]]
// CHECK:       if.end:
// CHECK-NEXT:    [[CALL1:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    store i1 [[CALL1]], ptr [[RETVAL]], align 1
// CHECK-NEXT:    br label [[RETURN]]
// CHECK:       return:
// CHECK-NEXT:    [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 1
// CHECK-NEXT:    ret i1 [[TMP1]]
//
bool g() {
  if (b)
    [[unlikely]] {
      return A();
    }

  return B();
}

// CHECK-LABEL: @_Z1hv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Av()
// CHECK-NEXT:    store i1 [[CALL]], ptr [[RETVAL]], align 1
// CHECK-NEXT:    br label [[RETURN:%.*]]
// CHECK:       if.end:
// CHECK-NEXT:    [[CALL1:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    store i1 [[CALL1]], ptr [[RETVAL]], align 1
// CHECK-NEXT:    br label [[RETURN]]
// CHECK:       return:
// CHECK-NEXT:    [[TMP1:%.*]] = load i1, ptr [[RETVAL]], align 1
// CHECK-NEXT:    ret i1 [[TMP1]]
//
bool h() {
  if (b)
    [[unlikely]] return A();

  return B();
}

// CHECK-LABEL: @_Z8NullStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    br label [[IF_END:%.*]]
// CHECK:       if.else:
// CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
// CHECK-NEXT:    br label [[IF_END]]
// CHECK:       if.end:
// CHECK-NEXT:    ret void
//
void NullStmt() {
  if (b)
    [[unlikely]];
  else {
    // Make sure the branches aren't optimized away.
    b = true;
  }
}

// CHECK-LABEL: @_Z6IfStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    br i1 [[CALL]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
// CHECK:       if.then1:
// CHECK-NEXT:    br label [[IF_END]]
// CHECK:       if.end:
// CHECK-NEXT:    br label [[IF_END2]]
// CHECK:       if.end2:
// CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL3:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT:    br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_END8:%.*]]
// CHECK:       if.then4:
// CHECK-NEXT:    [[CALL5:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    [[CALL5_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CALL5]], i1 false)
// CHECK-NEXT:    br i1 [[CALL5_EXPVAL]], label [[IF_THEN6:%.*]], label [[IF_END7:%.*]]
// CHECK:       if.then6:
// CHECK-NEXT:    store volatile i8 0, ptr @b, align 1, !tbaa [[TBAA2]]
// CHECK-NEXT:    br label [[IF_END7]]
// CHECK:       if.end7:
// CHECK-NEXT:    br label [[IF_END8]]
// CHECK:       if.end8:
// CHECK-NEXT:    ret void
//
void IfStmt() {
  if (b)
    [[unlikely]] if (B()) {}

  if (b) {
    if (B())
      [[unlikely]] { b = false; }
  }
}

// CHECK-LABEL: @_Z9WhileStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    br label [[WHILE_COND:%.*]]
// CHECK:       while.cond:
// CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    br i1 [[CALL]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]]
// CHECK:       while.body:
// CHECK-NEXT:    br label [[WHILE_COND]], !llvm.loop [[LOOP7:![0-9]+]]
// CHECK:       while.end:
// CHECK-NEXT:    br label [[IF_END]]
// CHECK:       if.end:
// CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
// CHECK:       if.then2:
// CHECK-NEXT:    br label [[WHILE_COND3:%.*]]
// CHECK:       while.cond3:
// CHECK-NEXT:    [[CALL4:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    [[CALL4_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CALL4]], i1 false)
// CHECK-NEXT:    br i1 [[CALL4_EXPVAL]], label [[WHILE_BODY5:%.*]], label [[WHILE_END6:%.*]]
// CHECK:       while.body5:
// CHECK-NEXT:    store volatile i8 0, ptr @b, align 1, !tbaa [[TBAA2]]
// CHECK-NEXT:    br label [[WHILE_COND3]], !llvm.loop [[LOOP10:![0-9]+]]
// CHECK:       while.end6:
// CHECK-NEXT:    br label [[IF_END7]]
// CHECK:       if.end7:
// CHECK-NEXT:    ret void
//
void WhileStmt() {
  if (b)
    [[unlikely]] while (B()) {}

  if (b)
    while (B())
      [[unlikely]] { b = false; }
}

// CHECK-LABEL: @_Z6DoStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    br label [[DO_BODY:%.*]]
// CHECK:       do.body:
// CHECK-NEXT:    br label [[DO_COND:%.*]]
// CHECK:       do.cond:
// CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    br i1 [[CALL]], label [[DO_BODY]], label [[DO_END:%.*]], !llvm.loop [[LOOP11:![0-9]+]]
// CHECK:       do.end:
// CHECK-NEXT:    br label [[IF_END]]
// CHECK:       if.end:
// CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
// CHECK:       if.then2:
// CHECK-NEXT:    br label [[DO_BODY3:%.*]]
// CHECK:       do.body3:
// CHECK-NEXT:    br label [[DO_COND4:%.*]]
// CHECK:       do.cond4:
// CHECK-NEXT:    [[CALL5:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    br i1 [[CALL5]], label [[DO_BODY3]], label [[DO_END6:%.*]], !llvm.loop [[LOOP12:![0-9]+]]
// CHECK:       do.end6:
// CHECK-NEXT:    br label [[IF_END7]]
// CHECK:       if.end7:
// CHECK-NEXT:    ret void
//
void DoStmt() {
  if (b)
    [[unlikely]] do {}
    while (B())
      ;

  if (b)
    do
      [[unlikely]] {}
    while (B());
}

// CHECK-LABEL: @_Z7ForStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    br label [[FOR_COND:%.*]]
// CHECK:       for.cond:
// CHECK-NEXT:    [[CALL:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    br i1 [[CALL]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
// CHECK:       for.body:
// CHECK-NEXT:    br label [[FOR_COND]], !llvm.loop [[LOOP13:![0-9]+]]
// CHECK:       for.end:
// CHECK-NEXT:    br label [[IF_END]]
// CHECK:       if.end:
// CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
// CHECK:       if.then2:
// CHECK-NEXT:    br label [[FOR_COND3:%.*]]
// CHECK:       for.cond3:
// CHECK-NEXT:    [[CALL4:%.*]] = call noundef zeroext i1 @_Z1Bv()
// CHECK-NEXT:    [[CALL4_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CALL4]], i1 false)
// CHECK-NEXT:    br i1 [[CALL4_EXPVAL]], label [[FOR_BODY5:%.*]], label [[FOR_END6:%.*]]
// CHECK:       for.body5:
// CHECK-NEXT:    br label [[FOR_COND3]], !llvm.loop [[LOOP14:![0-9]+]]
// CHECK:       for.end6:
// CHECK-NEXT:    br label [[IF_END7]]
// CHECK:       if.end7:
// CHECK-NEXT:    ret void
//
void ForStmt() {
  if (b)
    [[unlikely]] for (; B();) {}

  if (b)
    for (; B();)
      [[unlikely]] {}
}

// CHECK-LABEL: @_Z8GotoStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    br label [[END:%.*]]
// CHECK:       if.else:
// CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
// CHECK-NEXT:    br label [[IF_END:%.*]]
// CHECK:       if.end:
// CHECK-NEXT:    br label [[END]]
// CHECK:       end:
// CHECK-NEXT:    ret void
//
void GotoStmt() {
  if (b)
    [[unlikely]] goto end;
  else {
    // Make sure the branches aren't optimized away.
    b = true;
  }
end:;
}

// CHECK-LABEL: @_Z10ReturnStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    br label [[IF_END:%.*]]
// CHECK:       if.else:
// CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
// CHECK-NEXT:    br label [[IF_END]]
// CHECK:       if.end:
// CHECK-NEXT:    ret void
//
void ReturnStmt() {
  if (b)
    [[unlikely]] return;
  else {
    // Make sure the branches aren't optimized away.
    b = true;
  }
}

// CHECK-LABEL: @_Z10SwitchStmtv(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK:       if.then:
// CHECK-NEXT:    [[TMP1:%.*]] = load volatile i32, ptr @i, align 4, !tbaa [[TBAA15:![0-9]+]]
// CHECK-NEXT:    switch i32 [[TMP1]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT:    ]
// CHECK:       sw.epilog:
// CHECK-NEXT:    br label [[IF_END:%.*]]
// CHECK:       if.else:
// CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
// CHECK-NEXT:    br label [[IF_END]]
// CHECK:       if.end:
// CHECK-NEXT:    [[TMP2:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP2]] to i1
// CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE4:%.*]]
// CHECK:       if.then2:
// CHECK-NEXT:    [[TMP3:%.*]] = load volatile i32, ptr @i, align 4, !tbaa [[TBAA15]]
// CHECK-NEXT:    switch i32 [[TMP3]], label [[SW_EPILOG3:%.*]] [
// CHECK-NEXT:    ]
// CHECK:       sw.epilog3:
// CHECK-NEXT:    br label [[IF_END5:%.*]]
// CHECK:       if.else4:
// CHECK-NEXT:    store volatile i8 1, ptr @b, align 1, !tbaa [[TBAA2]]
// CHECK-NEXT:    br label [[IF_END5]]
// CHECK:       if.end5:
// CHECK-NEXT:    ret void
//
void SwitchStmt() {
  if (b)
    [[unlikely]] switch (i) {}
  else {
    // Make sure the branches aren't optimized away.
    b = true;
  }
  if (b)
    switch (i)
      [[unlikely]] {}
  else {
    // Make sure the branches aren't optimized away.
    b = true;
  }
}