Skip to content

Commit d3bc86b

Browse files
Fznamznonvmaksimo
authored andcommitted
Fix handling of complex constant expressions
When some constant expression is used as operand of regular instruction and operand of other constant expression, the current algorithm of lowering could produce incorrect order of instructions because it is not possible to add instruction operand to a constant expression. Consider following pseudo code example: ``` call foo(constexpr2(constexpr1), constexpr1) // After first loop iteration through operands of the call instruction: A = constexpr2op(constexpr1) call foo(A, constexpr1) // Ok, instruction A is now a user of constexpr1, so, when second // operand is processed, all uses of constexpr1 are updated, but the // instruction that represents constexpr1 is inserted before call // instruction because it is now being processed, so it will look like // this: A = constexpr2(B) B = constexpr1 call foo(A, B) // So, instruction B needs to be moved after all its users to get a // valid module: B = constexpr1 A = constexpr2(B) call foo(A, B) ``` Original commit: KhronosGroup/SPIRV-LLVM-Translator@390aba9
1 parent 96004a5 commit d3bc86b

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

llvm-spirv/lib/SPIRV/SPIRVLowerConstExpr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,12 @@ void SPIRVLowerConstExprBase::visit(Module *M) {
157157
Users.push_back(InstUser);
158158
}
159159
}
160-
for (auto &User : Users)
160+
for (auto &User : Users) {
161+
if (ReplInst->getParent() == User->getParent())
162+
if (User->comesBefore(ReplInst))
163+
ReplInst->moveBefore(User);
161164
User->replaceUsesOfWith(CE, ReplInst);
165+
}
162166
return ReplInst;
163167
};
164168

llvm-spirv/test/complex-constexpr.ll

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -o %t.spv
3+
; RUN: llvm-spirv %t.spv -o %t.spt --to-text
4+
; RUN: llvm-spirv -r %t.spv -o %t.bc
5+
; RUN: llvm-dis %t.bc -o %t.ll
6+
; RUN: FileCheck %s --input-file %t.spt -check-prefix=CHECK-SPIRV
7+
; RUN: FileCheck %s --input-file %t.ll -check-prefix=CHECK-LLVM
8+
; RUN: spirv-val %t.spv
9+
10+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
11+
target triple = "spir64"
12+
13+
@.str.1 = private unnamed_addr addrspace(1) constant [1 x i8] zeroinitializer, align 1
14+
15+
define linkonce_odr hidden spir_func void @foo() {
16+
entry:
17+
; CHECK-SPIRV: PtrCastToGeneric {{[0-9]+}} [[Cast:[0-9]+]]
18+
; CHECK-SPIRV: InBoundsPtrAccessChain {{[0-9]+}} [[Gep:[0-9]+]] [[Cast]]
19+
; CHECK-SPIRV: InBoundsPtrAccessChain {{[0-9]+}} [[Gep1:[0-9]+]] [[Cast]]
20+
; CHECK-SPIRV: ConvertPtrToU {{[0-9]+}} [[PtrToU1:[0-9]+]] [[Gep1]]
21+
; CHECK-SPIRV: ConvertPtrToU {{[0-9]+}} [[PtrToU2:[0-9]+]]
22+
; CHECK-SPIRV: IEqual {{[0-9]+}} [[IEq:[0-9]+]] [[PtrToU1]] [[PtrToU2]]
23+
; CHECK-SPIRV: ConvertUToPtr {{[0-9]+}} [[UToPtr:[0-9]+]]
24+
; CHECK-SPIRV: Select {{[0-9]+}} [[Sel:[0-9]+]] [[IEq]] [[UToPtr]] [[Gep1]]
25+
; CHECK-SPIRV: FunctionCall 9 31 28 [[Gep]] [[Sel]]
26+
; CHECK-LLVM: %[[Cast:[0-9]+]] = addrspacecast [1 x i8] addrspace(1)* @.str.1 to [1 x i8] addrspace(4)*
27+
; CHECK-LLVM: %[[Gep:[0-9]+]] = getelementptr inbounds [1 x i8], [1 x i8] addrspace(4)* %0, i64 0, i64 0
28+
; CHECK-LLVM: %[[Gep1:[0-9]+]] = getelementptr inbounds [1 x i8], [1 x i8] addrspace(4)* %0, i64 0, i64 0
29+
; CHECK-LLVM: %[[PtrToU1:[0-9]+]] = ptrtoint i8 addrspace(4)* %[[Gep1]] to i64
30+
; CHECK-LLVM: %[[PtrToU2:[0-9]+]] = ptrtoint i8 addrspace(4)* null to i64
31+
; CHECK-LLVM: %[[IEq:[0-9]+]] = icmp eq i64 %[[PtrToU1]], %[[PtrToU2]]
32+
; CHECK-LLVM: %[[UToPtr:[0-9]+]] = inttoptr i64 -1 to i8 addrspace(4)*
33+
; CHECK-LLVM: %[[Sel:[0-9]+]] = select i1 %[[IEq]], i8 addrspace(4)* %[[UToPtr]], i8 addrspace(4)* %[[Gep1]]
34+
; CHECK-LLVM: call spir_func void @bar(i8 addrspace(4)* %[[Gep]], i8 addrspace(4)* %[[Sel]]) #0
35+
call spir_func void @bar(i8 addrspace(4)* getelementptr inbounds ([1 x i8], [1 x i8] addrspace(4)* addrspacecast ([1 x i8] addrspace(1)* @.str.1 to [1 x i8] addrspace(4)*), i64 0, i64 0), i8 addrspace(4)* select (i1 icmp eq (i8 addrspace(4)* getelementptr inbounds ([1 x i8], [1 x i8] addrspace(4)* addrspacecast ([1 x i8] addrspace(1)* @.str.1 to [1 x i8] addrspace(4)*), i64 0, i64 0), i8 addrspace(4)* null), i8 addrspace(4)* inttoptr (i64 -1 to i8 addrspace(4)*), i8 addrspace(4)* getelementptr inbounds ([1 x i8], [1 x i8] addrspace(4)* addrspacecast ([1 x i8] addrspace(1)* @.str.1 to [1 x i8] addrspace(4)*), i64 0, i64 0)))
36+
ret void
37+
}
38+
39+
define linkonce_odr hidden spir_func void @bar(i8 addrspace(4)* %__beg, i8 addrspace(4)* %__end) {
40+
entry:
41+
ret void
42+
}
43+

0 commit comments

Comments
 (0)