Skip to content

Commit 34b4fb7

Browse files
committed
[CIR][CIRGen] Add codegen for stdarg builtins
Implement the necessary codegen to emit the va_start, va_end, va_arg, and va_copy builtins as custom CIR instructions. ghstack-source-id: d641b62 Pull Request resolved: #94
1 parent 4abcf3b commit 34b4fb7

File tree

8 files changed

+104
-3
lines changed

8 files changed

+104
-3
lines changed

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

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

2425
#include "clang/AST/GlobalDecl.h"
@@ -334,6 +335,26 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
334335
llvm_unreachable("NYI");
335336
break;
336337

338+
// C stdarg builtins.
339+
case Builtin::BI__builtin_stdarg_start:
340+
case Builtin::BI__builtin_va_start:
341+
case Builtin::BI__va_start: {
342+
auto vaList = buildScalarExpr(E->getArg(0));
343+
builder.create<mlir::cir::VAStartOp>(vaList.getLoc(), vaList);
344+
return {};
345+
}
346+
case Builtin::BI__builtin_va_end: {
347+
auto vaList = buildVAListRef(E->getArg(0)).getPointer();
348+
builder.create<mlir::cir::VAEndOp>(vaList.getLoc(), vaList);
349+
return {};
350+
}
351+
case Builtin::BI__builtin_va_copy: {
352+
auto dstPtr = buildVAListRef(E->getArg(0)).getPointer();
353+
auto srcPtr = buildVAListRef(E->getArg(1)).getPointer();
354+
builder.create<mlir::cir::VACopyOp>(dstPtr.getLoc(), dstPtr, srcPtr);
355+
return {};
356+
}
357+
337358
// C++ std:: builtins.
338359
case Builtin::BImove:
339360
case Builtin::BImove_if_noexcept:

