Skip to content

Commit 3302640

Browse files
sitio-coutolanza
authored andcommitted
[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: 4a73b84 Pull Request resolved: #94
1 parent f33086b commit 3302640

File tree

8 files changed

+110
-3
lines changed

8 files changed

+110
-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"
@@ -349,6 +350,26 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
349350
}
350351
break;
351352

353+
// C stdarg builtins.
354+
case Builtin::BI__builtin_stdarg_start:
355+
case Builtin::BI__builtin_va_start:
356+
case Builtin::BI__va_start: {
357+
auto vaList = buildScalarExpr(E->getArg(0));
358+
builder.create<mlir::cir::VAStartOp>(vaList.getLoc(), vaList);
359+
return {};
360+
}
361+
case Builtin::BI__builtin_va_end: {
362+
auto vaList = buildVAListRef(E->getArg(0)).getPointer();
363+
builder.create<mlir::cir::VAEndOp>(vaList.getLoc(), vaList);
364+
return {};
365+
}
366+
case Builtin::BI__builtin_va_copy: {
367+
auto dstPtr = buildVAListRef(E->getArg(0)).getPointer();
368+
auto srcPtr = buildVAListRef(E->getArg(1)).getPointer();
369+
builder.create<mlir::cir::VACopyOp>(dstPtr.getLoc(), dstPtr, srcPtr);
370+
return {};
371+
}
372+
352373
// C++ std:: builtins.
353374
case Builtin::BImove:
354375
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
@@ -1144,3 +1144,15 @@ RValue CallArg::getRValue(CIRGenFunction &CGF, mlir::Location loc) const {
11441144
IsUsed = true;
11451145
return RValue::getAggregate(Copy.getAddress());
11461146
}
1147+
1148+
/* VarArg handling */
1149+
1150+
// FIXME(cir): This completely abstracts away the ABI with a generic CIR Op. We
1151+
// need to decide how to handle va_arg target-specific codegen.
1152+
mlir::Value CIRGenFunction::buildVAArg(VAArgExpr *VE, Address &VAListAddr) {
1153+
assert(!VE->isMicrosoftABI() && "NYI");
1154+
auto loc = CGM.getLoc(VE->getExprLoc());
1155+
auto type = ConvertType(VE->getType());
1156+
auto vaList = buildVAListRef(VE->getSubExpr()).getPointer();
1157+
return builder.create<mlir::cir::VAArgOp>(loc, type, vaList);
1158+
}

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

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

668+
// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
669+
case CK_ArrayToPointerDecay:
670+
return buildArrayToPointerDecay(CE->getSubExpr());
671+
668672
case CK_UncheckedDerivedToBase:
669673
case CK_DerivedToBase: {
670674
// 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
}
@@ -1960,3 +1960,15 @@ mlir::Value ScalarExprEmitter::VisitBinLOr(const clang::BinaryOperator *E) {
19601960

19611961
return Builder.createZExtOrBitCast(ResOp.getLoc(), ResOp, ResTy);
19621962
}
1963+
1964+
mlir::Value ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
1965+
QualType Ty = VE->getType();
1966+
1967+
if (Ty->isVariablyModifiedType())
1968+
assert(!UnimplementedFeature::variablyModifiedTypeEmission() && "NYI");
1969+
1970+
Address ArgValue = Address::invalid();
1971+
mlir::Value Val = CGF.buildVAArg(VE, ArgValue);
1972+
1973+
return Val;
1974+
}

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

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

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
@@ -65,6 +65,9 @@ struct UnimplementedFeature {
6565
// Coroutines
6666
static bool unhandledException() { return false; }
6767

68+
// Missing Emissions
69+
static bool variablyModifiedTypeEmission() { return false; }
70+
6871
// Clang early struct optimizations
6972
static bool shouldUseBZeroPlusStoresToInitialize() { return false; }
7073
static bool shouldUseMemSetToInitialize() { return false; }

clang/test/CIR/CodeGen/variadics.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,35 @@
33
// RUN: %clang_cc1 -x c++ -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -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+
typedef __builtin_va_list va_list;
7+
8+
#define va_start(ap, param) __builtin_va_start(ap, param)
9+
#define va_end(ap) __builtin_va_end(ap)
10+
#define va_arg(ap, type) __builtin_va_arg(ap, type)
11+
#define va_copy(dst, src) __builtin_va_copy(dst, src)
12+
13+
// CHECK: [[VALISTTYPE:!.+va_list_.+]] = !cir.struct<"struct.__va_list_tag"
14+
15+
int average(int count, ...) {
16+
// CHECK: cir.func @{{.*}}average{{.*}}(%arg0: !s32i loc({{.+}}), ...) -> !s32i
17+
va_list args, args_copy;
18+
va_start(args, count);
19+
// CHECK: cir.va.start %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>
20+
21+
va_copy(args_copy, args);
22+
// CHECK: cir.va.copy %{{[0-9]+}} to %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>, !cir.ptr<[[VALISTTYPE]]>
23+
24+
int sum = 0;
25+
for(int i = 0; i < count; i++) {
26+
sum += va_arg(args, int);
27+
// CHECK: %{{[0-9]+}} = cir.va.arg %{{[0-9]+}} : (!cir.ptr<[[VALISTTYPE]]>) -> !s32i
28+
}
29+
30+
va_end(args);
31+
// CHECK: cir.va.end %{{[0-9]+}} : !cir.ptr<[[VALISTTYPE]]>
32+
33+
return count > 0 ? sum / count : 0;
34+
}
835

936
int test(void) {
1037
return average(5, 1, 2, 3, 4, 5);

0 commit comments

Comments
 (0)