Trong trường hợp các lệnh là độc lập với nhau, pipelining có thể thực hiện các lệnh gối lên nhau và việc gối lên nhau giữa các lệnh được gọi là Instruction level parallelism (ILP). ILP cho phép tăng khảnăng song song hóa thực hiện các lệnh, đồng thời giảm ảnh hưởng của các data hazard và control hazard, giúp tăng khảnăng xử lý để khai thác hiệu quảcơ chế song song hóạ Việc song song hóa có thểđược thực hiện bằng phần cứng và phần mềm, nếu được thực hiện bằng phần cứng thì được gọi là dynamic techniques, được thực hiện bằng phần mềm gọi là static techniques.
Mục đích của bộ biên dịch và bộ xử lý là phải nhận biết và thực hiện song song hóa ở mức tối đa có thể. Các chương trình thông thường đều được viết theo mô hình thực hiện tuần tự, trong đó, các lệnh được thực hiện lần lượt, lệnh này sau lệnh khác với thứ tựđược chỉra trong chương trình. ILP cho phép bộ biên dịch và bộ xử lý gối lên nhau khi thực hiện các lệnh, thậm chí là thay đổi thứ tự các lệnh được thực hiện. Ví dụ với chương trình sau:
1. e = a + b 2. f = c + d 3. g = e * f
Thao tác thứ ba được thực hiện dựa trên kết quả của thao tác thứ nhất và thứ hai, do đó nó không thể được thực hiện cho đến khi một, hai hoàn thành. Tuy nhiên, thao tác một
và hai không phụ thuộc lẫn nhau, nên có thểđược thực hiện đồng thờị Giả sử mỗi thao tác được hoàn thành trong một đơn vị thời gian, thì cảchương trình có thểđược thực hiện chỉ trong hai đơn vị thời gian, do đó ILP được tính là 3/2.
Dạng đơn giản nhất và phổ biến nhất của song song mức lệnh là song song mức lệnh trong vòng lặp (loop-level parallelism).
Ví dụ 1:
for (i=1; i<=1000; i= i+1) x[i] = x[i] + y[i];
Trong vòng lặp này, mỗi bước lặp là không có liên quan đến nhau, và các bước lặp có thể được thực hiện song song với nhaụ
Ví dụ 2:
for (i=1; i<=100; i= i+1) {
a[i] = a[i] + b[i]; //s1 b[i+1] = c[i] + d[i]; //s2 }
Trong mỗi bước lặp, s1 phụ thuộc vào s2, nhưng s2 không phụ thuộc vào s1. Đểxóa đi sự phụ thuộc này, nhằm thực hiện song song trong mỗi vòng lặp, ta biến đổi như sau:
a[1] = a[1] + b[1]; for (i=1; i<=99; i= i+1) {
b[i+1] = c[i] + d[i]; a[i+1] = a[i+1] + b[i+1]; }
b[101] = c[100] + d[100]; Ví dụ 3:
for (i=1; i<=100; i= i+1) {
a[i+1] = a[i] + c[i]; //s1 b[i+1] = b[i] + a[i+1]; //s2 }
Trong ví dụ này, s1 phụ thuộc vào s2, đồng thời s2 cũng phụ thuộc vào s1. Ở đây không có cách biến đổi nào để mỗi vòng lặp có thể thực hiện song song với nhau được.