diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index df7cc6bce6df..3a764853b578 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -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" @@ -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(vaList.getLoc(), vaList); + return {}; + } + case Builtin::BI__builtin_va_end: { + auto vaList = buildVAListRef(E->getArg(0)).getPointer(); + builder.create(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(dstPtr.getLoc(), dstPtr, srcPtr); + return {}; + } + // C++ std:: builtins. case Builtin::BImove: case Builtin::BImove_if_noexcept: diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 39190f3fe304..77206c5d73dc 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -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(loc, type, vaList); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index b10cdb6e165e..454602a39922 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -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 diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index b715a33bceb2..abc292f6d497 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -551,7 +551,7 @@ class ScalarExprEmitter : public StmtVisitor { 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"); } @@ -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; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index ec5207185b83..2be781a58dcc 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -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(); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 588aed51eb8b..54cd193d5d6c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -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. diff --git a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h index 72de44fd4bd4..2263c12b09bc 100644 --- a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h +++ b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h @@ -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; } diff --git a/clang/test/CIR/CodeGen/variadics.c b/clang/test/CIR/CodeGen/variadics.c index 3c35432b28ab..827c276aefdb 100644 --- a/clang/test/CIR/CodeGen/variadics.c +++ b/clang/test/CIR/CodeGen/variadics.c @@ -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);