Academic Company Events NI Developer Zone Support Solutions Products & Services Contact NI MyNI


Ask Dr. VI!

Here is your chance to ask the LabVIEW team that in-depth question that has you and your fellow wireworkers stumped. Submit your questions today!

Inside LabVIEW - How the Compiler Works

I find that many people have a fundamental question about LabVIEW and whether it is a programming language or something else. I have read a lot of different attempts to answer this question about LabVIEW and I would like to provide my own answer which I hope will provide the most complete information. In order to answer this question I need to address several related questions. What does it mean to be compiled, are LabVIEW VIs compiled or interpreted and what does the code look like to the computer, and what is in the LabVIEW runtime library? Along the way, maybe we can gain a little insight into how graphical VIs turn into something your CPU can execute.

Compiled or Interpreted?

To get us started, lets look at how compilers and translators work. The following are several equivalent code expressions.
  1. C= (A*A + 0.5)*B;
  2. (A^2 + 0.5) * B -> C
  3. A, SQR, 0.5, +, B * -> C

With a technical background, most people probably understand at least three of these - number three represents RPN found on a common calculator. As you might guess, though, computers understand none of these. To a computer, the first three occupy about a dozen bytes of memory and the fourth bitmap would be about 20KB with no compression. The computer understands only its own instructions and a small number of built-in data types. Making sense of these different forms is typically done using a parser. Many of you have probably written simple parsers to retrieve numbers from a blob of text, and the concepts are the same with language or expression parsers, but the number of details grows rapidly.

To deal with the complexity, a formal mathematical grammar is commonly used to describe what is legal and what is not legal in the language. Then the parser is built as a rather complex state machine doing tasks such as matching parenthesis. Each of the three string based expressions will be parsed and create what is known as a parse tree which looks something like Figure 1 on the right.

The parser takes the textual string apart by identifying reserved characters such as +, *, =, (, and ). It designates the others as tokens which are either constants or variables, and stores them in the parse tree to preserve their relationship. The parse tree shows that A, B, and C have been classified as variables and 0.5 has been classified as a constant. A is either consumed by the square operator or is fed twice into a multiplication whose value will be consumed by the operator + along with the constant 0.5. The output of + will be consumed by the operator * along with the value of variable B. Finally, the = or assignment takes two inputs, but unlike the commutative operators used thus far, assignment will treat one as the input value and the other as the output to be assigned into.

figure 1
Figure 1. Parse Tree

The parse tree is a very convenient structure for recording the meaning of an expression, and both interpreters and compilers will typically construct a parse tree. Interestingly, notice that the parse tree bears a striking resemblance to the fourth expression above, the LV diagram. In fact, the LabVIEW editor doesn't save a bitmap of a diagram, the information saved for a VI block diagram is the type and connection information for the nodes, which is based upon dataflow and is a superset of the information in the parse tree. The picture displayed in the editor is based upon the objects, but it is purely for the benefit of the person using the editor.

Version 1.0 of LabVIEW executed a VI by interpreting it. Like other interpreters, it repeatedly walked the parse tree calling a function for a given operator, passing in the inputs and sending the outputs to the next. When there are no more operators, your expression has completed and it is either time to loop again or the program has completed. When executing a program involves repeatedly building or inspecting a parse tree, this is referred to as interpreted execution.

Since version 2.0, LabVIEW has sent the parse tree to a compiler. The compiler walks the parse tree and generates native instructions that the computer's CPU can directly execute. When the execution takes place using native machine instructions compiled from the expressions of the original language, this is called compiled execution.

Although LabVIEW uses compiled execution, some programming languages use other approaches. Some languages like Java use a hybrid approach where the language is compiled not to a particular machine's instructions, but rather to a virtual machine which is later interpreted or translated to native machine code.

What does LabVIEW generated code look like?

We have seen that a compiler typically builds a parse tree to capture what an expression is instructing the computer to do. So maybe it would be good to look at what a compiler actually produces. It will help to use a somewhat more complex example. The following code snippets count the number of zeroes in an array of integers. Figure 2 is a simple LV diagram, and Figure 3 is pretty standard C code using a resizable array.

figure 2
Figure 2. LabVIEW Code

count= 0;
if(array && (arraySize= GetArraySize(array)))
    for(i= 0; i < arraySize; i++)
        if(array[i] == 0)
            count ++;