clang/lib/CIR/CodeGen/CIRGenCall.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,3 +1131,15 @@ RValue CallArg::getRValue(CIRGenFunction &CGF, mlir::Location loc) const {
11311131
IsUsed = true;
11321132
return RValue::getAggregate(Copy.getAddress());
11331133
}
1134+
1135+
/* VarArg handling */
1136+
1137+
// FIXME(cir): This completely abstracts away the ABI with a generic CIR Op. We
1138+
// need to decide how to handle va_arg target-specific codegen.
1139+
mlir::Value CIRGenFunction::buildVAArg(VAArgExpr *VE, Address &VAListAddr) {
1140+
assert(!VE->isMicrosoftABI() && "NYI");
1141+
auto loc = CGM.getLoc(VE->getExprLoc());
1142+
auto type = ConvertType(VE->getType());
1143+
auto vaList = buildVAListRef(VE->getSubExpr()).getPointer();
1144+
return builder.create<mlir::cir::VAArgOp>(loc, type, vaList);
1145+
}

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,10 @@ Address CIRGenFunction::buildPointerWithAlignment(const Expr *E,
663663
case CK_LValueToRValue:
664664
break;
665665

666+
// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
667+
case CK_ArrayToPointerDecay:
668+
return buildArrayToPointerDecay(CE->getSubExpr());
669+
666670
case CK_UncheckedDerivedToBase:
667671
case CK_DerivedToBase: {
668672
// TODO: Support accesses to members of base classes in TBAA. For now, we

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
551551
mlir::Value
552552
VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
553553
mlir::Value VisitChooseExpr(ChooseExpr *E) { llvm_unreachable("NYI"); }
554-
mlir::Value VisitVAArgExpr(VAArgExpr *E) { llvm_unreachable("NYI"); }
554+
mlir::Value VisitVAArgExpr(VAArgExpr *VE);
555555
mlir::Value VisitObjCStringLiteral(const ObjCStringLiteral *E) {
556556
llvm_unreachable("NYI");
557557
}
@@ -1945,3 +1945,15 @@ mlir::Value ScalarExprEmitter::VisitBinLOr(const clang::BinaryOperator *E) {
19451945

19461946
return Builder.createZExtOrBitCast(ResOp.getLoc(), ResOp, ResTy);
19471947
}
1948+
1949+
mlir::Value ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
1950+
QualType Ty = VE->getType();
1951+
1952+
if (Ty->isVariablyModifiedType())
1953+
assert(!UnimplementedFeature::variablyModifiedTypeEmission() && "NYI");
1954+
1955+
Address ArgValue = Address::invalid();
1956+
mlir::Value Val = CGF.buildVAArg(VE, ArgValue);
1957+
1958+
return Val;
1959+
}

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,3 +1246,9 @@ void CIRGenFunction::buildDeclRefExprDbgValue(const DeclRefExpr *E,
12461246
const APValue &Init) {
12471247
assert(!UnimplementedFeature::generateDebugInfo());
12481248
}
1249+
1250+
Address CIRGenFunction::buildVAListRef(const Expr* E) {
1251+
if (getContext().getBuiltinVaListType()->isArrayType())
1252+
return buildPointerWithAlignment(E);
1253+
return buildLValue(E).getAddress();
1254+
}

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,28 @@ class CIRGenFunction : public CIRGenTypeCache {
803803
RValue convertTempToRValue(Address addr, clang::QualType type,
804804
clang::SourceLocation Loc);
805805

806+
// Build a "reference" to a va_list; this is either the address or the value
807+
// of the expression, depending on how va_list is defined.
808+
Address buildVAListRef(const Expr *E);
809+
810+
/// Emits a call to an LLVM variable-argument intrinsic, either
811+
/// \c llvm.va_start or \c llvm.va_end.
812+
/// \param ArgValue A reference to the \c va_list as emitted by either
813+
/// \c EmitVAListRef or \c EmitMSVAListRef.
814+
/// \param IsStart If \c true, emits a call to \c llvm.va_start; otherwise,
815+
/// calls \c llvm.va_end.
816+
mlir::cir::CallOp buildVAStartEnd(mlir::Value ArgValue, bool IsStart);
817+
818+
/// Generate code to get an argument from the passed in pointer
819+
/// and update it accordingly.
820+
/// \param VE The \c VAArgExpr for which to generate code.
821+
/// \param VAListAddr Receives a reference to the \c va_list as emitted by
822+
/// either \c EmitVAListRef or \c EmitMSVAListRef.
823+
/// \returns SSA value with the argument.
824+
// FIXME: We should be able to get rid of this method and use the va_arg
825+
// instruction in LLVM instead once it works well enough.
826+
mlir::Value buildVAArg(VAArgExpr *VE, Address &VAListAddr);
827+
806828
/// Given an expression that represents a value lvalue, this method emits the
807829
/// address of the lvalue, then loads the result as an rvalue, returning the
808830
/// rvalue.

clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ struct UnimplementedFeature {
6262
// Coroutines
6363
static bool unhandledException() { return false; }
6464

65+
// Missing Emissions
66+
static bool variablyModifiedTypeEmission() { return false; }
67+
6568
// Clang early struct optimizations
6669
static bool shouldUseBZeroPlusStoresToInitialize() { return false; }
6770
static bool shouldUseMemSetToInitialize() { return false; }

clang/test/CIR/CodeGen/variadics.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,29 @@
33
// RUN: %clang_cc1 -x c++ -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir-enable -emit-cir %s -o %t.cir
44
// RUN: FileCheck --input-file=%t.cir %s
55

6-
int average(int count, ...);
7-
// CHECK: cir.func private @{{.*}}average{{.*}}(!s32i, ...) -> !s32i
6+
#include <stdarg.h>
7+
// CHECK: [[VALISTTYPE:!.+va_list_.+]] = !cir.struct<"struct.__va_list_tag"
8+
9+
int average(int count, ...) {
10+
// CHECK: cir.func @{{.*}}average{{.*}}(%arg0: !s32i loc({{.+}}), ...) -> !s32i
11+
va_list args, args_copy;
12+
va_start(args, count);
13+
// CHECK: cir.vastart %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>
14+
15+
va_copy(args_copy, args);
16+
// CHECK: cir.vacopy %{{[0-9]+}} to %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>, !cir.ptr<[[VALISTTYPE]]>
17+
18+
int sum = 0;
19+
for(int i = 0; i < count; i++) {
20+
sum += va_arg(args, int);
21+
// CHECK: %{{[0-9]+}} = cir.vaarg %{{[0-9]+}} : (!cir.ptr<[[VALISTTYPE]]>) -> !s32i
22+
}
23+
24+
va_end(args);
25+
// CHECK: cir.vaend %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>
26+
27+
return count > 0 ? sum / count : 0;
28+
}
829

930
int test(void) {
1031
return average(5, 1, 2, 3, 4, 5);

0 commit comments

Comments
 (0)