; Source: ; /*** for ***/ ; void for_count() ; { ; __attribute__((opencl_unroll_hint(1))) ; for( int i = 0; i < 1024; ++i) { ; if(i%2) continue; ; int x = i; ; } ; } ; ; /*** while ***/ ; void while_count() ; { ; int i = 1024; ; __attribute__((opencl_unroll_hint(8))) ; while(i-->0) { ; if(i%2) continue; ; int x = i; ; } ; } ; ; /*** do ***/ ; void do_count() ; { ; int i = 1024; ; __attribute__((opencl_unroll_hint)) ; do { ; if(i%2) continue; ; int x = i; ; } while(i--> 0); ; } ; ; for_count_unusual() is a synthetically written function ; ; Command: ; clang -cc1 -triple spir64 -O0 LoopUnroll.cl -emit-llvm -o /test/SPIRV/transcoding/LoopUnroll.ll ; ; unroll_full() test was generated from the following source with -O2 ; void foo(); ; ; void unroll_full() { ; #pragma clang unroll(full) ; for (int i = 0; i != 1024; ++i) { ; foo(); ; } ; } ; RUN: llvm-as < %s > %t.bc ; RUN: llvm-spirv %t.bc -o %t.spv ; RUN: llvm-spirv -to-text %t.spv -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV ; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefixes=CHECK-LLVM ; RUN: llvm-spirv %t.bc -o %t.spv --spirv-max-version=1.1 ; RUN: llvm-spirv -to-text %t.spv -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV-NEGATIVE ; Check SPIR-V versions in a format magic number + version ; CHECK-SPIRV: 119734787 66560 ; CHECK-SPIRV-NEGATIVE: 119734787 65536 target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" target triple = "spir64" ; CHECK-SPIRV: Function ; Function Attrs: noinline nounwind optnone define spir_func void @for_count() #0 { entry: ; CHECK-SPIRV: Label %i = alloca i32, align 4 %x = alloca i32, align 4 store i32 0, ptr %i, align 4 br label %for.cond for.cond: ; preds = %for.inc, %entry ; CHECK-SPIRV: Label [[#HEADER:]] %0 = load i32, ptr %i, align 4 %cmp = icmp slt i32 %0, 1024 ; Per SPIRV spec p3.23 "DontUnroll" loop control = 0x2 ; CHECK-SPIRV: LoopMerge [[#MERGEBLOCK:]] [[#CONTINUE:]] 2 ; CHECK-SPIRV: BranchConditional [[#]] [[#]] [[#MERGEBLOCK]] br i1 %cmp, label %for.body, label %for.end for.body: ; preds = %for.cond ; CHECK-SPIRV: Label %1 = load i32, ptr %i, align 4 %rem = srem i32 %1, 2 %tobool = icmp ne i32 %rem, 0 br i1 %tobool, label %if.then, label %if.end if.then: ; preds = %for.body ; CHECK-SPIRV: Label br label %for.inc if.end: ; preds = %for.body ; CHECK-SPIRV: Label %2 = load i32, ptr %i, align 4 store i32 %2, ptr %x, align 4 br label %for.inc for.inc: ; preds = %if.end, %if.then ; CHECK-SPIRV: Label [[#CONTINUE]] %3 = load i32, ptr %i, align 4 %inc = add nsw i32 %3, 1 store i32 %inc, ptr %i, align 4 br label %for.cond, !llvm.loop !5 ; CHECK-LLVM: br label %for.cond, !llvm.loop ![[#UNROLLDISABLE:]] ; CHECK-SPIRV: Branch [[#HEADER]] for.end: ; preds = %for.cond ; CHECK-SPIRV: Label [[#MERGEBLOCK]] ret void } ; CHECK-SPIRV: Function ; Function Attrs: noinline nounwind optnone define spir_func void @while_count() #0 { entry: ; CHECK-SPIRV: Label %i = alloca i32, align 4 %x = alloca i32, align 4 store i32 1024, ptr %i, align 4 br label %while.cond while.cond: ; preds = %if.end, %if.then, %entry ; CHECK-SPIRV: Label [[#HEADER:]] %0 = load i32, ptr %i, align 4 %dec = add nsw i32 %0, -1 store i32 %dec, ptr %i, align 4 %cmp = icmp sgt i32 %0, 0 ; Per SPIRV spec p3.23 "Unroll" loop control = 0x1 ; CHECK-SPIRV: LoopMerge [[#MERGEBLOCK:]] [[#CONTINUE:]] 256 8 ; CHECK-SPIRV: BranchConditional [[#]] [[#]] [[#MERGEBLOCK]] ; CHECK-SPIRV-NEGATIVE-NOT: LoopMerge {{.*}} 256 br i1 %cmp, label %while.body, label %while.end while.body: ; preds = %while.cond ; CHECK-SPIRV: Label %1 = load i32, ptr %i, align 4 %rem = srem i32 %1, 2 %tobool = icmp ne i32 %rem, 0 br i1 %tobool, label %if.then, label %if.end if.then: ; preds = %while.body ; CHECK-SPIRV: Label ; CHECK-LLVM: br label %while.cond, !llvm.loop ![[#UNROLLCOUNT:]] br label %while.cond, !llvm.loop !7 ; loop-simplify pass will create extra basic block which is the only one in ; loop having a back-edge to the header ; CHECK-SPIRV: [[#CONTINUE]] ; CHECK-SPIRV: Branch [[#HEADER]] if.end: ; preds = %while.body ; CHECK-SPIRV: Label %2 = load i32, ptr %i, align 4 store i32 %2, ptr %x, align 4 br label %while.cond, !llvm.loop !7 while.end: ; preds = %while.cond ; CHECK-SPIRV: [[#MERGEBLOCK]] ret void } ; CHECK-SPIRV: Function ; Function Attrs: noinline nounwind optnone define spir_func void @do_count() #0 { entry: ; CHECK-SPIRV: Label %i = alloca i32, align 4 %x = alloca i32, align 4 store i32 1024, ptr %i, align 4 br label %do.body do.body: ; preds = %do.cond, %entry ; CHECK-SPIRV: Label [[#HEADER:]] %0 = load i32, ptr %i, align 4 %rem = srem i32 %0, 2 %tobool = icmp ne i32 %rem, 0 ; Per SPIRV spec p3.23 "Unroll" loop control = 0x1 ; CHECK-SPIRV: LoopMerge [[#MERGEBLOCK:]] [[#CONTINUE:]] 1 ; CHECK-SPIRV: BranchConditional br i1 %tobool, label %if.then, label %if.end if.then: ; preds = %do.body ; CHECK-SPIRV: Label br label %do.cond if.end: ; preds = %do.body ; CHECK-SPIRV: Label %1 = load i32, ptr %i, align 4 store i32 %1, ptr %x, align 4 br label %do.cond do.cond: ; preds = %if.end, %if.then ; CHECK-SPIRV: Label [[#CONTINUE]] %2 = load i32, ptr %i, align 4 %dec = add nsw i32 %2, -1 store i32 %dec, ptr %i, align 4 %cmp = icmp sgt i32 %2, 0 ; CHECK-SPIRV: BranchConditional [[#]] [[#HEADER]] [[#MERGEBLOCK]] ; CHECK-LLVM: br i1 %cmp, label %do.body, label %do.end, !llvm.loop ![[#UNROLLENABLE1:]] br i1 %cmp, label %do.body, label %do.end, !llvm.loop !9 do.end: ; preds = %do.cond ; CHECK-SPIRV: Label [[#MERGEBLOCK]] ret void } ; CHECK-SPIRV: Function ; Function Attrs: noinline nounwind optnone define spir_func void @for_count_unusual() #0 { entry: ; CHECK-SPIRV: Label %i = alloca i32, align 4 %x = alloca i32, align 4 store i32 1024, ptr %i, align 4 br label %for.body for.body: ; preds = %for.cond, %entry ; CHECK-SPIRV: Label [[#HEADER:]] %0 = load i32, ptr %i, align 4 %rem = srem i32 %0, 2 %tobool = icmp ne i32 %rem, 0 ; Per SPIRV spec p3.23 "Unroll" loop control = 0x1 ; CHECK-SPIRV: LoopMerge [[#MERGEBLOCK:]] [[#CONTINUE:]] 1 ; CHECK-SPIRV: BranchConditional br i1 %tobool, label %if.then, label %if.end if.then: ; preds = %for.body ; CHECK-SPIRV: Label br label %for.cond if.end: ; preds = %for.body ; CHECK-SPIRV: Label %1 = load i32, ptr %i, align 4 store i32 %1, ptr %x, align 4 br label %for.cond for.cond: ; preds = %if.end, %if.then ; CHECK-SPIRV: Label [[#CONTINUE]] %2 = load i32, ptr %i, align 4 %dec = add nsw i32 %2, -1 store i32 %dec, ptr %i, align 4 %cmp = icmp sgt i32 %2, 0 ; CHECK-SPIRV: BranchConditional [[#]] [[#MERGEBLOCK]] [[#HEADER]] ; CHECK-LLVM: br i1 %cmp, label %for.end, label %for.body, !llvm.loop ![[#UNROLLENABLE2:]] br i1 %cmp, label %for.end, label %for.body, !llvm.loop !9 for.end: ; preds = %for.cond ; CHECK-SPIRV: Label [[#MERGEBLOCK]] ret void } ; CHECK-SPIRV: Function ; CHECK-SPIRV: Label ; CHECK-SPIRV: Branch [[#Header:]] ; CHECK-SPIRV: LoopMerge [[#Return:]] [[#Header]] 257 1 ; CHECK-SPIRV: BranchConditional [[#]] [[#Return]] [[#Header]] ; CHECK-SPIRV: Label [[#Return]] ; Function Attrs: noinline nounwind optnone define spir_func void @unroll_full() { br label %2 1: ; preds = %2 ret void 2: ; preds = %0, %2 %3 = phi i32 [ 0, %0 ], [ %4, %2 ] tail call void @_Z3foov() %4 = add nuw nsw i32 %3, 1 %5 = icmp eq i32 %4, 1024 ; CHECK-LLVM: br i1 %[[#]], label %[[#]], label %[[#]], !llvm.loop ![[#FULL:]] br i1 %5, label %1, label %2, !llvm.loop !11 } declare void @_Z3foov() attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.module.flags = !{!0} !opencl.enable.FP_CONTRACT = !{} !opencl.ocl.version = !{!1} !opencl.spir.version = !{!2} !opencl.used.extensions = !{!3} !opencl.used.optional.core.features = !{!3} !opencl.compiler.options = !{!3} !llvm.ident = !{!4} !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{i32 1, i32 0} !2 = !{i32 1, i32 2} !3 = !{} !4 = !{!"clang version 5.0.1 (cfe/trunk)"} !5 = distinct !{!5, !6} !6 = !{!"llvm.loop.unroll.disable"} !7 = distinct !{!7, !8} !8 = !{!"llvm.loop.unroll.count", i32 8} !9 = distinct !{!9, !10} !10 = !{!"llvm.loop.unroll.enable"} !11 = distinct !{!11, !12} !12 = !{!"llvm.loop.unroll.full"} ; CHECK-LLVM: ![[#UNROLLDISABLE]] = distinct !{![[#UNROLLDISABLE]], ![[#DISABLE:]]} ; CHECK-LLVM: ![[#DISABLE]] = !{!"llvm.loop.unroll.disable"} ; CHECK-LLVM: ![[#UNROLLCOUNT]] = distinct !{![[#UNROLLCOUNT]], ![[#COUNT:]]} ; CHECK-LLVM: ![[#COUNT]] = !{!"llvm.loop.unroll.count", i32 8} ; CHECK-LLVM: ![[#UNROLLENABLE1]] = distinct !{![[#UNROLLENABLE1]], ![[#ENABLE:]]} ; CHECK-LLVM: ![[#ENABLE]] = !{!"llvm.loop.unroll.enable"} ; CHECK-LLVM: ![[#UNROLLENABLE2]] = distinct !{![[#UNROLLENABLE2]], ![[#ENABLE]]} ; CHECK-LLVM: ![[#FULL]] = distinct !{![[#FULL]], ![[#UNROLLFULL:]]} ; CHECK-LLVM: ![[#UNROLLFULL]] = !{!"llvm.loop.unroll.full"}