Skip to content

Commit 4541a7f

Browse files
mlychkovbader
authored andcommitted
[SYCL] Insert addrspacecast for comparing operands
Pointers with the same address space in AST may end up in different address spaces in IR. We cannot CodeGen a binary compare operator (<, >, ==, etc.) whose operands have different address spaces, so we have to addrspacecast them to generic. Signed-off-by: Mikhail Lychkov <[email protected]>
1 parent e339962 commit 4541a7f

File tree

2 files changed

+80
-53
lines changed

2 files changed

+80
-53
lines changed

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,8 +1998,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
19981998
// in AST, but in IR one of them may be in opencl_private, and another in
19991999
// opencl_generic address space:
20002000
//
2001-
// int arr[5]; // automatic variable, default AS in AST, private AS in
2002-
// IR char* p = arr; // default AS in AST, generic AS in IR
2001+
// int arr[5]; // automatic variable, default AS in AST,
2002+
// // private AS in IR
2003+
//
2004+
// char* p = arr; // default AS in AST, generic AS in IR
20032005
//
20042006
if (E->getType().getAddressSpace() != DestTy.getAddressSpace())
20052007
llvm_unreachable("wrong cast for pointers in different address spaces"
@@ -2821,6 +2823,53 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
28212823
// Binary Operators
28222824
//===----------------------------------------------------------------------===//
28232825

2826+
static Value *insertAddressSpaceCast(Value *V, unsigned NewAS) {
2827+
auto *VTy = cast<llvm::PointerType>(V->getType());
2828+
if (VTy->getAddressSpace() == NewAS)
2829+
return V;
2830+
2831+
llvm::PointerType *VTyNewAS =
2832+
llvm::PointerType::get(VTy->getElementType(), NewAS);
2833+
2834+
if (auto *Constant = dyn_cast<llvm::Constant>(V))
2835+
return llvm::ConstantExpr::getAddrSpaceCast(Constant, VTyNewAS);
2836+
2837+
llvm::Instruction *NewV =
2838+
new llvm::AddrSpaceCastInst(V, VTyNewAS, V->getName() + ".ascast");
2839+
NewV->insertAfter(cast<llvm::Instruction>(V));
2840+
return NewV;
2841+
}
2842+
2843+
static void ensureSameAddrSpace(Value *&RHS, Value *&LHS,
2844+
bool CanInsertAddrspaceCast,
2845+
const LangOptions &Opts,
2846+
const ASTContext &Context) {
2847+
if (RHS->getType() == LHS->getType())
2848+
return;
2849+
2850+
auto *RHSTy = dyn_cast<llvm::PointerType>(RHS->getType());
2851+
auto *LHSTy = dyn_cast<llvm::PointerType>(LHS->getType());
2852+
if (!RHSTy || !LHSTy || RHSTy->getAddressSpace() == LHSTy->getAddressSpace())
2853+
return;
2854+
2855+
if (!CanInsertAddrspaceCast)
2856+
// Pointers have different address spaces and we cannot do anything with
2857+
// this.
2858+
llvm_unreachable("Pointers are expected to have the same address space.");
2859+
2860+
// Language rules define if it is legal to cast from one address space to
2861+
// another, and which address space we should use as a "common
2862+
// denominator". In SYCL, generic address space overlaps with all other
2863+
// address spaces.
2864+
if (Opts.SYCLIsDevice) {
2865+
unsigned GenericAS = Context.getTargetAddressSpace(LangAS::opencl_generic);
2866+
RHS = insertAddressSpaceCast(RHS, GenericAS);
2867+
LHS = insertAddressSpaceCast(LHS, GenericAS);
2868+
} else
2869+
llvm_unreachable("Unable to find a common address space for "
2870+
"two pointers.");
2871+
}
2872+
28242873
BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
28252874
TestAndClearIgnoreResultAssign();
28262875
BinOpInfo Result;
@@ -3855,6 +3904,14 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
38553904
RHS = Builder.CreateStripInvariantGroup(RHS);
38563905
}
38573906

3907+
// Expression operands may have the same addrspace in AST, but different
3908+
// addrspaces in LLVM IR, in which case an addrspacecast should be valid.
3909+
bool CanInsertAddrspaceCast =
3910+
LHSTy.getAddressSpace() == RHSTy.getAddressSpace();
3911+
3912+
ensureSameAddrSpace(RHS, LHS, CanInsertAddrspaceCast, CGF.getLangOpts(),
3913+
CGF.getContext());
3914+
38583915
Result = Builder.CreateICmp(UICmpOpc, LHS, RHS, "cmp");
38593916
}
38603917

