Skip to content
Merged
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
92 changes: 72 additions & 20 deletions clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "CIRGenCall.h"
#include "CIRGenValue.h"
#include "mlir/IR/Location.h"
#include "clang/AST/Attr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/CIR/MissingFeatures.h"
Expand Down Expand Up @@ -422,28 +423,35 @@ cir::TryOp CIRGenFunction::LexicalScope::getClosestTryParent() {
return nullptr;
}

void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
cir::FuncOp fn, cir::FuncType funcType,
FunctionArgList args, SourceLocation loc,
SourceLocation startLoc) {
assert(!curFn &&
"CIRGenFunction can only be used for one function at a time");
/// An argument came in as a promoted argument; demote it back to its
/// declared type.
static mlir::Value emitArgumentDemotion(CIRGenFunction &cgf, const VarDecl *var,
mlir::Value value) {
mlir::Type ty = cgf.convertType(var->getType());

curFn = fn;
// This can happen with promotions that actually don't change the
// underlying type, like the enum promotions.
if (value.getType() == ty)
return value;

const Decl *d = gd.getDecl();
assert((mlir::isa<cir::IntType>(ty) || cir::isAnyFloatingPointType(ty)) &&
"unexpected promotion type");

didCallStackSave = false;
curCodeDecl = d;
const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
curFuncDecl = d->getNonClosureContext();
if (mlir::isa<cir::IntType>(ty))
return cgf.getBuilder().CIRBaseBuilderTy::createIntCast(value, ty);

prologueCleanupDepth = ehStack.stable_begin();
return cgf.getBuilder().createFloatingCast(value, ty);
}

mlir::Block *entryBB = &fn.getBlocks().front();
builder.setInsertionPointToStart(entryBB);
void CIRGenFunction::emitFunctionProlog(const FunctionArgList &args,
mlir::Block *entryBB,
const FunctionDecl *fd,
SourceLocation bodyBeginLoc) {
// Naked functions don't have prologues.
if (fd && fd->hasAttr<NakedAttr>()) {
cgm.errorNYI(bodyBeginLoc, "naked function decl");
}

// TODO(cir): this should live in `emitFunctionProlog
// Declare all the function arguments in the symbol table.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Classic codegen starts this function by checking the FunctionDecl for NakedAttr and returning immediately if it's present. We should have a check for that.

  // Naked functions don't have prologues.
  if (fd && fd->hasAttr<NakedAttr>()) {
    cgm.errorNYI(bodyBeginLoc, "naked function decl");
  }

for (const auto nameValue : llvm::zip(args, entryBB->getArguments())) {
const VarDecl *paramVar = std::get<0>(nameValue);
Expand All @@ -466,20 +474,64 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
cast<ParmVarDecl>(paramVar)->isKNRPromoted();
assert(!cir::MissingFeatures::constructABIArgDirectExtend());
if (isPromoted)
cgm.errorNYI(fd->getSourceRange(), "Function argument demotion");
paramVal = emitArgumentDemotion(*this, paramVar, paramVal);

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

void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
cir::FuncOp fn, cir::FuncType funcType,
FunctionArgList args, SourceLocation loc,
SourceLocation startLoc) {
assert(!curFn &&
"CIRGenFunction can only be used for one function at a time");

curFn = fn;

const Decl *d = gd.getDecl();

didCallStackSave = false;
curCodeDecl = d;
const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
curFuncDecl = d->getNonClosureContext();

prologueCleanupDepth = ehStack.stable_begin();

mlir::Block *entryBB = &fn.getBlocks().front();
builder.setInsertionPointToStart(entryBB);

// Determine the function body begin location for the prolog.
// If fd is null or has no body, use startLoc as fallback.
SourceLocation bodyBeginLoc = startLoc;
if (fd) {
if (Stmt *body = fd->getBody())
bodyBeginLoc = body->getBeginLoc();
else
bodyBeginLoc = fd->getLocation();
}

emitFunctionProlog(args, entryBB, fd, bodyBeginLoc);

// When the current function is not void, create an address to store the
// result value.
if (!returnType->isVoidType())
emitAndUpdateRetAlloca(returnType, getLoc(fd->getBody()->getEndLoc()),
if (!returnType->isVoidType()) {
// Determine the function body end location.
// If fd is null or has no body, use loc as fallback.
SourceLocation bodyEndLoc = loc;
if (fd) {
if (Stmt *body = fd->getBody())
bodyEndLoc = body->getEndLoc();
else
bodyEndLoc = fd->getLocation();
}
emitAndUpdateRetAlloca(returnType, getLoc(bodyEndLoc),
getContext().getTypeAlignInChars(returnType));
}

if (isa_and_nonnull<CXXMethodDecl>(d) &&
cast<CXXMethodDecl>(d)->isInstance()) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,11 @@ class CIRGenFunction : public CIRGenTypeCache {
clang::QualType buildFunctionArgList(clang::GlobalDecl gd,
FunctionArgList &args);

/// Emit the function prologue: declare function arguments in the symbol
/// table.
void emitFunctionProlog(const FunctionArgList &args, mlir::Block *entryBB,
const FunctionDecl *fd, SourceLocation bodyBeginLoc);

/// Emit code for the start of a function.
/// \param loc The location to be associated with the function.
/// \param startLoc The location of the function body.
Expand Down
42 changes: 42 additions & 0 deletions clang/test/CIR/CodeGen/kr-func-promote.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c89 -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c89 -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c89 -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG

// CIR: cir.func {{.*}}@foo(%arg0: !s32i
// CIR: %0 = cir.alloca !s16i, !cir.ptr<!s16i>, ["x", init]
// CIR: %1 = cir.cast integral %arg0 : !s32i -> !s16i
// CIR: cir.store %1, %0 : !s16i, !cir.ptr<!s16i>
// expected-warning@+1 {{a function definition without a prototype is deprecated}}
void foo(x) short x; {}

// LLVM: define{{.*}} void @foo(i32 %0)
// LLVM: %[[X_PTR:.*]] = alloca i16, i64 1, align 2
// LLVM: %[[X:.*]] = trunc i32 %0 to i16
// LLVM: store i16 %[[X]], ptr %[[X_PTR]], align 2

// OGCG: define{{.*}} void @foo(i32 noundef %0)
// OGCG: entry:
// OGCG: %[[X_PTR:.*]] = alloca i16, align 2
// OGCG: %[[X:.*]] = trunc i32 %0 to i16
// OGCG: store i16 %[[X]], ptr %[[X_PTR]], align 2

// CIR: cir.func{{.*}}no_proto dso_local @bar(%arg0: !cir.double
// CIR: %0 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["f", init]
// CIR: %1 = cir.cast floating %arg0 : !cir.double -> !cir.float
// CIR: cir.store %1, %0 : !cir.float, !cir.ptr<!cir.float>
// expected-warning@+1 {{a function definition without a prototype is deprecated}}
void bar(f) float f; {}

// LLVM: define{{.*}} void @bar(double %0)
// LLVM: %[[F_PTR:.*]] = alloca float, i64 1, align 4
// LLVM: %[[F:.*]] = fptrunc double %0 to float
// LLVM: store float %[[F]], ptr %[[F_PTR]], align 4

// OGCG: define{{.*}} void @bar(double noundef %0)
// OGCG: entry:
// OGCG: %[[F_PTR:.*]] = alloca float, align 4
// OGCG: %[[F:.*]] = fptrunc double %0 to float
// OGCG: store float %[[F]], ptr %[[F_PTR]], align 4