Skip to content

Commit

Permalink
Translate new set of Intel FPGA Loop Controls
Browse files Browse the repository at this point in the history
Specification can be found here:
KhronosGroup/SPIRV-Registry#62

As per revision C -> revision E transition in the spec, patch introduces
translation of the following loop controls:
* PipelineDisableINTEL
* LoopCoalesceINTEL
* MaxInterleavingINTEL
* SpeculatedIterationsINTEL
  • Loading branch information
vmaksimo authored and AlexeySotkin committed Mar 27, 2020
1 parent 05cdada commit 7abc765
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 0 deletions.
41 changes: 41 additions & 0 deletions lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,47 @@ void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM,
Metadata.push_back(llvm::MDNode::get(*Context, Parameters));
}
}
if (LC & LoopControlPipelineEnableINTEL) {
Metadata.push_back(llvm::MDNode::get(
*Context,
getMetadataFromNameAndParameter("llvm.loop.intel.pipelining.enable",
LoopControlParameters[NumParam])));
++NumParam;
assert(NumParam <= LoopControlParameters.size() &&
"Missing loop control parameter!");
}
if (LC & LoopControlLoopCoalesceINTEL) {
if (LoopControlParameters.size()) {
Metadata.push_back(llvm::MDNode::get(
*Context,
getMetadataFromNameAndParameter("llvm.loop.coalesce.count",
LoopControlParameters[NumParam])));
++NumParam;
} else { // If LoopCoalesce has no parameters
Metadata.push_back(llvm::MDNode::get(
*Context, getMetadataFromName("llvm.loop.coalesce.enable")));
}
assert(NumParam <= LoopControlParameters.size() &&
"Missing loop control parameter!");
}
if (LC & LoopControlMaxInterleavingINTEL) {
Metadata.push_back(llvm::MDNode::get(
*Context,
getMetadataFromNameAndParameter("llvm.loop.max_interleaving.count",
LoopControlParameters[NumParam])));
++NumParam;
assert(NumParam <= LoopControlParameters.size() &&
"Missing loop control parameter!");
}
if (LC & LoopControlSpeculatedIterationsINTEL) {
Metadata.push_back(llvm::MDNode::get(
*Context, getMetadataFromNameAndParameter(
"llvm.loop.intel.speculated.iterations.count",
LoopControlParameters[NumParam])));
++NumParam;
assert(NumParam <= LoopControlParameters.size() &&
"Missing loop control parameter!");
}
llvm::MDNode *Node = llvm::MDNode::get(*Context, Metadata);

