Skip to content

Commit

Permalink
[CIR][CodeGen] support array def after decl with unknown bound
Browse files Browse the repository at this point in the history
Arrays can be first declared without a known bound, and then defined
with a known bound. clangir crashes on generating CIR for this case.
This patch adds support.
  • Loading branch information
Lancern committed Dec 31, 2023
1 parent 38e962d commit 0c65f1c
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 2 deletions.
54 changes: 52 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,34 @@ void CIRGenModule::setCommonAttributes(GlobalDecl GD, mlir::Operation *GV) {
assert(!UnimplementedFeature::setCommonAttributes());
}

/// Given the type of a previously-seen declaration and the type of a new
/// declaration, determine whether the new declaration can re-declare the
/// previous declaration.
///
/// This typically requires that the given two types are identical. However
/// there are some exceptions:
/// - If the given two types are array types with identical element type,
/// and PreviousTy has unknown array bound, this function returns true.
static bool isValidRedeclarationType(mlir::Type PreviousTy, mlir::Type NowTy) {
if (PreviousTy == NowTy)
return true;

if (isa<mlir::cir::ArrayType>(PreviousTy) &&
isa<mlir::cir::ArrayType>(NowTy)) {
auto PreviousArrayTy = cast<mlir::cir::ArrayType>(PreviousTy);
auto NowArrayTy = cast<mlir::cir::ArrayType>(NowTy);

if (PreviousArrayTy.getEltType() != NowArrayTy.getEltType())
return false;

// At this point PreviousTy and NowTy cannot have identical sizes because
// this would make PreviousTy and NowTy identical.
return PreviousArrayTy.getSize() == 0;
}

return false;
}

/// If the specified mangled name is not in the module,
/// create and return an mlir GlobalOp with the specified type (TODO(cir):
/// address space).
Expand Down Expand Up @@ -546,7 +574,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
assert(0 && "not implemented");

// TODO(cir): check TargetAS matches Entry address space
if (Entry.getSymType() == Ty &&
if (isValidRedeclarationType(Entry.getSymType(), Ty) &&
!UnimplementedFeature::addressSpaceInGlobalVar())
return Entry;

Expand Down Expand Up @@ -909,7 +937,7 @@ void CIRGenModule::buildGlobalVarDefinition(const clang::VarDecl *D,
// from the type of the global (this happens with unions).
if (!GV || GV.getSymType() != InitType) {
// TODO(cir): this should include an address space check as well.
assert(0 && "not implemented");
setTypeOfGlobal(GV, InitType);
}

maybeHandleStaticInExternC(D, GV);
Expand Down Expand Up @@ -1512,6 +1540,28 @@ mlir::cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator(
return mlir::cir::GlobalLinkageKind::ExternalLinkage;
}

void CIRGenModule::setTypeOfGlobal(mlir::cir::GlobalOp &Op, mlir::Type Ty) {
if (Op.getSymType() == Ty)
return;

Op.setSymType(Ty);
auto Sym = cast<mlir::SymbolOpInterface>(Op.getOperation());

// Replace the types at every use site.
auto SymUses = Sym.getSymbolUses(theModule.getOperation());
if (!SymUses.has_value())
return;

for (auto SymUse : *SymUses) {
auto UseOp = dyn_cast<mlir::cir::GetGlobalOp>(SymUse.getUser());
assert(UseOp && "symbol users of GlobalOp is not a GetGlobalOp");

auto UseOpResultValue = UseOp.getAddr();
UseOpResultValue.setType(
mlir::cir::PointerType::get(builder.getContext(), Ty));
}
}

/// This function is called when we implement a function with no prototype, e.g.
/// "int foo() {}". If there are existing call uses of the old function in the
/// module, this adjusts them to call the new function directly.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,10 @@ class CIRGenModule : public CIRGenTypeCache {
getMLIRVisibilityFromCIRLinkage(L));
}

/// Set the type of the given GlobalOp to the given type, and replace the
/// types accordingly at every use site of the given GlobalOp.
void setTypeOfGlobal(mlir::cir::GlobalOp &Op, mlir::Type Ty);

mlir::cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *VD,
bool IsConstant);

Expand Down
11 changes: 11 additions & 0 deletions clang/test/CIR/CodeGen/array-unknown-bound.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s

extern int table[];
// CHECK: cir.global external @table = #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array<!s32i x 3>

int test() { return table[1]; }
// CHECK: cir.func @_Z4testv() -> !s32i extra( {inline = #cir.inline<no>, optnone = #cir.optnone} ) {
// CHECK-NEXT: %0 = cir.alloca !s32i, cir.ptr <!s32i>, ["__retval"] {alignment = 4 : i64}
// CHECK-NEXT: %1 = cir.get_global @table : cir.ptr <!cir.array<!s32i x 3>>

int table[3] {1, 2, 3};

0 comments on commit 0c65f1c

Please sign in to comment.