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
21 changes: 21 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

// TODO(cir): we shouldn't need this but we currently reuse intrinsic IDs for
// convenience.
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "llvm/IR/Intrinsics.h"

#include "clang/AST/GlobalDecl.h"
Expand Down Expand Up @@ -349,6 +350,26 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
break;

// C stdarg builtins.
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
case Builtin::BI__va_start: {
auto vaList = buildScalarExpr(E->getArg(0));
builder.create<mlir::cir::VAStartOp>(vaList.getLoc(), vaList);
return {};
}
case Builtin::BI__builtin_va_end: {
auto vaList = buildVAListRef(E->getArg(0)).getPointer();
builder.create<mlir::cir::VAEndOp>(vaList.getLoc(), vaList);
return {};
}
case Builtin::BI__builtin_va_copy: {
auto dstPtr = buildVAListRef(E->getArg(0)).getPointer();
auto srcPtr = buildVAListRef(E->getArg(1)).getPointer();
builder.create<mlir::cir::VACopyOp>(dstPtr.getLoc(), dstPtr, srcPtr);
return {};
}

// C++ std:: builtins.
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,3 +1144,15 @@ RValue CallArg::getRValue(CIRGenFunction &CGF, mlir::Location loc) const {
IsUsed = true;
return RValue::getAggregate(Copy.getAddress());
}

/* VarArg handling */

// FIXME(cir): This completely abstracts away the ABI with a generic CIR Op. We
// need to decide how to handle va_arg target-specific codegen.
mlir::Value CIRGenFunction::buildVAArg(VAArgExpr *VE, Address &VAListAddr) {
assert(!VE->isMicrosoftABI() && "NYI");
auto loc = CGM.getLoc(VE->getExprLoc());
auto type = ConvertType(VE->getType());
auto vaList = buildVAListRef(VE->getSubExpr()).getPointer();
return builder.create<mlir::cir::VAArgOp>(loc, type, vaList);
}
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,10 @@ Address CIRGenFunction::buildPointerWithAlignment(const Expr *E,
case CK_LValueToRValue:
break;

// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
case CK_ArrayToPointerDecay:
return buildArrayToPointerDecay(CE->getSubExpr());

case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
// TODO: Support accesses to members of base classes in TBAA. For now, we
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value
VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
mlir::Value VisitChooseExpr(ChooseExpr *E) { llvm_unreachable("NYI"); }
mlir::Value VisitVAArgExpr(VAArgExpr *E) { llvm_unreachable("NYI"); }
mlir::Value VisitVAArgExpr(VAArgExpr *VE);
mlir::Value VisitObjCStringLiteral(const ObjCStringLiteral *E) {
llvm_unreachable("NYI");
}
Expand Down Expand Up @@ -1960,3 +1960,15 @@ mlir::Value ScalarExprEmitter::VisitBinLOr(const clang::BinaryOperator *E) {

return Builder.createZExtOrBitCast(ResOp.getLoc(), ResOp, ResTy);
}

mlir::Value ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
QualType Ty = VE->getType();

if (Ty->isVariablyModifiedType())
assert(!UnimplementedFeature::variablyModifiedTypeEmission() && "NYI");

Address ArgValue = Address::invalid();
mlir::Value Val = CGF.buildVAArg(VE, ArgValue);

return Val;
}
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1246,3 +1246,9 @@ void CIRGenFunction::buildDeclRefExprDbgValue(const DeclRefExpr *E,
const APValue &Init) {
assert(!UnimplementedFeature::generateDebugInfo());
}

Address CIRGenFunction::buildVAListRef(const Expr* E) {
if (getContext().getBuiltinVaListType()->isArrayType())
return buildPointerWithAlignment(E);
return buildLValue(E).getAddress();
}
22 changes: 22 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,28 @@ class CIRGenFunction : public CIRGenTypeCache {
RValue convertTempToRValue(Address addr, clang::QualType type,
clang::SourceLocation Loc);

// Build a "reference" to a va_list; this is either the address or the value
// of the expression, depending on how va_list is defined.
Address buildVAListRef(const Expr *E);

/// Emits a call to an LLVM variable-argument intrinsic, either
/// \c llvm.va_start or \c llvm.va_end.
/// \param ArgValue A reference to the \c va_list as emitted by either
/// \c EmitVAListRef or \c EmitMSVAListRef.
/// \param IsStart If \c true, emits a call to \c llvm.va_start; otherwise,
/// calls \c llvm.va_end.
mlir::cir::CallOp buildVAStartEnd(mlir::Value ArgValue, bool IsStart);

/// Generate code to get an argument from the passed in pointer
/// and update it accordingly.
/// \param VE The \c VAArgExpr for which to generate code.
/// \param VAListAddr Receives a reference to the \c va_list as emitted by
/// either \c EmitVAListRef or \c EmitMSVAListRef.
/// \returns SSA value with the argument.
// FIXME: We should be able to get rid of this method and use the va_arg
// instruction in LLVM instead once it works well enough.
mlir::Value buildVAArg(VAArgExpr *VE, Address &VAListAddr);

/// Given an expression that represents a value lvalue, this method emits the
/// address of the lvalue, then loads the result as an rvalue, returning the
/// rvalue.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct UnimplementedFeature {
// Coroutines
static bool unhandledException() { return false; }

// Missing Emissions
static bool variablyModifiedTypeEmission() { return false; }

// Clang early struct optimizations
static bool shouldUseBZeroPlusStoresToInitialize() { return false; }
static bool shouldUseMemSetToInitialize() { return false; }
Expand Down
31 changes: 29 additions & 2 deletions clang/test/CIR/CodeGen/variadics.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,35 @@
// RUN: %clang_cc1 -x c++ -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir-enable -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s

int average(int count, ...);
// CHECK: cir.func private @{{.*}}average{{.*}}(!s32i, ...) -> !s32i
typedef __builtin_va_list va_list;

#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_copy(dst, src) __builtin_va_copy(dst, src)

// CHECK: [[VALISTTYPE:!.+va_list_.+]] = !cir.struct<"struct.__va_list_tag"

int average(int count, ...) {
// CHECK: cir.func @{{.*}}average{{.*}}(%arg0: !s32i loc({{.+}}), ...) -> !s32i
va_list args, args_copy;
va_start(args, count);
// CHECK: cir.va.start %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>

va_copy(args_copy, args);
// CHECK: cir.va.copy %{{[0-9]+}} to %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>, !cir.ptr<[[VALISTTYPE]]>

int sum = 0;
for(int i = 0; i < count; i++) {
sum += va_arg(args, int);
// CHECK: %{{[0-9]+}} = cir.va.arg %{{[0-9]+}} : (!cir.ptr<[[VALISTTYPE]]>) -> !s32i
}

va_end(args);
// CHECK: cir.va.end %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>

return count > 0 ? sum / count : 0;
}

int test(void) {
return average(5, 1, 2, 3, 4, 5);
Expand Down