printf("Located %ld zeroes in array.",count);
Figure 3. C Code

To view what is produced by the C and LabVIEW compilers, it is useful to use a debugging tool or a binary file viewer. Figure 4 shows what the LabVIEW compiler produces for an Intel x86 CPU. Yes, this is actually what a compiler generates and what the CPU executes viewed as integer bytes of memory.

Address Contents
04BC7FFB
04BC800B
04BC801B
04BC802B
04BC803B
04BC804B
04BC805B
04BC806B
04BC807B
04BC808B
04BC809B
04BC80AB
04BC80BB
04BC80CB
04BC80DB
04BC80EB
04BC80FB
85C758CC  000002D8  00000000  02E0B58B
F0890000  0000003D  04840F00  8B000000
89068B36  DC8D89C1  8B000002  0002E0B5
ECBD8D00  83000002  840F00FE  0000001A
8B50368B  04478906  0847C758  00000004
8904C683  0014E937  07C70000  00000004
000447C7  C7000000  00040847  B58D0000
000002EC  462B068B  8D068908  0002D4BD
83078900  0002DCBD  8F0F0000  00000005
00006DE9  ECB58D00  8B000002  08460306
BD8D0689  000002D4  858B0789  000002D4
003D008B  0F000000  00000584  0011E900
858B0000  000002D0  00000105  D0858900
8B000002  78836845  840F0018  000000F1
02DC858B  8D8B0000  000002D8  3901C183
0B8D0FC1  89000000  0002D88D  FF93E900
8D50FFFF  0002F885  5658CC00
Figure 4. Machine Code (viewed as four byte integers)

Using another programming tool called a disassembler, we can make this a bit easier for us to read. Below is a sample of assembly code with annotations that explain what operation they instruct the CPU to perform.

Disassembled Code Annotation
C7A mov ecx,dword ptr [ebp-4]
C7D mov edx,dword ptr [ecx]
C7F add edx,4
C82 mov dword ptr [ebp-8],edx
Move the value four bytes before register ebp into register ecx
Move the value pointed to by register ecx into register edx
add four to the value in register edx and store the result in edx
move the value in register edx to the memory location ebp-8
Figure 5. Assembly code with Annotations

If you are hungry for more, the following link shows the full disassembly of the code snippets with annotations.

Full Details

What is the LabVIEW Runtime?

One of the things you may have noticed from the previous section is that the C compiler doesn't generate much code for the print statement. Instead, it pushes parameters and makes a call to a helper routine. The print statement is an example of the shared code used often enough, that it is built once and placed in a convenient location for reuse. Sometimes these library routines can be statically linked into your EXE, but often they are dynamically loaded from one location on the system so that all executables can share them in a consistent manner. The library for VB, MFC, and other languages is often preinstalled with the OS so you may never notice that they are needed. If you have ever installed a Java environment, you probably noticed that many megabytes of JRT or Java runtime are installed that Java code calls into.

The LabVIEW runtime library by comparison contains approximately 750 exported functions that offer UI features like graphing, memory management functions for the dynamic arrays, and yes, even string formatting libraries similar to printf. This runtime library servers the same function for LabVIEW executables that the MFC libraries offer to executables built in C. The applications that you build in LabVIEW call into this runtime library to access helper functions and use routines and graphics that are commonly used. The only difference between C and LabVIEW is that with C programs you often don't have to install these libraries because they are included with the OS, but with LabVIEW, your installer must include these libraries. LabVIEW executables are roughly the same physical size on disk as an equivalent C application, but because the LabVIEW runtime libraries need to be installed, the LabVIEW installers look like they are larger. Over time the runtime libraries become more modular allowing for smaller installations and enabling execution on smaller targets such as Compact FieldPoint, and Real Time PXI Controllers.

By demonstrating what compilers do to the code you write in a programming language I have provided the most detailed information I can to illustrate LabVIEW as a programming language. In the process I have also shown how code created by LabVIEW compares to code created by a C compiler and I have also explained how the LabVIEW runtime libraries are used by the compiled applications. This article however is not meant to be the end of a discussion, but more the beginning of a discussion about LabVIEW as a professional development language. If you would like to comment on the contents of this article or to bring up points that this article does not cover that you would like more information about in a future article please use this discussion on LabVIEW Zone.

Submit your question. You may see Dr. VI's answer here next month.

To discuss this topic with other LabVIEW users, please join us in the Discussion Forum.