Index: lib/Analysis/DependenceInfo.cpp =================================================================== --- lib/Analysis/DependenceInfo.cpp +++ lib/Analysis/DependenceInfo.cpp @@ -70,8 +70,53 @@ cl::Hidden, cl::init(VALUE_BASED_ANALYSIS), cl::ZeroOrMore, cl::cat(PollyCategory)); +enum AnalyisLevel { + STATEMENT_LEVEL_ANALYSIS = 0, + REFERENCE_LEVEL_ANALYSIS, + ACCESS_LEVEL_ANALYSIS +}; +static cl::opt OptAnalysisLevel( + "polly-dependences-analysis-level", + cl::desc("The level of dependence analysis"), + cl::values(clEnumValN(STATEMENT_LEVEL_ANALYSIS, "statement-level", + "Statement-level analysis"), + clEnumValN(REFERENCE_LEVEL_ANALYSIS, "reference-level", + "Memory reference level analysis that distinguish" + " accessed references in the same statement"), + clEnumValN(ACCESS_LEVEL_ANALYSIS, "access-level", + "Memory reference level analysis that distinguish" + " access instructions in the same statement"), + clEnumValEnd), + cl::Hidden, cl::init(STATEMENT_LEVEL_ANALYSIS), cl::ZeroOrMore, + cl::cat(PollyCategory)); + //===----------------------------------------------------------------------===// +/// @brief Tag the @p Relation domain with @p TagId +static __isl_give isl_map *tag(__isl_take isl_map *Relation, + __isl_take isl_id *TagId) { + isl_space *Space = isl_map_get_space(Relation); + Space = isl_space_drop_dims(Space, isl_dim_out, 0, isl_map_n_out(Relation)); + Space = isl_space_set_tuple_id(Space, isl_dim_out, TagId); + isl_multi_aff *Tag = isl_multi_aff_domain_map(Space); + Relation = isl_map_preimage_domain_multi_aff(Relation, Tag); + return Relation; +} + +/// @brief Tag the @p Relation domain with either MA->getArrayId() or +/// MA->getId() based on @p TagLevel +static __isl_give isl_map *tag(__isl_take isl_map *Relation, MemoryAccess *MA, + AnalyisLevel TagLevel) { + if (TagLevel == REFERENCE_LEVEL_ANALYSIS) + return tag(Relation, MA->getArrayId()); + + if (TagLevel == ACCESS_LEVEL_ANALYSIS) + return tag(Relation, MA->getId()); + + // No need to tag at the statement level. + return Relation; +} + /// @brief Collect information about the SCoP @p S. static void collectInfo(Scop &S, isl_union_map **Read, isl_union_map **Write, isl_union_map **MayWrite, @@ -116,7 +161,14 @@ Schedule, isl_map_reverse(isl_map_domain_map(isl_map_copy(accdom)))); accdom = isl_map_range_map(accdom); + *AccessSchedule = isl_union_map_add_map(*AccessSchedule, Schedule); + } else { + accdom = tag(accdom, MA, OptAnalysisLevel); + if (OptAnalysisLevel > STATEMENT_LEVEL_ANALYSIS) { + isl_map *Schedule = tag(Stmt.getSchedule(), MA, OptAnalysisLevel); + *StmtSchedule = isl_union_map_add_map(*StmtSchedule, Schedule); + } } if (MA->isRead()) @@ -124,7 +176,9 @@ else *Write = isl_union_map_add_map(*Write, accdom); } - *StmtSchedule = isl_union_map_add_map(*StmtSchedule, Stmt.getSchedule()); + + if (OptAnalysisLevel == STATEMENT_LEVEL_ANALYSIS) + *StmtSchedule = isl_union_map_add_map(*StmtSchedule, Stmt.getSchedule()); } *StmtSchedule = @@ -262,9 +316,22 @@ collectInfo(S, &Read, &Write, &MayWrite, &AccessSchedule, &StmtSchedule); + DEBUG(dbgs() << "Read: " << Read << '\n'; + dbgs() << "Write: " << Write << '\n'; + dbgs() << "MayWrite: " << MayWrite << '\n'; + dbgs() << "AccessSchedule: " << AccessSchedule << '\n'; + dbgs() << "StmtSchedule: " << StmtSchedule << '\n';); + if (isl_union_map_is_empty(AccessSchedule)) { isl_union_map_free(AccessSchedule); Schedule = S.getScheduleTree(); + // Tag the schedule tree if we want fine-grain dependence info + if (OptAnalysisLevel > STATEMENT_LEVEL_ANALYSIS) { + auto TaggedDom = isl_union_map_domain((isl_union_map_copy(StmtSchedule))); + auto TaggedMap = isl_union_set_unwrap(TaggedDom); + auto Tags = isl_union_map_domain_map_union_pw_multi_aff(TaggedMap); + Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags); + } } else { auto *ScheduleMap = isl_union_map_union(AccessSchedule, isl_union_map_copy(StmtSchedule)); @@ -290,7 +357,8 @@ DEBUG(dbgs() << "Read: " << Read << "\n"; dbgs() << "Write: " << Write << "\n"; - dbgs() << "MayWrite: " << MayWrite << "\n"); + dbgs() << "MayWrite: " << MayWrite << "\n"; + dbgs() << "Schedule: " << Schedule << "\n"); RAW = WAW = WAR = RED = nullptr; @@ -302,7 +370,10 @@ AI = isl_union_access_info_set_must_source(AI, isl_union_map_copy(Write)); AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(MayWrite)); AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule)); + Flow = isl_union_access_info_compute_flow(AI); + DEBUG(if (!Flow) dbgs() + << "last error: " << isl_ctx_last_error(IslCtx.get()) << '\n';); RAW = isl_union_flow_get_must_dependence(Flow); isl_union_flow_free(Flow); @@ -333,6 +404,8 @@ AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(Write)); AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule)); Flow = isl_union_access_info_compute_flow(AI); + DEBUG(if (!Flow) dbgs() + << "last error: " << isl_ctx_last_error(IslCtx.get()) << '\n';); RAW = isl_union_flow_get_may_dependence(Flow); isl_union_flow_free(Flow); Index: test/DependenceInfo/access_level_dep_simple_0.ll =================================================================== --- /dev/null +++ test/DependenceInfo/access_level_dep_simple_0.ll @@ -0,0 +1,63 @@ +; RUN: opt %loadPolly -polly-dependences -polly-dependences-analysis-type=value-based -polly-dependences-analysis-level=reference-level -analyze < %s | FileCheck %s +; +; CHECK: RAW dependences: +; CHECK-NEXT: [N] -> { [Stmt_for_body[i0] -> MemRef_a[]] -> [Stmt_for_body[4 + i0] -> MemRef_a[]] : 0 <= i0 <= -11 + N; [Stmt_for_body[i0] -> MemRef_b[]] -> [Stmt_for_body[6 + i0] -> MemRef_b[]] : 0 <= i0 <= -13 + N; Stmt_for_body[i0] -> Stmt_for_body[6 + i0] : 0 <= i0 <= -13 + N; Stmt_for_body[i0] -> Stmt_for_body[4 + i0] : 0 <= i0 <= -11 + N } +; CHECK-NEXT: WAR dependences: +; CHECK-NEXT: { } +; CHECK-NEXT: WAW dependences: +; CHECK-NEXT: { } +; CHECK-NEXT: Reduction dependences: +; CHECK-NEXT: { } +; +; void test(char a[], char b[], long N) { +; for (long i = 6; i < N; ++i) { +; a[i] = a[i - 4] + i; +; b[i] = b[i - 6] + i; +; } +; } + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define void @test(i8* %a, i8* %b, i64 %N) #0 { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %i.0 = phi i64 [ 6, %entry ], [ %inc, %for.inc ] + %cmp = icmp slt i64 %i.0, %N + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %sub = sub nsw i64 %i.0, 4 + %arrayidx = getelementptr inbounds i8, i8* %a, i64 %sub + %0 = load i8, i8* %arrayidx, align 1 + %conv = sext i8 %0 to i64 + %add = add nsw i64 %conv, %i.0 + %conv1 = trunc i64 %add to i8 + %arrayidx2 = getelementptr inbounds i8, i8* %a, i64 %i.0 + store i8 %conv1, i8* %arrayidx2, align 1 + %sub3 = sub nsw i64 %i.0, 6 + %arrayidx4 = getelementptr inbounds i8, i8* %b, i64 %sub3 + %1 = load i8, i8* %arrayidx4, align 1 + %conv5 = sext i8 %1 to i64 + %add6 = add nsw i64 %conv5, %i.0 + %conv7 = trunc i64 %add6 to i8 + %arrayidx8 = getelementptr inbounds i8, i8* %b, i64 %i.0 + store i8 %conv7, i8* %arrayidx8, align 1 + br label %for.inc + +for.inc: ; preds = %for.body + %inc = add nsw i64 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.ident = !{!0} + +!0 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git 3d5d4c39659f11dfbe8e11c857cadf5c449b559b) (http://llvm.org/git/llvm.git 801561e2bba12f2aa0285feb1105e110df443761)"} Index: test/DependenceInfo/reduction_complex_location.ll =================================================================== --- test/DependenceInfo/reduction_complex_location.ll +++ test/DependenceInfo/reduction_complex_location.ll @@ -1,4 +1,6 @@ ; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-dependences -polly-dependences-analysis-level=reference-level -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-dependences -polly-dependences-analysis-level=access-level -analyze < %s | FileCheck %s ; ; CHECK: RAW dependences: ; CHECK-NEXT: { } Index: test/DependenceInfo/reduction_multiple_loops_array_sum.ll =================================================================== --- test/DependenceInfo/reduction_multiple_loops_array_sum.ll +++ test/DependenceInfo/reduction_multiple_loops_array_sum.ll @@ -1,4 +1,6 @@ ; RUN: opt -basicaa %loadPolly -polly-dependences -analyze < %s | FileCheck %s +; RUN: opt -basicaa %loadPolly -polly-dependences -polly-dependences-analysis-level=reference-level -analyze < %s | FileCheck %s +; RUN: opt -basicaa %loadPolly -polly-dependences -polly-dependences-analysis-level=access-level -analyze < %s | FileCheck %s ; ; Verify that only the inner reduction like accesses cause reduction dependences ; Index: test/DependenceInfo/sequential_loops.ll =================================================================== --- test/DependenceInfo/sequential_loops.ll +++ test/DependenceInfo/sequential_loops.ll @@ -1,5 +1,6 @@ ; RUN: opt -S %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=value-based < %s | FileCheck %s -check-prefix=VALUE ; RUN: opt -S %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=memory-based < %s | FileCheck %s -check-prefix=MEMORY +; RUN: opt -S %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=value-based -polly-dependences-analysis-level=access-level < %s | FileCheck %s -check-prefix=VALUE_ACCESS ; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'sequential_writes': ; VALUE-NEXT: RAW dependences: @@ -9,6 +10,14 @@ ; VALUE-NEXT: WAW dependences: ; VALUE-NEXT: { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 } ; +;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'sequential_writes': +;VALUE_ACCESS-NEXT: RAW dependences: +;VALUE_ACCESS-NEXT: { } +;VALUE_ACCESS-NEXT: WAR dependences: +;VALUE_ACCESS-NEXT: { } +;VALUE_ACCESS-NEXT: WAW dependences: +;VALUE_ACCESS-NEXT: { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0_MemRef_A[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0_MemRef_A[]] : 10 <= i0 <= 99; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; [Stmt_S2[i0] -> Stmt_S2_Write0_MemRef_A[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0_MemRef_A[]] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0_MemRef_A[]] -> [Stmt_S2[i0] -> Stmt_S2_Write0_MemRef_A[]] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 } +; ; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'read_after_writes': ; VALUE-NEXT: RAW dependences: ; VALUE-NEXT: { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 } @@ -17,6 +26,14 @@ ; VALUE-NEXT: WAW dependences: ; VALUE-NEXT: { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9 } ; +;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'read_after_writes': +;VALUE_ACCESS-NEXT: RAW dependences: +;VALUE_ACCESS-NEXT: { [Stmt_S1[i0] -> Stmt_S1_Write0_MemRef_A[]] -> [Stmt_S3[i0] -> Stmt_S3_Read0_MemRef_A[]] : 10 <= i0 <= 99; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; [Stmt_S2[i0] -> Stmt_S2_Write0_MemRef_A[]] -> [Stmt_S3[i0] -> Stmt_S3_Read0_MemRef_A[]] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 } +;VALUE_ACCESS-NEXT: WAR dependences: +;VALUE_ACCESS-NEXT: { } +;VALUE_ACCESS-NEXT: WAW dependences: +;VALUE_ACCESS-NEXT: { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0_MemRef_A[]] -> [Stmt_S2[i0] -> Stmt_S2_Write0_MemRef_A[]] : 0 <= i0 <= 9 } +; ; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'write_after_read': ; VALUE-NEXT: RAW dependences: ; VALUE-NEXT: { } @@ -25,6 +42,14 @@ ; VALUE-NEXT: WAW dependences: ; VALUE-NEXT: { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9 } ; +;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'write_after_read': +;VALUE_ACCESS-NEXT: RAW dependences: +;VALUE_ACCESS-NEXT: { } +;VALUE_ACCESS-NEXT: WAR dependences: +;VALUE_ACCESS-NEXT: { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Read0_MemRef_A[]] -> [Stmt_S2[i0] -> Stmt_S2_Write0_MemRef_A[]] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Read0_MemRef_A[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0_MemRef_A[]] : 10 <= i0 <= 99; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 } +;VALUE_ACCESS-NEXT: WAW dependences: +;VALUE_ACCESS-NEXT: { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; [Stmt_S2[i0] -> Stmt_S2_Write0_MemRef_A[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0_MemRef_A[]] : 0 <= i0 <= 9 } +; ; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.2' in function 'parametric_offset': ; VALUE-NEXT: RAW dependences: ; VALUE-NEXT: [p] -> { Stmt_S1[i0] -> Stmt_S2[-p + i0] : i0 >= p and 0 <= i0 <= 99 and i0 <= 9 + p } @@ -32,6 +57,14 @@ ; VALUE-NEXT: [p] -> { } ; VALUE-NEXT: WAW dependences: ; VALUE-NEXT: [p] -> { } +; +;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.2' in function 'parametric_offset': +;VALUE_ACCESS-NEXT: RAW dependences: +;VALUE_ACCESS-NEXT: [p] -> { [Stmt_S1[i0] -> Stmt_S1_Write0_MemRef_A[]] -> [Stmt_S2[-p + i0] -> Stmt_S2_Read0_MemRef_A[]] : i0 >= p and 0 <= i0 <= 99 and i0 <= 9 + p; Stmt_S1[i0] -> Stmt_S2[-p + i0] : i0 >= p and 0 <= i0 <= 99 and i0 <= 9 + p } +;VALUE_ACCESS-NEXT: WAR dependences: +;VALUE_ACCESS-NEXT: [p] -> { } +;VALUE_ACCESS-NEXT: WAW dependences: +;VALUE_ACCESS-NEXT: [p] -> { } ; MEMORY-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'sequential_writes': ; MEMORY-NEXT: RAW dependences: