-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][CodeGen] Return RValue from EmitVAArg
#94635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This should simplify handling of resulting value by the callers.
@llvm/pr-subscribers-backend-amdgpu @llvm/pr-subscribers-backend-powerpc Author: Mariya Podchishchaeva (Fznamznon) ChangesThis should simplify handling of resulting value by the callers. Full diff: https://github.com/llvm/llvm-project/pull/94635.diff 6 Files Affected:
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 97449a5e51e73..8a6b9797b6a1d 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5988,12 +5988,29 @@ CGCallee CGCallee::prepareConcreteCallee(CodeGenFunction &CGF) const {
/* VarArg handling */
-Address CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr) {
- VAListAddr = VE->isMicrosoftABI()
- ? EmitMSVAListRef(VE->getSubExpr())
- : EmitVAListRef(VE->getSubExpr());
+RValue CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr) {
+ VAListAddr = VE->isMicrosoftABI() ? EmitMSVAListRef(VE->getSubExpr())
+ : EmitVAListRef(VE->getSubExpr());
QualType Ty = VE->getType();
+ Address ResAddr = Address::invalid();
if (VE->isMicrosoftABI())
- return CGM.getTypes().getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty);
- return CGM.getTypes().getABIInfo().EmitVAArg(*this, VAListAddr, Ty);
+ ResAddr = CGM.getTypes().getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty);
+ else
+ ResAddr = CGM.getTypes().getABIInfo().EmitVAArg(*this, VAListAddr, Ty);
+
+ switch (getEvaluationKind(VE->getType())) {
+ case TEK_Scalar: {
+ llvm::Value *Load = Builder.CreateLoad(ResAddr);
+ return RValue::get(Load);
+ }
+ case TEK_Complex: {
+ llvm::Value *Load = Builder.CreateLoad(ResAddr);
+ llvm::Value *Real = Builder.CreateExtractValue(Load, 0);
+ llvm::Value *Imag = Builder.CreateExtractValue(Load, 1);
+ return RValue::getComplex(std::make_pair(Real, Imag));
+ }
+ case TEK_Aggregate:
+ return RValue::getAggregate(ResAddr);
+ }
+ llvm_unreachable("bad evaluation kind");
}
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 5b2039af6128b..41688c1f861ed 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1328,15 +1328,15 @@ void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
Address ArgValue = Address::invalid();
- Address ArgPtr = CGF.EmitVAArg(VE, ArgValue);
+ RValue ArgPtr = CGF.EmitVAArg(VE, ArgValue);
// If EmitVAArg fails, emit an error.
- if (!ArgPtr.isValid()) {
+ if (!ArgValue.isValid()) {
CGF.ErrorUnsupported(VE, "aggregate va_arg expression");
return;
}
- EmitFinalDestCopy(VE->getType(), CGF.MakeAddrLValue(ArgPtr, VE->getType()));
+ EmitFinalDestCopy(VE->getType(), ArgPtr);
}
void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 9ef73e36f66f3..3b3f026eaaeac 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -1449,9 +1449,9 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
Address ArgValue = Address::invalid();
- Address ArgPtr = CGF.EmitVAArg(E, ArgValue);
+ RValue RV = CGF.EmitVAArg(E, ArgValue);
- if (!ArgPtr.isValid()) {
+ if (!ArgValue.isValid()) {
CGF.ErrorUnsupported(E, "complex va_arg expression");
llvm::Type *EltTy =
CGF.ConvertType(E->getType()->castAs<ComplexType>()->getElementType());
@@ -1459,8 +1459,7 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
return ComplexPairTy(U, U);
}
- return EmitLoadOfLValue(CGF.MakeAddrLValue(ArgPtr, E->getType()),
- E->getExprLoc());
+ return RV.getComplexVal();
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 58f0a3113b4f8..53c3276dd0559 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -5357,28 +5357,11 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
CGF.EmitVariablyModifiedType(Ty);
Address ArgValue = Address::invalid();
- Address ArgPtr = CGF.EmitVAArg(VE, ArgValue);
+ RValue ArgPtr = CGF.EmitVAArg(VE, ArgValue);
llvm::Type *ArgTy = ConvertType(VE->getType());
- // If EmitVAArg fails, emit an error.
- if (!ArgPtr.isValid()) {
- CGF.ErrorUnsupported(VE, "va_arg expression");
- return llvm::UndefValue::get(ArgTy);
- }
-
- // FIXME Volatility.
- llvm::Value *Val = Builder.CreateLoad(ArgPtr);
-
- // If EmitVAArg promoted the type, we must truncate it.
- if (ArgTy != Val->getType()) {
- if (ArgTy->isPointerTy() && !Val->getType()->isPointerTy())
- Val = Builder.CreateIntToPtr(Val, ArgTy);
- else
- Val = Builder.CreateTrunc(Val, ArgTy);
- }
-
- return Val;
+ return ArgPtr.getScalarVal();
}
Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 5739fbaaa9194..f74b6a76a7dce 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3016,7 +3016,7 @@ class CodeGenFunction : public CodeGenTypeCache {
/// \returns A pointer to 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.
- Address EmitVAArg(VAArgExpr *VE, Address &VAListAddr);
+ RValue EmitVAArg(VAArgExpr *VE, Address &VAListAddr);
/// emitArrayLength - Compute the length of an array, even if it's a
/// VLA, and drill down to the base element type.
diff --git a/clang/test/CodeGen/PowerPC/aix32-complex-varargs.c b/clang/test/CodeGen/PowerPC/aix32-complex-varargs.c
index 6036adb7d23be..02dd071bdb744 100644
--- a/clang/test/CodeGen/PowerPC/aix32-complex-varargs.c
+++ b/clang/test/CodeGen/PowerPC/aix32-complex-varargs.c
@@ -11,14 +11,13 @@ void testva (int n, ...)
// CHECK: %[[VAR40:[A-Za-z0-9.]+]] = load ptr, ptr %[[VAR100:[A-Za-z0-9.]+]]
// CHECK-NEXT: %[[VAR41:[A-Za-z0-9.]+]] = getelementptr inbounds i8, ptr %[[VAR40]]
// CHECK-NEXT: store ptr %[[VAR41]], ptr %[[VAR100]], align 4
-// CHECK-NEXT: %[[VAR6:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, ptr %[[VAR40]], i32 0, i32 0
-// CHECK-NEXT: %[[VAR7:[A-Za-z0-9.]+]] = load i32, ptr %[[VAR6]]
-// CHECK-NEXT: %[[VAR8:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, ptr %[[VAR40]], i32 0, i32 1
-// CHECK-NEXT: %[[VAR9:[A-Za-z0-9.]+]] = load i32, ptr %[[VAR8]]
+// CHECK-NEXT: %[[VAR6:[A-Za-z0-9.]+]] = load { i32, i32 }, ptr %[[VAR40]], align 4
+// CHECK-NEXT: %[[VAR7:[A-Za-z0-9.]+]] = extractvalue { i32, i32 } %[[VAR6]], 0
+// CHECK-NEXT: %[[VAR8:[A-Za-z0-9.]+]] = extractvalue { i32, i32 } %[[VAR6]], 1
// CHECK-NEXT: %[[VAR10:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, ptr %[[VARINT:[A-Za-z0-9.]+]], i32 0, i32 0
// CHECK-NEXT: %[[VAR11:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, ptr %[[VARINT]], i32 0, i32 1
// CHECK-NEXT: store i32 %[[VAR7]], ptr %[[VAR10]]
-// CHECK-NEXT: store i32 %[[VAR9]], ptr %[[VAR11]]
+// CHECK-NEXT: store i32 %[[VAR8]], ptr %[[VAR11]]
_Complex short s = va_arg(ap, _Complex short);
// CHECK: %[[VAR50:[A-Za-z0-9.]+]] = load ptr, ptr %[[VAR100:[A-Za-z0-9.]+]]
@@ -51,12 +50,11 @@ void testva (int n, ...)
_Complex float f = va_arg(ap, _Complex float);
// CHECK: %[[VAR70:[A-Za-z0-9.]+]] = getelementptr inbounds i8, ptr %[[VAR71:[A-Za-z0-9.]+]], i32 8
// CHECK-NEXT: store ptr %[[VAR70]], ptr %[[VAR100:[A-Za-z0-9.]+]]
-// CHECK-NEXT: %[[VAR29:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, ptr %[[VAR71]], i32 0, i32 0
-// CHECK-NEXT: %[[VAR30:[A-Za-z0-9.]+]] = load float, ptr %[[VAR29]]
-// CHECK-NEXT: %[[VAR31:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, ptr %[[VAR71]], i32 0, i32 1
-// CHECK-NEXT: %[[VAR32:[A-Za-z0-9.]+]] = load float, ptr %[[VAR31]]
+// CHECK-NEXT: %[[VAR29:[A-Za-z0-9.]+]] = load { float, float }, ptr %[[VAR71]], align 4
+// CHECK-NEXT: %[[VAR30:[A-Za-z0-9.]+]] = extractvalue { float, float } %[[VAR29]], 0
+// CHECK-NEXT: %[[VAR31:[A-Za-z0-9.]+]] = extractvalue { float, float } %[[VAR29]], 1
// CHECK-NEXT: %[[VAR33:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, ptr %f, i32 0, i32 0
// CHECK-NEXT: %[[VAR34:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, ptr %f, i32 0, i32 1
// CHECK-NEXT: store float %[[VAR30]], ptr %[[VAR33]]
-// CHECK-NEXT: store float %[[VAR32]], ptr %[[VAR34]]
+// CHECK-NEXT: store float %[[VAR31]], ptr %[[VAR34]]
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was hoping that you might push this down into the target code — if you make emitVoidPtrVAArg
return an RValue
, that'll handle about half of the targets. Most of the rest will just need an EmitLoadOfLValue
at the end. MIPS (which is the target with the weird unpromotion logic) calls emitVoidPtrVAArg
, so it will just need to do its unpromotion on the scalar value, which it should be able to do without creating a temporary.
But this works as a first pass if you think that's too much to ask.
Ok, that seems doable, but I'm having trouble with |
Oh, sorry, I should have looked closer — I didn't notice that this only handles the scalar case. You should probably still call it instead of just emitting your own load for scalars, but yeah, you'll need to switch over the evaluation kind and then call either
Only to the extent that I mislead you. You can make a common function to call to do this, though. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than the one slight nit (that I think may be irrelevant), this LGTM. I'd like @efriedma-quic to also do a quick review if he has time, though.
clang/lib/CodeGen/CGExpr.cpp
Outdated
case TEK_Complex: | ||
return RValue::getComplex(EmitLoadOfComplex(LV, Loc)); | ||
case TEK_Aggregate: | ||
EmitAggFinalDestCopy(Ty, Slot, LV, EVK_RValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the EVK argument here is mean to represent the kind of value that the l-value represents. In that case, it's an l-value — we need to preserve the underlying va_list
storage and not treat it as something we own, because it's possible to iterate varargs twice. I'm not sure it makes a practical difference here because variadic argumets are required to be trivial, but it's better to be accurate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, passed EVK_NonRValue instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generally seems fine.
clang/lib/CodeGen/Targets/Sparc.cpp
Outdated
@@ -325,14 +325,19 @@ Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, | |||
break; | |||
|
|||
case ABIArgInfo::Ignore: | |||
return Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeInfo.Align); | |||
return CGF.EmitLoadOfAnyValue( | |||
CGF.MakeAddrLValue( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very wrong... but I guess that's not related to this patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we should probably separately add some function to synthesize an ignored value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be done in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going to switch all the other Ignore handlers to just return Slot.asRValue();
, might as well also change this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done.
clang/test/CodeGen/mips-varargs.c
Outdated
// O32: [[ARG:%.+]] = load ptr, ptr [[AP_CUR]], align [[$PTRALIGN]] | ||
// N64: [[ARG:%.+]] = load ptr, ptr [[AP_CUR]], align [[$PTRALIGN]] | ||
// ALL: store ptr [[ARG]], ptr [[V]], align [[$PTRALIGN]] | ||
// N32: store ptr [[PTR]], ptr [[V]], align 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure the CHECK line continues to check all the different ABIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose now it does.
|
||
/// EmitAggFinalDestCopy - Emit copy of the specified aggregate into | ||
/// destination address. | ||
void EmitAggFinalDestCopy(QualType Type, AggValueSlot Dest, const LValue &Src, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels strange to be adding this API now... but I guess it's fine? The alternative would be to use EmitAggregateCopy directly. It only really makes a difference for structs containing pointers to ObjC types, which can't be passed by va_arg anyway, but I guess it's better for EmitLoadOfAnyValue to be fully general in case we add other uses in the future.
return Address(CGF.Builder.CreateLoad(VAListAddr, "ap.cur"), | ||
CGF.ConvertTypeForMem(Ty), SlotSize); | ||
if (isEmptyRecord(getContext(), Ty, true)) { | ||
Address ResAddr = Address(CGF.Builder.CreateLoad(VAListAddr, "ap.cur"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should just skip copying empty records?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, for this and the point above, it feels like we should be able to just do nothing. (Ignore
can only be used for empty types.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we will end up with a temporary alloca but not using it. Would that be still ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean, the alloca for the destination? Sure, that's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine to have an alloca
that ends up unused. It'd be slightly better not to, so if you can easily avoid the allocation by e.g. doing the empty-class check earlier, please do; but if that's awkward to achieve, don't worry about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't returning the correct address; for aggregates, we should always return the address in "Slot".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, it might not really matter in this context... CGExprAgg ignores the return value. But still, there's no point to constructing a load that will never be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I didn't think about that. I removed load construction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple minor comments; otherwise LGTM
@@ -834,5 +834,4 @@ typedef struct {} empty; | |||
empty empty_record_test(void) { | |||
// CHECK-LABEL: define{{.*}} void @empty_record_test() | |||
return va_arg(the_list, empty); | |||
// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load ptr, ptr @the_list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe should check something here? Something like // CHECK: call void @llvm.va_start // CHECK-NEXT: ret void
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, there is no va_start but I checked ret
clang/lib/CodeGen/Targets/Sparc.cpp
Outdated
@@ -325,14 +325,19 @@ Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, | |||
break; | |||
|
|||
case ABIArgInfo::Ignore: | |||
return Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeInfo.Align); | |||
return CGF.EmitLoadOfAnyValue( | |||
CGF.MakeAddrLValue( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going to switch all the other Ignore handlers to just return Slot.asRValue();
, might as well also change this one.
This should simplify handling of resulting value by the callers.