Open Wits15730 opened 6 months ago
Reproducing Example
run the program below with no optimization passes applied
define dso_local i64 @matmul(i32 noundef %dim, i64 %y, ptr nocapture noundef writeonly %c, ptr nocapture noundef readonly %a, ptr nocapture noundef readonly %b) local_unnamed_addr #0 {
entry:
; Define a constant vector with specific values
br label %vector.body
restart:
br label %vector.body
vector.body: ; preds = %vector.body, %vector.ph
%offset.idx = phi i64 [ 0, %entry ], [ %z, %restart ]
%vec.phi = phi <4 x i64> [ zeroinitializer, %entry ], [ %27, %restart ]
%16 = trunc i64 %offset.idx to i32
%17 = add i32 %16, 4
%19 = zext i32 %17 to i64
%20 = getelementptr inbounds i64, ptr %a, i64 %19
%21 = getelementptr inbounds i64, ptr %20, i32 0
%wide.load = load <4 x i64>, ptr %21, align 8
%22 = add i32 %17, %17
%23 = zext i32 %22 to i64
%24 = getelementptr inbounds i64, ptr %b, i64 %23
%25 = getelementptr inbounds i64, ptr %24, i32 0
%wide.load11 = load <4 x i64>, ptr %25, align 8
%26 = mul <4 x i64> %wide.load11, %wide.load
%27 = add <4 x i64> %26, %vec.phi
%z = add nuw i64 %offset.idx, 4
%28 = icmp eq i64 %z, %y
br i1 %28, label %for.end22, label %restart
for.end22:
%32 = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %27) ; preds = %for.end22.loopexit, %entry
ret i64 %32
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i64 @llvm.vector.reduce.add.v4i64(<4 x i64>) #4
저희 환경에서는 제공해주신 reproduction example에서 다른 오류가 발생하여서, 정확한 문제 지점을 파악하는 데 조금 시간이 걸리고 있습니다. 최대한 빠르게 파악 후 수정할 수 있도록 하겠습니다.
제공해주신 example을 컴파일하지 못하는 이유가 일차적으로는 다음과 같습니다.
zeroinitializer
로 생성되는 splat vector 같은 vector 상수를 백엔드에서 처리하지 못함@llvm.vector.reduce.add.v4i64
와 같은 LLVM 내장 intrinsic을 백엔드에서 처리하지 못함전자는 zeroinitializer
대신 call @vbcast_i64x4
같은 SWPP intrinsic을 사용하는 식으로 대체 가능하며, 후자는 LLVM 내장 intrinsic에 대한 지원 계획이 없으므로 별도로 유사한 동작을 재구현하셔야 합니다.
다만, vector 연산을 emit하는 과정에서 잘못된 casting으로 인한 크래시를 발견해 수정했습니다.
Vector operation을 사용한 .ll 코드를 컴파일 할 때 backend의 버그가 존재하는 듯합니다. 벡터 operation 을 사용하지 않으면 에러가 발생하지 않으나, 최적화를 통해 vector operation을 만들면 문제가 발생합니다.
최적화의 결과 사용하는 vector operation의 종류는 다음과 같습니다.
%sum.0 = phi <4 x i64> [ zeroinitializer, %for.body3 ], [ %add12, %for.inc ]
%vec_a = load <4 x i64>, ptr %arrayidx, align 8
%vec_mul = mul <4 x i64> %vec_a, %vec_b
%add12 = add <4 x i64> %sum.0, %vec_mul
%32 = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %30)
다음과 같은 에러가 발생하고 있습니다. static BinaryOperator llvm::BinaryOperator::Create(BinaryOps, Value , Value , const Twine &, Instruction ): Assertion `S1->getType() == S2->getType() && "Cannot create binary operator with two operands of differing type!"' failed.
제가 확인해 보지는 못하였으나, 아마도 PHI instruction을 사용하는 과정에서 register_allocate.cpp의
resolvePHIInterference
함수에서 문제가 발생하는 것이 아닐까 싶습니다.