Skip to content

Commit 3a8c295

Browse files
authored
Merge branch 'main' into cuf_saturatef
2 parents ff3823d + a629119 commit 3a8c295

File tree

52 files changed

+2511
-504
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2511
-504
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,10 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
214214

215215
/// Get constant address of a global variable as an MLIR attribute.
216216
cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type,
217-
cir::GlobalOp globalOp) {
217+
cir::GlobalOp globalOp,
218+
mlir::ArrayAttr indices = {}) {
218219
auto symbol = mlir::FlatSymbolRefAttr::get(globalOp.getSymNameAttr());
219-
return cir::GlobalViewAttr::get(type, symbol);
220+
return cir::GlobalViewAttr::get(type, symbol, indices);
220221
}
221222

222223
mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global) {

clang/include/clang/CIR/Dialect/IR/CIRAttrs.td

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,20 @@ def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
379379
]> {
380380
let summary = "Provides constant access to a global address";
381381
let description = [{
382-
Get constant address of global `symbol`. It provides a way to access globals
383-
from other global and always produces a pointer.
382+
Get constant address of global `symbol` and optionally apply offsets to
383+
access existing subelements. It provides a way to access globals from other
384+
global and always produces a pointer.
384385

385386
The type of the input symbol can be different from `#cir.global_view`
386387
output type, since a given view of the global might require a static
387388
cast for initializing other globals.
388389

390+
A list of indices can be optionally passed and each element subsequently
391+
indexes underlying types. For `symbol` types like `!cir.array`
392+
and `!cir.record`, it leads to the constant address of sub-elements, while
393+
for `!cir.ptr`, an offset is applied. The first index is relative to the
394+
original symbol type, not the produced one.
395+
389396
The result type of this attribute may be an integer type. In such a case,
390397
the pointer to the referenced global is casted to an integer and this
391398
attribute represents the casted result.
@@ -396,23 +403,57 @@ def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
396403
cir.global external @s = @".str2": !cir.ptr<i8>
397404
cir.global external @x = #cir.global_view<@s> : !cir.ptr<i8>
398405
cir.global external @s_addr = #cir.global_view<@s> : !s64i
406+
407+
cir.global external @rgb = #cir.const_array<[0 : i8, -23 : i8, 33 : i8]
408+
: !cir.array<i8 x 3>>
409+
cir.global external @elt_ptr = #cir.global_view<@rgb, [1]> : !cir.ptr<i8>
410+
```
411+
412+
Note, that unlike LLVM IR's gep instruction, CIR doesn't add the leading
413+
zero index when it's known to be constant zero, e.g. for pointers, i.e. we
414+
use indexes exactly to access sub elements or for the offset. The leading
415+
zero index is added later in the lowering.
416+
417+
Example:
418+
```
419+
struct A {
420+
int a;
421+
};
422+
423+
struct B: virtual A {
424+
int b;
425+
};
426+
```
427+
VTT for B in CIR:
428+
```
429+
cir.global linkonce_odr @_ZTT1B = #cir.const_array<[
430+
#cir.global_view<@_ZTV1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>]>
431+
: !cir.array<!cir.ptr<!u8i> x 1>
432+
```
433+
VTT for B in LLVM IR:
434+
```
435+
@_ZTT1B = linkonce_odr global [1 x ptr] [ptr getelementptr inbounds
436+
({ [3 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3)], align 8
399437
```
400438
}];
401439

402440
let parameters = (ins AttributeSelfTypeParameter<"">:$type,
403-
"mlir::FlatSymbolRefAttr":$symbol);
441+
"mlir::FlatSymbolRefAttr":$symbol,
442+
OptionalParameter<"mlir::ArrayAttr">:$indices);
404443

405444
let builders = [
406445
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
407-
"mlir::FlatSymbolRefAttr":$symbol), [{
408-
return $_get(type.getContext(), type, symbol);
446+
"mlir::FlatSymbolRefAttr":$symbol,
447+
CArg<"mlir::ArrayAttr", "{}">:$indices), [{
448+
return $_get(type.getContext(), type, symbol, indices);
409449
}]>
410450
];
411451

412452
// let genVerifyDecl = 1;
413453
let assemblyFormat = [{
414454
`<`
415455
$symbol
456+
(`,` $indices^)?
416457
`>`
417458
}];
418459
}

clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ class CIRDataLayout {
3535

3636
bool isBigEndian() const { return bigEndian; }
3737

38+
/// Internal helper method that returns requested alignment for type.
39+
llvm::Align getAlignment(mlir::Type ty, bool abiOrPref) const;
40+
41+
llvm::Align getABITypeAlign(mlir::Type ty) const {
42+
return getAlignment(ty, true);
43+
}
44+
3845
/// Returns the maximum number of bytes that may be overwritten by
3946
/// storing the specified type.
4047
///
@@ -48,6 +55,19 @@ class CIRDataLayout {
4855
baseSize.isScalable()};
4956
}
5057

58+
/// Returns the offset in bytes between successive objects of the
59+
/// specified type, including alignment padding.
60+
///
61+
/// If Ty is a scalable vector type, the scalable property will be set and
62+
/// the runtime size will be a positive integer multiple of the base size.
63+
///
64+
/// This is the amount that alloca reserves for this type. For example,
65+
/// returns 12 or 16 for x86_fp80, depending on alignment.
66+
llvm::TypeSize getTypeAllocSize(mlir::Type ty) const {
67+
// Round up to the next alignment boundary.
68+
return llvm::alignTo(getTypeStoreSize(ty), getABITypeAlign(ty).value());
69+
}
70+
5171
llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const;
5272
};
5373

clang/lib/CIR/CodeGen/CIRGenBuilder.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "CIRGenBuilder.h"
10+
#include "llvm/ADT/TypeSwitch.h"
1011

1112
using namespace clang::CIRGen;
1213

@@ -66,6 +67,69 @@ clang::CIRGen::CIRGenBuilderTy::getConstFP(mlir::Location loc, mlir::Type t,
6667
return create<cir::ConstantOp>(loc, cir::FPAttr::get(t, fpVal));
6768
}
6869

70+
void CIRGenBuilderTy::computeGlobalViewIndicesFromFlatOffset(
71+
int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
72+
llvm::SmallVectorImpl<int64_t> &indices) {
73+
if (!offset)
74+
return;
75+
76+
auto getIndexAndNewOffset =
77+
[](int64_t offset, int64_t eltSize) -> std::pair<int64_t, int64_t> {
78+
int64_t divRet = offset / eltSize;
79+
if (divRet < 0)
80+
divRet -= 1; // make sure offset is positive
81+
int64_t modRet = offset - (divRet * eltSize);
82+
return {divRet, modRet};
83+
};
84+
85+
mlir::Type subType =
86+
llvm::TypeSwitch<mlir::Type, mlir::Type>(ty)
87+
.Case<cir::ArrayType>([&](auto arrayTy) {
88+
int64_t eltSize = layout.getTypeAllocSize(arrayTy.getElementType());
89+
const auto [index, newOffset] =
90+
getIndexAndNewOffset(offset, eltSize);
91+
indices.push_back(index);
92+
offset = newOffset;
93+
return arrayTy.getElementType();
94+
})
95+
.Case<cir::RecordType>([&](auto recordTy) {
96+
ArrayRef<mlir::Type> elts = recordTy.getMembers();
97+
int64_t pos = 0;
98+
for (size_t i = 0; i < elts.size(); ++i) {
99+
int64_t eltSize =
100+
(int64_t)layout.getTypeAllocSize(elts[i]).getFixedValue();
101+
unsigned alignMask = layout.getABITypeAlign(elts[i]).value() - 1;
102+
if (recordTy.getPacked())
103+
alignMask = 0;
104+
// Union's fields have the same offset, so no need to change pos
105+
// here, we just need to find eltSize that is greater then the
106+
// required offset. The same is true for the similar union type
107+
// check below
108+
if (!recordTy.isUnion())
109+
pos = (pos + alignMask) & ~alignMask;
110+
assert(offset >= 0);
111+
if (offset < pos + eltSize) {
112+
indices.push_back(i);
113+
offset -= pos;
114+
return elts[i];
115+
}
116+
// No need to update pos here, see the comment above.
117+
if (!recordTy.isUnion())
118+
pos += eltSize;
119+
}
120+
llvm_unreachable("offset was not found within the record");
121+
})
122+
.Default([](mlir::Type otherTy) {
123+
llvm_unreachable("unexpected type");
124+
return otherTy; // Even though this is unreachable, we need to
125+
// return a type to satisfy the return type of the
126+
// lambda.
127+
});
128+
129+
assert(subType);
130+
computeGlobalViewIndicesFromFlatOffset(offset, subType, layout, indices);
131+
}
132+
69133
// This can't be defined in Address.h because that file is included by
70134
// CIRGenBuilder.h
71135
Address Address::withElementType(CIRGenBuilderTy &builder,

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Address.h"
1313
#include "CIRGenRecordLayout.h"
1414
#include "CIRGenTypeCache.h"
15+
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
1516
#include "clang/CIR/Interfaces/CIRTypeInterfaces.h"
1617
#include "clang/CIR/MissingFeatures.h"
1718

@@ -401,6 +402,14 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
401402
mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,
402403
mlir::Type eltTy);
403404

405+
// Convert byte offset to sequence of high-level indices suitable for
406+
// GlobalViewAttr. Ideally we shouldn't deal with low-level offsets at all
407+
// but currently some parts of Clang AST, which we don't want to touch just
408+
// yet, return them.
409+
void computeGlobalViewIndicesFromFlatOffset(
410+
int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
411+
llvm::SmallVectorImpl<int64_t> &indices);
412+
404413
/// Creates a versioned global variable. If the symbol is already taken, an ID
405414
/// will be appended to the symbol. The returned global must always be queried
406415
/// for its name so it can be referenced correctly.

clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -388,22 +388,32 @@ class ConstantLValueEmitter
388388
/// Return GEP-like value offset
389389
mlir::ArrayAttr getOffset(mlir::Type ty) {
390390
int64_t offset = value.getLValueOffset().getQuantity();
391-
if (offset == 0)
392-
return {};
391+
cir::CIRDataLayout layout(cgm.getModule());
392+
SmallVector<int64_t, 3> idxVec;
393+
cgm.getBuilder().computeGlobalViewIndicesFromFlatOffset(offset, ty, layout,
394+
idxVec);
395+
396+
llvm::SmallVector<mlir::Attribute, 3> indices;
397+
for (int64_t i : idxVec) {
398+
mlir::IntegerAttr intAttr = cgm.getBuilder().getI32IntegerAttr(i);
399+
indices.push_back(intAttr);
400+
}
393401

394-
cgm.errorNYI("ConstantLValueEmitter: global view with offset");
395-
return {};
402+
if (indices.empty())
403+
return {};
404+
return cgm.getBuilder().getArrayAttr(indices);
396405
}
397406

398407
/// Apply the value offset to the given constant.
399408
ConstantLValue applyOffset(ConstantLValue &c) {
400409
// Handle attribute constant LValues.
401410
if (auto attr = mlir::dyn_cast<mlir::Attribute>(c.value)) {
402411
if (auto gv = mlir::dyn_cast<cir::GlobalViewAttr>(attr)) {
403-
if (value.getLValueOffset().getQuantity() == 0)
404-
return gv;
405-
cgm.errorNYI("ConstantLValue: global view with offset");
406-
return {};
412+
auto baseTy = mlir::cast<cir::PointerType>(gv.getType()).getPointee();
413+
mlir::Type destTy = cgm.getTypes().convertTypeForMem(destType);
414+
assert(!gv.getIndices() && "Global view is already indexed");
415+
return cir::GlobalViewAttr::get(destTy, gv.getSymbol(),
416+
getOffset(baseTy));
407417
}
408418
llvm_unreachable("Unsupported attribute type to offset");
409419
}

clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,30 @@ void CIRDataLayout::reset(mlir::DataLayoutSpecInterface spec) {
2323
}
2424
}
2525

26+
llvm::Align CIRDataLayout::getAlignment(mlir::Type ty, bool useABIAlign) const {
27+
if (auto recTy = llvm::dyn_cast<cir::RecordType>(ty)) {
28+
// Packed record types always have an ABI alignment of one.
29+
if (recTy && recTy.getPacked() && useABIAlign)
30+
return llvm::Align(1);
31+
32+
// Get the layout annotation... which is lazily created on demand.
33+
llvm_unreachable("getAlignment()) for record type is not implemented");
34+
}
35+
36+
// FIXME(cir): This does not account for differnt address spaces, and relies
37+
// on CIR's data layout to give the proper alignment.
38+
assert(!cir::MissingFeatures::addressSpace());
39+
40+
// Fetch type alignment from MLIR's data layout.
41+
unsigned align = useABIAlign ? layout.getTypeABIAlignment(ty)
42+
: layout.getTypePreferredAlignment(ty);
43+
return llvm::Align(align);
44+
}
45+
2646
// The implementation of this method is provided inline as it is particularly
2747
// well suited to constant folding when called on a specific Type subclass.
2848
llvm::TypeSize CIRDataLayout::getTypeSizeInBits(mlir::Type ty) const {
29-
assert(!cir::MissingFeatures::dataLayoutTypeIsSized());
49+
assert(cir::isSized(ty) && "Cannot getTypeInfo() on a type that is unsized!");
3050

3151
if (auto recordTy = llvm::dyn_cast<cir::RecordType>(ty)) {
3252
// FIXME(cir): CIR record's data layout implementation doesn't do a good job
@@ -38,5 +58,6 @@ llvm::TypeSize CIRDataLayout::getTypeSizeInBits(mlir::Type ty) const {
3858
// on CIR's data layout to give the proper ABI-specific type width.
3959
assert(!cir::MissingFeatures::addressSpace());
4060

61+
// This is calling mlir::DataLayout::getTypeSizeInBits().
4162
return llvm::TypeSize::getFixed(layout.getTypeSizeInBits(ty));
4263
}

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,22 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) {
426426
mlir::Value addrOp = rewriter.create<mlir::LLVM::AddressOfOp>(
427427
loc, mlir::LLVM::LLVMPointerType::get(rewriter.getContext()), symName);
428428

429-
assert(!cir::MissingFeatures::globalViewIndices());
429+
if (globalAttr.getIndices()) {
430+
llvm::SmallVector<mlir::LLVM::GEPArg> indices;
431+
432+
if (mlir::isa<mlir::LLVM::LLVMArrayType, mlir::LLVM::LLVMStructType>(
433+
sourceType))
434+
indices.push_back(0);
435+
436+
for (mlir::Attribute idx : globalAttr.getIndices()) {
437+
auto intAttr = mlir::cast<mlir::IntegerAttr>(idx);
438+
indices.push_back(intAttr.getValue().getSExtValue());
439+
}
440+
mlir::Type resTy = addrOp.getType();
441+
mlir::Type eltTy = converter->convertType(sourceType);
442+
addrOp = rewriter.create<mlir::LLVM::GEPOp>(
443+
loc, resTy, eltTy, addrOp, indices, mlir::LLVM::GEPNoWrapFlags::none);
444+
}
430445

431446
// The incubator has handling here for the attribute having integer type, but
432447
// the only test case I could find that reaches it is a direct CIR-to-LLVM IR

clang/test/CIR/CodeGen/globals.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
33
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
44
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
57

68
// Should constant initialize global with constant address.
79
int var = 1;
@@ -11,10 +13,25 @@ int *constAddr = &var;
1113

1214
// LLVM: @constAddr = global ptr @var, align 8
1315

16+
// OGCG: @constAddr = global ptr @var, align 8
17+
1418
// Should constant initialize global with constant address.
1519
int f();
1620
int (*constFnAddr)() = f;
1721

1822
// CIR: cir.global external @constFnAddr = #cir.global_view<@_Z1fv> : !cir.ptr<!cir.func<() -> !s32i>>
1923

2024
// LLVM: @constFnAddr = global ptr @_Z1fv, align 8
25+
26+
// OGCG: @constFnAddr = global ptr @_Z1fv, align 8
27+
28+
int arr[4][16];
29+
int *constArrAddr = &arr[2][1];
30+
31+
// CIR: cir.global external @constArrAddr = #cir.global_view<@arr, [2 : i32, 1 : i32]> : !cir.ptr<!s32i>
32+
33+
// The 'inbounds' and 'nuw' flags are inferred by LLVM's constant folder. The
34+
// same flags show up at -O1 in OGCG.
35+
// LLVM: @constArrAddr = global ptr getelementptr inbounds nuw (i8, ptr @arr, i64 132), align 8
36+
37+
// OGCG: @constArrAddr = global ptr getelementptr (i8, ptr @arr, i64 132), align 8

clang/test/CodeGenHIP/hip-cumode.hip

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@
55
// RUN: %clang -S -o - --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib -mcumode \
66
// RUN: %s 2>&1 | FileCheck --check-prefix=NOWGP %s
77
// RUN: %clang -S -o - --offload-arch=gfx906 --cuda-device-only -nogpuinc -nogpulib -mno-cumode \
8-
// RUN: %s 2>&1 | FileCheck --check-prefixes=NOWGP,WARN-CUMODE %s
8+
// RUN: %s 2>&1 | FileCheck -DOFFLOAD_ARCH=gfx906 --check-prefixes=NOWGP,WARN-CUMODE %s
99
// RUN: %clang -S -o - --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib \
1010
// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s
1111
// RUN: %clang -S -o - --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib -mcumode \
1212
// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-ON %s
1313
// RUN: %clang -S -o - --offload-arch=gfx1030 --cuda-device-only -nogpuinc -nogpulib -mno-cumode \
1414
// RUN: %s 2>&1 | FileCheck --check-prefix=CUMODE-OFF %s
15-
// WARN-CUMODE: warning: ignoring '-mno-cumode' option as it is not currently supported for processor 'gfx906' [-Woption-ignored]
15+
// RUN: %clang -S -o - --offload-arch=gfx1250 --cuda-device-only -nogpuinc -nogpulib \
16+
// RUN: %s 2>&1 | FileCheck --check-prefix=NOWGP %s
17+
// RUN: %clang -S -o - --offload-arch=gfx1250 --cuda-device-only -nogpuinc -nogpulib -mcumode \
18+
// RUN: %s 2>&1 | FileCheck --check-prefix=NOWGP %s
19+
// RUN: %clang -S -o - --offload-arch=gfx1250 --cuda-device-only -nogpuinc -nogpulib -mno-cumode \
20+
// RUN: %s 2>&1 | FileCheck -DOFFLOAD_ARCH=gfx1250 --check-prefixes=NOWGP,WARN-CUMODE %s
21+
// WARN-CUMODE: warning: ignoring '-mno-cumode' option as it is not currently supported for processor '[[OFFLOAD_ARCH]]' [-Woption-ignored]
1622
// NOWGP-NOT: .amdhsa_workgroup_processor_mode
1723
// CUMODE-ON: .amdhsa_workgroup_processor_mode 0
1824
// CUMODE-OFF: .amdhsa_workgroup_processor_mode 1

0 commit comments

Comments
 (0)