lcy
lcy

Reputation: 21

What's the instruction for '&&' in LLVM IR?

I want to write an LLVM pass to reduce && in LLVM IR, but I can't find the specific instructions for it in IR. For example,

#include <iostream>

int main(){
    bool a = true;
    bool b = false;
    bool c = a && b;
    
    return 0;
}

and I get the IR,

define dso_local i32 @main() #4 {
  %1 = alloca i32, align 4
  %2 = alloca i8, align 1
  %3 = alloca i8, align 1
  %4 = alloca i8, align 1
  store i32 0, i32* %1, align 4
  store i8 1, i8* %2, align 1
  store i8 0, i8* %3, align 1
  %5 = load i8, i8* %2, align 1
  %6 = trunc i8 %5 to i1
  br i1 %6, label %7, label %10

7:                                                ; preds = %0
  %8 = load i8, i8* %3, align 1
  %9 = trunc i8 %8 to i1
  br label %10

10:                                               ; preds = %7, %0
  %11 = phi i1 [ false, %0 ], [ %9, %7 ]
  %12 = zext i1 %11 to i8
  store i8 %12, i8* %4, align 1
  ret i32 0
}

but I tried this one,

#include <iostream>

int main(){
   int a = 10;
   int b = 10;
   int c;
   c = a && b;

   return 0; 
}

and I get this

define dso_local i32 @main() #4 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 10, i32* %2, align 4
  store i32 10, i32* %3, align 4
  %5 = load i32, i32* %2, align 4
  %6 = icmp ne i32 %5, 0
  br i1 %6, label %7, label %10

7:                                                ; preds = %0
  %8 = load i32, i32* %3, align 4
  %9 = icmp ne i32 %8, 0
  br label %10

10:                                               ; preds = %7, %0
  %11 = phi i1 [ false, %0 ], [ %9, %7 ]
  %12 = zext i1 %11 to i32
  store i32 %12, i32* %4, align 4
  ret i32 0
}

I use LLVM 10 in ubuntu. I'll appreciate any answers or suggestions.

Upvotes: 2

Views: 1035

Answers (1)

sepp2k
sepp2k

Reputation: 370445

There is no LLVM instruction that specifically corresponds to the && operator. It can and will be translated in different ways depending on the expression and the optimization settings.

When you have optimizations enabled, the operands are side effect free (and not expensive to evaluate) and the whole expression can't be optimized away, clang will usually convert both operands to i1 and apply the logical and operator on them.

When optimizations are disabled or the operands have side effects, it'll usually be translated using branch instructions. That's the case in the two examples you posted.

Note that expr1 && expr2 is semantically equivalent to expr1 ? expr2 : false and you'll generally get the same LLVM code for both.

If you're okay with treating expr1 ? expr2 : false and other equivalent code (for example using if statements) the same as &&, you can try to detect the branching pattern created by them. If you need your pass to also be applicable after optimizations, you'll also have to detect at least the pattern of converting to i1 and anding.

If you only want your transformation to apply to && and nothing else, you simply can't do it at the LLVM level. You'd need an AST transformation at the Clang level.

Upvotes: 3

Related Questions