Skip to content

Commit 667e1cb

Browse files
authored
Allow translation of global internal constants with private address space (#3351)
Global constants cannot be processed in SPIRV. This change enables the translation of global constants declared in the private address space into local variables within the functions where they are used.
1 parent 28fc4d6 commit 667e1cb

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

lib/SPIRV/SPIRVRegularizeLLVM.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,42 @@ void SPIRVRegularizeLLVMBase::cleanupConversionToNonStdIntegers(Module *M) {
421421
}
422422
}
423423

424+
void SPIRVRegularizeLLVMBase::replacePrivateConstGlobalsWithAllocas(Module *M) {
425+
SmallVector<GlobalVariable *> GlobalsToRemove;
426+
for (auto &GV : M->globals()) {
427+
428+
if (!GV.isConstant() || !GV.hasInternalLinkage() ||
429+
!(GV.getAddressSpace() == SPIRAS_Private) || !GV.hasInitializer() ||
430+
GV.getName().starts_with("llvm.compiler.used") ||
431+
GV.getName().starts_with("llvm.used"))
432+
continue;
433+
434+
SmallVector<User *> Users(GV.users());
435+
// TODO: Handle other llvm::User types, for example, constant expressions.
436+
if (llvm::any_of(Users, [](User *U) { return !isa<Instruction>(U); }))
437+
continue;
438+
439+
DenseMap<Function *, AllocaInst *> LocalCopies;
440+
for (User *U : Users) {
441+
Instruction *Inst = cast<Instruction>(U);
442+
Function *F = Inst->getFunction();
443+
AllocaInst *&AI = LocalCopies[F];
444+
if (!AI) {
445+
IRBuilder<> Builder(&*F->getEntryBlock().getFirstInsertionPt());
446+
AI = Builder.CreateAlloca(GV.getValueType(), nullptr, GV.getName());
447+
if (GV.getAlign())
448+
AI->setAlignment(GV.getAlign().value());
449+
Builder.CreateStore(GV.getInitializer(), AI);
450+
}
451+
Inst->replaceUsesOfWith(&GV, AI);
452+
}
453+
GlobalsToRemove.push_back(&GV);
454+
}
455+
456+
for (GlobalVariable *GV : GlobalsToRemove)
457+
GV->eraseFromParent();
458+
}
459+
424460
bool SPIRVRegularizeLLVMBase::runRegularizeLLVM(Module &Module) {
425461
M = &Module;
426462
Ctx = &M->getContext();
@@ -582,6 +618,7 @@ bool SPIRVRegularizeLLVMBase::regularize() {
582618
addKernelEntryPoint(M);
583619
expandSYCLTypeUsing(M);
584620
cleanupConversionToNonStdIntegers(M);
621+
replacePrivateConstGlobalsWithAllocas(M);
585622

586623
for (auto I = M->begin(), E = M->end(); I != E;) {
587624
Function *F = &(*I++);

lib/SPIRV/SPIRVRegularizeLLVM.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ class SPIRVRegularizeLLVMBase {
102102
// non-standard integer types.
103103
void cleanupConversionToNonStdIntegers(llvm::Module *M);
104104

105+
// Move internal constants in the private address space to function-scope
106+
// variables. Such globals would otherwise be translated with Function storage
107+
// class which is invalid for global variables in SPIR-V.
108+
void replacePrivateConstGlobalsWithAllocas(llvm::Module *M);
109+
105110
// According to the specification, the operands of a shift instruction must be
106111
// a scalar/vector of integer. When LLVM-IR contains a shift instruction with
107112
// i1 operands, they are treated as a bool. We need to extend them to i32 to
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv -s %t.bc -o %t.out.bc
3+
; RUN: llvm-dis < %t.out.bc | FileCheck %s
4+
5+
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"
6+
target triple = "spir64-unknown-unknown"
7+
8+
; check that all internal private globals are removed
9+
; CHECK-NOT: @g_var_1
10+
; CHECK-NOT: @g_var_2
11+
@g_var_1 = internal unnamed_addr constant [8 x i32] [i32 0, i32 1, i32 -2, i32 3, i32 4, i32 5, i32 6, i32 7]
12+
@g_var_2 = internal unnamed_addr constant [8 x i32] [i32 2, i32 1, i32 -2, i32 3, i32 4, i32 5, i32 6, i32 7]
13+
14+
; check that external global is not changed
15+
; CHECK: @g_var_e
16+
@g_var_e = external unnamed_addr constant [8 x i32]
17+
18+
; check that non constant global is not changed
19+
; CHECK: @g_var_nc = internal global i32 4
20+
@g_var_nc = internal global i32 4
21+
22+
; CHECK-LABEL: define spir_func i32 @foo(
23+
define spir_func i32 @foo(i32 %i) {
24+
; CHECK: [[alloca:%.*]] = alloca [8 x i32], align 4
25+
; CHECK: store [8 x i32] [i32 0, i32 1, i32 -2, i32 3, i32 4, i32 5, i32 6, i32 7], ptr [[alloca]], align 4
26+
; CHECK: [[p:%.*]] = getelementptr [8 x i32], ptr [[alloca]], i32 0, i32 %i
27+
%p_1 = getelementptr [8 x i32], ptr @g_var_1, i32 0, i32 %i
28+
%v = load i32, ptr %p_1, align 4
29+
30+
; CHECK: %p2 = getelementptr [8 x i32], ptr [[alloca]], i32 0, i32 %i
31+
%p2 = getelementptr [8 x i32], ptr @g_var_1, i32 0, i32 %i
32+
%v2 = load i32, ptr %p2, align 4
33+
%v3 = add i32 %v, %v2
34+
35+
ret i32 %v3
36+
}
37+
38+
; CHECK-LABEL: define spir_func i32 @bar
39+
define spir_func i32 @bar() {
40+
; CHECK: [[alloca:%.*]] = alloca [8 x i32], align 4
41+
; CHECK: store [8 x i32] [i32 2, i32 1, i32 -2, i32 3, i32 4, i32 5, i32 6, i32 7], ptr [[alloca]], align 4
42+
; CHECK: [[p:%.*]] = getelementptr [8 x i32], ptr [[alloca]], i32 0, i32 3
43+
%p_1 = getelementptr [8 x i32], ptr @g_var_2, i32 0, i32 3
44+
%v = load i32, ptr %p_1, align 4
45+
ret i32 %v
46+
}
47+
48+
; CHECK-LABEL: define spir_func i32 @foobar
49+
define spir_func i32 @foobar() {
50+
; CHECK: [[alloca_2:%.*]] = alloca [8 x i32], align 4
51+
; CHECK: store [8 x i32] [i32 2, i32 1, i32 -2, i32 3, i32 4, i32 5, i32 6, i32 7], ptr [[alloca_2]], align 4
52+
; CHECK: [[alloca_1:%.*]] = alloca [8 x i32], align 4
53+
; CHECK: store [8 x i32] [i32 0, i32 1, i32 -2, i32 3, i32 4, i32 5, i32 6, i32 7], ptr [[alloca_1]], align 4
54+
; CHECK: [[p_1:%.*]] = getelementptr [8 x i32], ptr [[alloca_1]], i32 0, i32 3
55+
%p_1 = getelementptr [8 x i32], ptr @g_var_1, i32 0, i32 3
56+
%v_1 = load i32, ptr %p_1, align 4
57+
58+
; CHECK: [[p_2:%.*]] = getelementptr [8 x i32], ptr [[alloca_2]], i32 0, i32 4
59+
%p_2 = getelementptr [8 x i32], ptr @g_var_2, i32 0, i32 4
60+
%v_2 = load i32, ptr %p_1, align 4
61+
%sum = add i32 %v_1, %v_2
62+
63+
ret i32 %sum
64+
}

0 commit comments

Comments
 (0)