@@ -4160,53 +4217,6 @@ static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
41604217
// exist in the source-level program.
41614218
}
41624219

4163-
static Value *insertAddressSpaceCast(Value *V, unsigned NewAS) {
4164-
auto *VTy = cast<llvm::PointerType>(V->getType());
4165-
if (VTy->getAddressSpace() == NewAS)
4166-
return V;
4167-
4168-
llvm::PointerType *VTyNewAS =
4169-
llvm::PointerType::get(VTy->getElementType(), NewAS);
4170-
4171-
if (auto *Constant = dyn_cast<llvm::Constant>(V))
4172-
return llvm::ConstantExpr::getAddrSpaceCast(Constant, VTyNewAS);
4173-
4174-
llvm::Instruction *NewV =
4175-
new llvm::AddrSpaceCastInst(V, VTyNewAS, V->getName() + ".ascast");
4176-
NewV->insertAfter(cast<llvm::Instruction>(V));
4177-
return NewV;
4178-
}
4179-
4180-
static void ensureSameAddrSpace(Value *&RHS, Value *&LHS,
4181-
bool CanInsertAddrspaceCast,
4182-
const LangOptions &Opts,
4183-
const ASTContext &Context) {
4184-
if (RHS->getType() == LHS->getType())
4185-
return;
4186-
4187-
auto *RHSTy = dyn_cast<llvm::PointerType>(RHS->getType());
4188-
auto *LHSTy = dyn_cast<llvm::PointerType>(LHS->getType());
4189-
if (!RHSTy || !LHSTy || RHSTy->getAddressSpace() == LHSTy->getAddressSpace())
4190-
return;
4191-
4192-
if (!CanInsertAddrspaceCast)
4193-
// Pointers have different address spaces and we cannot do anything with
4194-
// this.
4195-
llvm_unreachable("Pointers are expected to have the same address space.");
4196-
4197-
// Language rules define if it is legal to cast from one address space to
4198-
// another, and which address space we should use as a "common
4199-
// denominator". In SYCL, generic address space overlaps with all other
4200-
// address spaces.
4201-
if (Opts.SYCLIsDevice) {
4202-
unsigned GenericAS = Context.getTargetAddressSpace(LangAS::opencl_generic);
4203-
RHS = insertAddressSpaceCast(RHS, GenericAS);
4204-
LHS = insertAddressSpaceCast(LHS, GenericAS);
4205-
} else
4206-
llvm_unreachable("Unable to find a common address space for "
4207-
"two pointers.");
4208-
}
4209-
42104220
Value *ScalarExprEmitter::
42114221
VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
42124222
TestAndClearIgnoreResultAssign();