// Set the first operand to refer itself
Expand Down
28 changes: 28 additions & 0 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,34 @@ LLVMToSPIRV::getLoopControl(const BranchInst *Branch,
unsigned SafeLen = IVDep.getSafeLen();
for (auto &ArrayId : IVDep.getArrayVariables())
DependencyArrayParameters.emplace_back(ArrayId, SafeLen);
} else if (S == "llvm.loop.intel.pipelining.enable") {
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
BM->addCapability(CapabilityFPGALoopControlsINTEL);
size_t I = getMDOperandAsInt(Node, 1);
Parameters.push_back(I);
LoopControl |= spv::LoopControlPipelineEnableINTEL;
} else if (S == "llvm.loop.coalesce.enable") {
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
BM->addCapability(CapabilityFPGALoopControlsINTEL);
LoopControl |= spv::LoopControlLoopCoalesceINTEL;
} else if (S == "llvm.loop.coalesce.count") {
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
BM->addCapability(CapabilityFPGALoopControlsINTEL);
size_t I = getMDOperandAsInt(Node, 1);
Parameters.push_back(I);
LoopControl |= spv::LoopControlLoopCoalesceINTEL;
} else if (S == "llvm.loop.max_interleaving.count") {
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
BM->addCapability(CapabilityFPGALoopControlsINTEL);
size_t I = getMDOperandAsInt(Node, 1);
Parameters.push_back(I);
LoopControl |= spv::LoopControlMaxInterleavingINTEL;
} else if (S == "llvm.loop.intel.speculated.iterations.count") {
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
BM->addCapability(CapabilityFPGALoopControlsINTEL);
size_t I = getMDOperandAsInt(Node, 1);
Parameters.push_back(I);
LoopControl |= spv::LoopControlSpeculatedIterationsINTEL;
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,10 @@ inline bool isValidLoopControlMask(SPIRVWord Mask) {
ValidMask |= LoopControlInitiationIntervalINTEL;
ValidMask |= LoopControlMaxConcurrencyINTEL;
ValidMask |= LoopControlDependencyArrayINTEL;
ValidMask |= LoopControlPipelineEnableINTEL;
ValidMask |= LoopControlLoopCoalesceINTEL;
ValidMask |= LoopControlMaxInterleavingINTEL;
ValidMask |= LoopControlSpeculatedIterationsINTEL;

return (Mask & ~ValidMask) == 0;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/SPIRV/libSPIRV/spirv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,10 @@ enum LoopControlMask {
LoopControlInitiationIntervalINTEL = 0x10000,
LoopControlMaxConcurrencyINTEL = 0x20000,
LoopControlDependencyArrayINTEL = 0x40000,
LoopControlPipelineEnableINTEL = 0x80000,
LoopControlLoopCoalesceINTEL = 0x100000,
LoopControlMaxInterleavingINTEL = 0x200000,
LoopControlSpeculatedIterationsINTEL = 0x400000,
};

enum FunctionControlShift {
Expand Down
211 changes: 211 additions & 0 deletions test/transcoding/FPGALoopAttr.ll
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,175 @@ for.end36: ; preds = %for.cond29
ret void
}

; Function Attrs: noinline nounwind optnone
define spir_func void @loop_pipelining() #0 {
entry:
%a = alloca [10 x i32], align 4
%i = alloca i32, align 4
store i32 0, i32* %i, align 4
br label %for.cond

; Per SPIR-V spec, LoopControlPipelineEnableINTEL = 0x80000 (524288)
; CHECK-SPIRV: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 524288 1
; CHECK-SPIRV-NEXT: 4 BranchConditional {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
; CHECK-SPIRV-NEGATIVE-NOT: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 524288 1
for.cond: ; preds = %for.inc, %entry
%0 = load i32, i32* %i, align 4
%cmp = icmp ne i32 %0, 10
br i1 %cmp, label %for.body, label %for.end

for.body: ; preds = %for.cond
%1 = load i32, i32* %i, align 4
%idxprom = sext i32 %1 to i64
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %a, i64 0, i64 %idxprom
store i32 0, i32* %arrayidx, align 4
br label %for.inc

for.inc: ; preds = %for.body
%2 = load i32, i32* %i, align 4
%inc = add nsw i32 %2, 1
store i32 %inc, i32* %i, align 4
br label %for.cond, !llvm.loop !12

for.end: ; preds = %for.cond
ret void
}

; Function Attrs: noinline nounwind optnone
define spir_func void @loop_coalesce() #0 {
entry:
%i = alloca i32, align 4
%m = alloca i32, align 4
store i32 0, i32* %i, align 4
store i32 42, i32* %m, align 4
br label %while.cond

; Per SPIR-V spec, LoopControlLoopCoalesceINTEL = 0x100000 (1048576)
; CHECK-SPIRV: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 1048576 4
; CHECK-SPIRV-NEXT: 4 BranchConditional {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
; CHECK-SPIRV-NEGATIVE-NOT: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 1048576 4
while.cond: ; preds = %if.end, %if.then, %entry
%0 = load i32, i32* %i, align 4
%1 = load i32, i32* %m, align 4
%cmp = icmp slt i32 %0, %1
br i1 %cmp, label %while.body, label %while.end

while.body: ; preds = %while.cond
%2 = load i32, i32* %i, align 4
%rem = srem i32 %2, 2
%tobool = icmp ne i32 %rem, 0
br i1 %tobool, label %if.then, label %if.end

if.then: ; preds = %while.body
%3 = load i32, i32* %i, align 4
%inc = add nsw i32 %3, 1
store i32 %inc, i32* %i, align 4
br label %while.cond, !llvm.loop !14

if.end: ; preds = %while.body
br label %while.cond, !llvm.loop !14

while.end: ; preds = %while.cond
store i32 0, i32* %i, align 4
br label %while.cond1

; Per SPIR-V spec, LoopControlLoopCoalesceINTEL = 0x100000 (1048576)
; CHECK-SPIRV: 4 LoopMerge {{[0-9]+}} {{[0-9]+}} 1048576
; CHECK-SPIRV-NEXT: 4 BranchConditional {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
; CHECK-SPIRV-NEGATIVE-NOT: 4 LoopMerge {{[0-9]+}} {{[0-9]+}} 1048576
while.cond1: ; preds = %if.end8, %if.then6, %while.end
%4 = load i32, i32* %i, align 4
%5 = load i32, i32* %m, align 4
%cmp2 = icmp slt i32 %4, %5
br i1 %cmp2, label %while.body3, label %while.end9

while.body3: ; preds = %while.cond1
%6 = load i32, i32* %i, align 4
%rem4 = srem i32 %6, 3
%tobool5 = icmp ne i32 %rem4, 0
br i1 %tobool5, label %if.then6, label %if.end8

if.then6: ; preds = %while.body3
%7 = load i32, i32* %i, align 4
%inc7 = add nsw i32 %7, 1
store i32 %inc7, i32* %i, align 4
br label %while.cond1, !llvm.loop !16

if.end8: ; preds = %while.body3
br label %while.cond1, !llvm.loop !16

while.end9: ; preds = %while.cond1
ret void
}

; Function Attrs: noinline nounwind optnone
define spir_func void @max_interleaving() #0 {
entry:
%a = alloca [10 x i32], align 4
%i = alloca i32, align 4
store i32 0, i32* %i, align 4
br label %for.cond

; Per SPIR-V spec, LoopControlMaxInterleavingINTEL = 0x200000 (2097152)
; CHECK-SPIRV: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 2097152 3
; CHECK-SPIRV-NEXT: 4 BranchConditional {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
; CHECK-SPIRV-NEGATIVE-NOT: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 2097152 3
for.cond: ; preds = %for.inc, %entry
%0 = load i32, i32* %i, align 4
%cmp = icmp ne i32 %0, 10
br i1 %cmp, label %for.body, label %for.end

for.body: ; preds = %for.cond
%1 = load i32, i32* %i, align 4
%idxprom = sext i32 %1 to i64
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %a, i64 0, i64 %idxprom
store i32 0, i32* %arrayidx, align 4
br label %for.inc

for.inc: ; preds = %for.body
%2 = load i32, i32* %i, align 4
%inc = add nsw i32 %2, 1
store i32 %inc, i32* %i, align 4
br label %for.cond, !llvm.loop !18

for.end: ; preds = %for.cond
ret void
}

; Function Attrs: noinline nounwind optnone
define spir_func void @speculated_iterations() #0 {
entry:
%a = alloca [10 x i32], align 4
%i = alloca i32, align 4
store i32 0, i32* %i, align 4
br label %for.cond

; Per SPIR-V spec, LoopControlSpeculatedIterationsINTEL = 0x400000 (4194304)
; CHECK-SPIRV: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 4194304 4
; CHECK-SPIRV-NEXT: 4 BranchConditional {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
; CHECK-SPIRV-NEGATIVE-NOT: 5 LoopMerge {{[0-9]+}} {{[0-9]+}} 4194304 4
for.cond: ; preds = %for.inc, %entry
%0 = load i32, i32* %i, align 4
%cmp = icmp ne i32 %0, 10
br i1 %cmp, label %for.body, label %for.end

for.body: ; preds = %for.cond
%1 = load i32, i32* %i, align 4
%idxprom = sext i32 %1 to i64
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %a, i64 0, i64 %idxprom
store i32 0, i32* %arrayidx, align 4
br label %for.inc

for.inc: ; preds = %for.body
%2 = load i32, i32* %i, align 4
%inc = add nsw i32 %2, 1
store i32 %inc, i32* %i, align 4
br label %for.cond, !llvm.loop !20

for.end: ; preds = %for.cond
ret void
}

attributes #0 = { convergent noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "denorms-are-zero"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "uniform-work-group-size"="true" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
Expand All @@ -186,18 +355,38 @@ attributes #0 = { convergent noinline nounwind optnone "correctly-rounded-divide
!9 = distinct !{!9, !10}
!10 = !{!"llvm.loop.max_concurrency.count", i32 2}
!11 = distinct !{!11, !8, !10}
!12 = distinct !{!12, !13}
!13 = !{!"llvm.loop.intel.pipelining.enable", i32 1}
!14 = distinct !{!14, !15}
!15 = !{!"llvm.loop.coalesce.count", i32 4}
!16 = distinct !{!16, !17}
!17 = !{!"llvm.loop.coalesce.enable"}
!18 = distinct !{!18, !19}
!19 = !{!"llvm.loop.max_interleaving.count", i32 3}
!20 = distinct !{!20, !21}
!21 = !{!"llvm.loop.intel.speculated.iterations.count", i32 4}

; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_A:[0-9]+]]
; CHECK-LLVM: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_B:[0-9]+]]
; CHECK-LLVM: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_C:[0-9]+]]
; CHECK-LLVM: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_D:[0-9]+]]
; CHECK-LLVM: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_E:[0-9]+]]
; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_F:[0-9]+]]
; CHECK-LLVM: br label %while.cond{{[0-9]*}}, !llvm.loop ![[MD_G:[0-9]+]]
; CHECK-LLVM: br label %while.cond{{[0-9]+}}, !llvm.loop ![[MD_H:[0-9]+]]
; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_I:[0-9]+]]
; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_J:[0-9]+]]

