Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,3 +429,12 @@ void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl,
builder.setInsertionPointToEnd(block);
cir::YieldOp::create(builder, addr->getLoc());
}

void CIRGenFunction::finishThunk() {
// Clear these to restore the invariants expected by
// StartFunction/FinishFunction.
CurCodeDecl = nullptr;
CurFuncDecl = nullptr;

finishFunction(SourceLocation());
}
13 changes: 7 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,8 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
// Create a scope in the symbol table to hold variable declarations.
SymTableScopeTy varScope(symbolTable);
// Compiler synthetized functions might have invalid slocs...
auto bSrcLoc = fd->getBody()->getBeginLoc();
auto eSrcLoc = fd->getBody()->getEndLoc();
auto bSrcLoc = (fd && fd->getBody()) ? fd->getBody()->getBeginLoc() : SourceLocation();
auto eSrcLoc = (fd && fd->getBody()) ? fd->getBody()->getEndLoc() : SourceLocation();
auto unknownLoc = builder.getUnknownLoc();

auto fnBeginLoc = bSrcLoc.isValid() ? getLoc(bSrcLoc) : unknownLoc;
Expand Down Expand Up @@ -1158,11 +1158,11 @@ void CIRGenFunction::StartFunction(GlobalDecl gd, QualType retTy,
llvm_unreachable("NYI");

// Apply xray attributes to the function (as a string, for now)
if (d->getAttr<XRayInstrumentAttr>()) {
if (d && d->getAttr<XRayInstrumentAttr>()) {
assert(!cir::MissingFeatures::xray());
}

if (ShouldXRayInstrumentFunction()) {
if (d && ShouldXRayInstrumentFunction()) {
assert(!cir::MissingFeatures::xray());
}

Expand Down Expand Up @@ -1365,12 +1365,13 @@ void CIRGenFunction::StartFunction(GlobalDecl gd, QualType retTy,

// Location of the store to the param storage tracked as beginning of
// the function body.
auto fnBodyBegin = getLoc(fd->getBody()->getBeginLoc());
auto fnBodyBegin =
(fd && fd->getBody()) ? getLoc(fd->getBody()->getBeginLoc()) : getLoc(Loc);
builder.CIRBaseBuilderTy::createStore(fnBodyBegin, paramVal, addr);
}
assert(builder.getInsertionBlock() && "Should be valid");

auto fnEndLoc = getLoc(fd->getBody()->getEndLoc());
auto fnEndLoc = (fd && fd->getBody()) ? getLoc(fd->getBody()->getEndLoc()) : getLoc(Loc);

// When the current function is not void, create an address to store the
// result value.
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,24 @@ class CIRGenFunction : public CIRGenTypeCache {

void emitDestructorBody(FunctionArgList &Args);

/// Generate a thunk for the given method.
void generateThunk(cir::FuncOp Fn, const CIRGenFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk,
bool IsUnprototyped);

void startThunk(cir::FuncOp Fn, GlobalDecl GD,
const CIRGenFunctionInfo &FnInfo, bool IsUnprototyped);

void emitCallAndReturnForThunk(cir::FuncOp Callee,
const ThunkInfo *Thunk,
bool IsUnprototyped);

/// Finish thunk generation.
void finishThunk();

void emitMustTailThunk(GlobalDecl GD, mlir::Value AdjustedThisPtr,
cir::FuncOp Callee);

mlir::LogicalResult emitDoStmt(const clang::DoStmt &S);

mlir::Value emitDynamicCast(Address ThisAddr, const CXXDynamicCastExpr *DCE);
Expand Down
33 changes: 24 additions & 9 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,14 +826,22 @@ cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &cgm,
// Some global emissions are triggered while emitting a function, e.g.
// void s() { const char *s = "yolo"; ... }
//
// Be sure to insert global before the current function
// Save the current function context for later insertion logic
auto *curCGF = cgm.getCurrCIRGenFun();
if (curCGF)
builder.setInsertionPoint(curCGF->CurFn);

// Clear insertion point to prevent auto-insertion by create()
// We'll manually insert at the correct location below
builder.clearInsertionPoint();

g = cir::GlobalOp::create(builder, loc, name, t, isConstant, linkage,
addrSpace);
if (!curCGF) {

// Manually insert at the correct location
if (curCGF) {
// Insert before the current function being generated
cgm.getModule().insert(mlir::Block::iterator(curCGF->CurFn), g);
} else {
// Insert at specified point or at end of module
if (insertPoint)
cgm.getModule().insert(insertPoint, g);
else
Expand Down Expand Up @@ -2710,10 +2718,12 @@ cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
// Some global emissions are triggered while emitting a function, e.g.
// void s() { x.method() }
//
// Be sure to insert a new function before a current one.
// Save the current function context for later insertion logic
auto *curCGF = getCurrCIRGenFun();
if (curCGF)
builder.setInsertionPoint(curCGF->CurFn);

// Clear insertion point to prevent auto-insertion by create()
// We'll manually insert at the correct location below
builder.clearInsertionPoint();

f = cir::FuncOp::create(builder, loc, name, ty);

Expand All @@ -2739,8 +2749,14 @@ cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
// Set the special member attribute for this function, if applicable.
setCXXSpecialMemberAttr(f, fd);

if (!curCGF)
// Manually insert at the correct location
if (curCGF) {
// Insert before the current function being generated
theModule.insert(mlir::Block::iterator(curCGF->CurFn), f);
} else {
// Insert at end of module
theModule.push_back(f);
}
}
return f;
}
Expand Down Expand Up @@ -3058,7 +3074,6 @@ void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl,
// NOTE(cir): Original CodeGen checks if this is an intrinsic. In CIR we
// represent them in dedicated ops. The correct attributes are ensured during
// translation to LLVM. Thus, we don't need to check for them here.
assert(!isThunk && "isThunk NYI");

if (!isIncompleteFunction) {
setCIRFunctionAttributes(globalDecl,
Expand Down
92 changes: 87 additions & 5 deletions clang/lib/CIR/CodeGen/CIRGenVTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,87 @@ static void setThunkProperties(CIRGenModule &cgm, const ThunkInfo &thunk,
llvm_unreachable("NYI");
}

void CIRGenFunction::startThunk(cir::FuncOp Fn, GlobalDecl GD,
const CIRGenFunctionInfo &FnInfo,
bool IsUnprototyped) {
assert(!CurGD.getDecl() && "CurGD was already set!");
CurGD = GD;
CurFuncIsThunk = true;

// Build FunctionArgs.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
QualType ThisType = MD->getThisType();
QualType ResultType;
if (IsUnprototyped)
ResultType = CGM.getASTContext().VoidTy;
else if (CGM.getCXXABI().HasThisReturn(GD))
ResultType = ThisType;
else if (CGM.getCXXABI().hasMostDerivedReturn(GD))
ResultType = CGM.getASTContext().VoidPtrTy;
else
ResultType = MD->getType()->castAs<FunctionProtoType>()->getReturnType();
FunctionArgList FunctionArgs;

// Create the implicit 'this' parameter declaration.
CGM.getCXXABI().buildThisParam(*this, FunctionArgs);

// Add the rest of the parameters, if we have a prototype to work with.
if (!IsUnprototyped) {
FunctionArgs.append(MD->param_begin(), MD->param_end());

if (isa<CXXDestructorDecl>(MD))
CGM.getCXXABI().addImplicitStructorParams(*this, ResultType,
FunctionArgs);
}

// Start defining the function.
// NOTE(cir): No ApplyDebugLocation in CIR
StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
MD->getLocation(), MD->getLocation());
// NOTE(cir): No ApplyDebugLocation in CIR

// Since we didn't pass a GlobalDecl to StartFunction, do this ourselves.
CGM.getCXXABI().emitInstanceFunctionProlog(MD->getLocation(), *this);
CXXThisValue = CXXABIThisValue;
CurCodeDecl = MD;
CurFuncDecl = MD;
}

void CIRGenFunction::emitCallAndReturnForThunk(cir::FuncOp Callee,
const ThunkInfo *Thunk,
bool IsUnprototyped) {
assert(isa<CXXMethodDecl>(CurGD.getDecl()) &&
"Please use a new CGF for this thunk");
llvm_unreachable("NYI: emitCallAndReturnForThunk");
}

void CIRGenFunction::emitMustTailThunk(GlobalDecl GD,
mlir::Value AdjustedThisPtr,
cir::FuncOp Callee) {
llvm_unreachable("NYI");
}

void CIRGenFunction::generateThunk(cir::FuncOp Fn,
const CIRGenFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk,
bool IsUnprototyped) {
startThunk(Fn, GD, FnInfo, IsUnprototyped);
// NOTE(cir): No ApplyDebugLocation in CIR

// Get our callee. Use a placeholder type if this method is unprototyped so
// that CIRGenModule doesn't try to set attributes.
mlir::Type Ty;
if (IsUnprototyped)
llvm_unreachable("NYI: unprototyped thunk placeholder type");
else
Ty = CGM.getTypes().GetFunctionType(FnInfo);

cir::FuncOp Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);

// Make the call and return the result.
emitCallAndReturnForThunk(Callee, &Thunk, IsUnprototyped);
}

static bool UseRelativeLayout(const CIRGenModule &CGM) {
return CGM.getTarget().getCXXABI().isItaniumFamily() &&
CGM.getItaniumVTableContext().isRelativeLayout();
Expand Down Expand Up @@ -280,11 +361,10 @@ void CIRGenVTables::addVTableComponent(ConstantArrayBuilder &builder,
layout.vtable_thunks()[nextVTableThunkIndex].first ==
componentIndex) {
// Thunks.
llvm_unreachable("NYI");
// auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second;
auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second;

// nextVTableThunkIndex++;
// fnPtr = maybeEmitThunk(GD, thunkInfo, /*ForVTable=*/true);
nextVTableThunkIndex++;
fnPtr = maybeEmitThunk(GD, thunkInfo, /*ForVTable=*/true);

} else {
// Otherwise we can use the method definition directly.
Expand Down Expand Up @@ -776,7 +856,9 @@ cir::FuncOp CIRGenVTables::maybeEmitThunk(GlobalDecl GD,
return ThunkFn;
llvm_unreachable("NYI method, see OG GenerateVarArgsThunk");
} else {
llvm_unreachable("NYI method, see OG generateThunk");
// Generate the thunk body
CIRGenFunction CGF(CGM, CGM.getBuilder());
CGF.generateThunk(ThunkFn, FnInfo, GD, ThunkAdjustments, IsUnprototyped);
}

setThunkProperties(CGM, ThunkAdjustments, ThunkFn, ForVTable, GD);
Expand Down
37 changes: 37 additions & 0 deletions clang/test/CIR/CodeGen/vtable-thunk-compare-codegen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// XFAIL: *
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.cir.ll
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.codegen.ll
// RUN: diff -u %t.codegen.ll %t.cir.ll
// RUN: FileCheck --input-file=%t.cir.ll %s --check-prefix=CIR
// RUN: FileCheck --input-file=%t.codegen.ll %s --check-prefix=CODEGEN

// Test that CIR thunk generation matches CodeGen behavior

class Base1 {
public:
virtual void foo() {}
};

class Base2 {
public:
virtual void bar() {}
};

class Derived : public Base1, public Base2 {
public:
void bar() override {}
};

void test() {
Derived d;
Base2* b2 = &d;
b2->bar();
}

// Both should generate a thunk
// CIR: define linkonce_odr void @_ZThn{{[0-9]+}}_N7Derived3barEv
// CODEGEN: define linkonce_odr void @_ZThn{{[0-9]+}}_N7Derived3barEv

// Both should have the thunk in the vtable
// CIR: @_ZTV7Derived = linkonce_odr global{{.*}}@_ZThn{{[0-9]+}}_N7Derived3barEv
// CODEGEN: @_ZTV7Derived = linkonce_odr global{{.*}}@_ZThn{{[0-9]+}}_N7Derived3barEv
43 changes: 43 additions & 0 deletions clang/test/CIR/CodeGen/vtable-thunk.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-llvm -fno-clangir-call-conv-lowering %s -o %t.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s

// Test basic thunk generation for multiple inheritance with non-virtual thunks

class Base1 {
public:
virtual void foo() {}
int x;
};

class Base2 {
public:
virtual void bar() {}
int y;
};

class Derived : public Base1, public Base2 {
public:
void bar() override {}
};

void test() {
Derived d;
Base2* b2 = &d;
b2->bar();
}

// Check that thunk function is generated with correct mangling
// CIR: cir.func linkonce_odr @_ZThn8_N7Derived3barEv
// CIR-SAME: (!cir.ptr<![[DerivedTy:.*]]>)

// Check thunk is in vtable
// CIR: cir.global linkonce_odr @_ZTV7Derived = #cir.vtable
// CIR-SAME: #cir.global_view<@_ZThn8_N7Derived3barEv>

// LLVM: define linkonce_odr void @_ZThn8_N7Derived3barEv
// LLVM-SAME: ptr

// LLVM: @_ZTV7Derived = linkonce_odr global
// LLVM-SAME: @_ZThn8_N7Derived3barEv
34 changes: 34 additions & 0 deletions clang/test/CIR/Lowering/vtable-thunk.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM

// Test that thunks lower correctly from CIR to LLVM IR

class Base1 {
public:
virtual void foo() {}
int x;
};

class Base2 {
public:
virtual void bar() {}
int y;
};

class Derived : public Base1, public Base2 {
public:
void bar() override {}
};

void test() {
Derived d;
Base2* b2 = &d;
b2->bar();
}

// Check thunk function is defined with correct linkage
// LLVM: define linkonce_odr void @_ZThn8_N7Derived3barEv(ptr{{.*}} %0)

// Check vtable contains thunk with correct offset (8 bytes on x86_64)
// LLVM: @_ZTV7Derived = linkonce_odr global
// LLVM-SAME: @_ZThn8_N7Derived3barEv
Loading