clang/test/CodeGenSYCL/address-space-new.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,27 @@ void test() {
3434

3535
// CHECK: @[[STR:[.a-zA-Z0-9_]+]] = private unnamed_addr constant [14 x i8] c"Hello, world!\00", align 1
3636

37+
// CHECK-NEW: %i.ascast = addrspacecast i32* %i to i32 addrspace(4)*
3738
// CHECK: %[[ARR:[a-zA-Z0-9]+]] = alloca [42 x i32]
3839

3940
int i = 0;
4041
int *pptr = &i;
4142
// CHECK-LEGACY: store i32* %i, i32** %pptr
4243
// CHECK-NEW: %[[GEN:[0-9]+]] = addrspacecast i32* %i to i32 addrspace(4)*
4344
// CHECK-NEW: store i32 addrspace(4)* %[[GEN]], i32 addrspace(4)** %pptr
45+
bool is_i_ptr = (pptr == &i);
46+
// CHECK-LEGACY: %[[VALPPTR:[0-9]+]] = load i32*, i32** %pptr
47+
// CHECK-LEGACY: %cmp{{[0-9]*}} = icmp eq i32* %[[VALPPTR]], %i
48+
// CHECK-NEW: %[[VALPPTR:[0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** %pptr
49+
// CHECK-NEW: %cmp{{[0-9]*}} = icmp eq i32 addrspace(4)* %[[VALPPTR]], %i.ascast
4450
*pptr = foo;
4551

4652
int var23 = 23;
4753
char *cp = (char *)&var23;
4854
*cp = 41;
4955
// CHECK: store i32 23, i32* %[[VAR:[a-zA-Z0-9]+]]
50-
// CHECK-OLD: [[VARCAST:[a-zA-Z0-9]+]] = bitcast i32* %[[VAR]] to i8*
51-
// CHECK-OLD: store i8* %[[VARCAST]], i8** %{{.*}}
56+
// CHECK-LEGACY: [[VARCAST:[a-zA-Z0-9]+]] = bitcast i32* %[[VAR]] to i8*
57+
// CHECK-LEGACY: store i8* %[[VARCAST]], i8** %{{.*}}
5258
// CHECK-NEW: [[VARAS:[a-zA-Z0-9]+]] = addrspacecast i32* %[[VAR]] to i32 addrspace(4)*
5359
// CHECK-NEW: [[VARCAST:[a-zA-Z0-9]+]] = bitcast i32 addrspace(4)* %[[VARAS]] to i8 addrspace(4)*
5460
// CHECK-NEW: store i8 addrspace(4)* %[[VARCAST]], i8 addrspace(4)** %{{.*}}
@@ -57,12 +63,23 @@ void test() {
5763
char *cpp = (char *)arr;
5864
*cpp = 43;
5965
// CHECK: %[[ARRDECAY:[a-zA-Z0-9]+]] = getelementptr inbounds [42 x i32], [42 x i32]* %[[ARR]], i64 0, i64 0
60-
// CHECK-OLD: [[ARRCAST:[a-zA-Z0-9]+]] = bitcast i32* %[[ARRDECAY]] to i8*
61-
// CHECK-OLD: store i8* %[[ARRCAST]], i8** %{{.*}}
66+
// CHECK-LEGACY: [[ARRCAST:[a-zA-Z0-9]+]] = bitcast i32* %[[ARRDECAY]] to i8*
67+
// CHECK-LEGACY: store i8* %[[ARRCAST]], i8** %{{.*}}
6268
// CHECK-NEW: %[[ARRAS:[a-zA-Z0-9]+]] = addrspacecast i32* %[[ARRDECAY]] to i32 addrspace(4)*
6369
// CHECK-NEW: %[[ARRCAST:[a-zA-Z0-9]+]] = bitcast i32 addrspace(4)* %[[ARRAS]] to i8 addrspace(4)*
6470
// CHECK-NEW: store i8 addrspace(4)* %[[ARRCAST]], i8 addrspace(4)** %{{.*}}
6571

72+
int *aptr = arr + 10;
73+
if (aptr < arr + sizeof(arr))
74+
*aptr = 44;
75+
// CHECK-LEGACY: %[[VALAPTR:[0-9]+]] = load i32*, i32** %aptr
76+
// CHECK-NEW: %[[VALAPTR:[0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** %aptr
77+
// CHECK: %[[ARRDCY2:[a-zA-Z0-9]+]] = getelementptr inbounds [42 x i32], [42 x i32]* %[[ARR]], i64 0, i64 0
78+
// CHECK: %[[ADDPTR:[a-zA-Z0-9.]+]] = getelementptr inbounds i32, i32* %[[ARRDCY2]], i64 168
79+
// CHECK-LEGACY: %cmp{{[0-9]+}} = icmp ult i32* %[[VALAPTR]], %[[ADDPTR]]
80+
// CHECK-NEW: %[[ADDPTRCAST:[a-zA-Z0-9.]+]] = addrspacecast i32* %[[ADDPTR]] to i32 addrspace(4)*
81+
// CHECK-NEW: %cmp{{[0-9]+}} = icmp ult i32 addrspace(4)* %[[VALAPTR]], %[[ADDPTRCAST]]
82+
6683
const char *str = "Hello, world!";
6784
// CHECK-LEGACY: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @[[STR]], i64 0, i64 0), i8** %[[STRVAL:[a-zA-Z0-9]+]], align 8
6885
// CHECK-NEW: store i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([14 x i8], [14 x i8]* @[[STR]], i64 0, i64 0) to i8 addrspace(4)*), i8 addrspace(4)** %[[STRVAL:[a-zA-Z0-9]+]], align 8

0 commit comments

Comments
 (0)