; CHECK-LLVM-NEGATIVE: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_A:[0-9]+]]
; CHECK-LLVM-NEGATIVE: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_B:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_C:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_D:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %for.cond{{[0-9]+}}, !llvm.loop ![[MD_E:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_F:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %while.cond{{[0-9]*}}, !llvm.loop ![[MD_G:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %while.cond{{[0-9]+}}, !llvm.loop ![[MD_H:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_I:[0-9]+]]
; CHECK-LLVM-NEGATIVE-NOT: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD_J:[0-9]+]]

; CHECK-LLVM: ![[MD_A]] = distinct !{![[MD_A]], ![[MD_ivdep_enable:[0-9]+]]}
; CHECK-LLVM: ![[MD_ivdep_enable]] = !{!"llvm.loop.ivdep.enable"}
Expand All @@ -208,6 +397,17 @@ attributes #0 = { convergent noinline nounwind optnone "correctly-rounded-divide
; CHECK-LLVM: ![[MD_D]] = distinct !{![[MD_D]], ![[MD_max_concurrency:[0-9]+]]}
; CHECK-LLVM: ![[MD_max_concurrency]] = !{!"llvm.loop.max_concurrency.count", i32 2}
; CHECK-LLVM: ![[MD_E]] = distinct !{![[MD_E]], ![[MD_ii:[0-9]+]], ![[MD_max_concurrency:[0-9]+]]}
; CHECK-LLVM: ![[MD_F]] = distinct !{![[MD_F]], ![[MD_pipelining:[0-9]+]]}
; CHECK-LLVM: ![[MD_pipelining]] = !{!"llvm.loop.intel.pipelining.enable", i32 1}
; CHECK-LLVM: ![[MD_G]] = distinct !{![[MD_G]], ![[MD_loop_coalesce_count:[0-9]+]]}
; CHECK-LLVM: ![[MD_loop_coalesce_count]] = !{!"llvm.loop.coalesce.count", i32 4}
; CHECK-LLVM: ![[MD_H]] = distinct !{![[MD_H]], ![[MD_loop_coalesce:[0-9]+]]}
; CHECK-LLVM: ![[MD_loop_coalesce]] = !{![[MD_loop_coalesce_enable:[0-9]+]]}
; CHECK-LLVM: ![[MD_loop_coalesce_enable]] = !{!"llvm.loop.coalesce.enable"}
; CHECK-LLVM: ![[MD_I]] = distinct !{![[MD_I]], ![[MD_max_interleaving:[0-9]+]]}
; CHECK-LLVM: ![[MD_max_interleaving]] = !{!"llvm.loop.max_interleaving.count", i32 3}
; CHECK-LLVM: ![[MD_J]] = distinct !{![[MD_J]], ![[MD_spec_iterations:[0-9]+]]}
; CHECK-LLVM: ![[MD_spec_iterations]] = !{!"llvm.loop.intel.speculated.iterations.count", i32 4}

; CHECK-LLVM-NEGATIVE: ![[MD_A]] = distinct !{![[MD_A]], ![[MD_ivdep_enable:[0-9]+]]}
; CHECK-LLVM-NEGATIVE: ![[MD_ivdep_enable]] = !{!"llvm.loop.ivdep.enable"}
Expand All @@ -218,3 +418,14 @@ attributes #0 = { convergent noinline nounwind optnone "correctly-rounded-divide
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_D]] = distinct !{![[MD_D]], ![[MD_max_concurrency:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_max_concurrency]] = !{!"llvm.loop.max_concurrency.count", i32 2}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_E]] = distinct !{![[MD_E]], ![[MD_ii:[0-9]+]], ![[MD_max_concurrency:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_F]] = distinct !{![[MD_F]], ![[MD_pipelining:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_pipelining]] = !{!"llvm.loop.intel.pipelining.enable", i32 1}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_G]] = distinct !{![[MD_G]], ![[MD_loop_coalesce_count:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_loop_coalesce_count]] = !{!"llvm.loop.coalesce.count", i32 4}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_H]] = distinct !{![[MD_H]], ![[MD_loop_coalesce:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_loop_coalesce]] = !{![[MD_loop_coalesce_enable:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_loop_coalesce_enable]] = !{!"llvm.loop.coalesce.enable"}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_I]] = distinct !{![[MD_I]], ![[MD_max_interleaving:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_max_interleaving]] = !{!"llvm.loop.max_interleaving.count", i32 3}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_J]] = distinct !{![[MD_J]], ![[MD_spec_iterations:[0-9]+]]}
; CHECK-LLVM-NEGATIVE-NOT: ![[MD_spec_iterations]] = !{!"llvm.loop.intel.speculated.iterations.count", i32 4}

0 comments on commit 7abc765

Please sign in to comment.