Skip to content

[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

Merged
merged 12 commits into from
Jun 17, 2024

Conversation

Fznamznon
Copy link
Contributor

This should simplify handling of resulting value by the callers.

This should simplify handling of resulting value by the callers.
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:PowerPC clang:codegen IR generation bugs: mangling, exceptions, etc. labels Jun 6, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 6, 2024

@llvm/pr-subscribers-backend-amdgpu
@llvm/pr-subscribers-backend-webassembly
@llvm/pr-subscribers-backend-sparc
@llvm/pr-subscribers-backend-systemz
@llvm/pr-subscribers-backend-loongarch
@llvm/pr-subscribers-backend-arm
@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-backend-msp430
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-powerpc

Author: Mariya Podchishchaeva (Fznamznon)

Changes

This should simplify handling of resulting value by the callers.


Full diff: https://github.com/llvm/llvm-project/pull/94635.diff

6 Files Affected:

  • (modified) clang/lib/CodeGen/CGCall.cpp (+23-6)
  • (modified) clang/lib/CodeGen/CGExprAgg.cpp (+3-3)
  • (modified) clang/lib/CodeGen/CGExprComplex.cpp (+3-4)
  • (modified) clang/lib/CodeGen/CGExprScalar.cpp (+2-19)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+1-1)
  • (modified) clang/test/CodeGen/PowerPC/aix32-complex-varargs.c (+8-10)
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]]
 }

Copy link
Contributor

@rjmccall rjmccall left a 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.

@Fznamznon
Copy link
Contributor Author

Fznamznon commented Jun 7, 2024

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

Ok, that seems doable, but I'm having trouble with EmitLoadOfLValue. In case target type is an aggregate, EmitLoadOfLValue still loads it as a scalar, so later EmitFinalDestCopy fails with an assertion because returned RValue is not aggregate.
I could just return RValue::getAggregate when target type is aggregate but I will have to check each time (about 16 places where I inserted EmitLoadOfLValue, I suppose) which makes it fairly big amount of code. Am I doing something wrong?

@rjmccall
Copy link
Contributor

rjmccall commented Jun 7, 2024

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

Ok, that seems doable, but I'm having trouble with EmitLoadOfLValue.

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 EmitLoadOfLValue, EmitLoadOfComplex, or EmitAggregateCopy.

In case target type is an aggregate, EmitLoadOfLValue still loads it as a scalar, so later EmitFinalDestCopy fails with an assertion because returned RValue is not aggregate. I could just return RValue::getAggregate when target type is aggregate but I will have to check each time (about 16 places where I inserted EmitLoadOfLValue, I suppose) which makes it fairly big amount of code. Am I doing something wrong?

Only to the extent that I mislead you. You can make a common function to call to do this, though.

Copy link

github-actions bot commented Jun 10, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@Fznamznon Fznamznon requested a review from rjmccall June 10, 2024 14:32
@Fznamznon Fznamznon requested a review from rjmccall June 11, 2024 16:44
Copy link
Contributor

@rjmccall rjmccall left a 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.

case TEK_Complex:
return RValue::getComplex(EmitLoadOfComplex(LV, Loc));
case TEK_Aggregate:
EmitAggFinalDestCopy(Ty, Slot, LV, EVK_RValue);
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

@efriedma-quic efriedma-quic left a 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.

@@ -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(
Copy link
Collaborator

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done.

// 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
Copy link
Collaborator

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.

Copy link
Contributor Author

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,
Copy link
Collaborator

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"),
Copy link
Collaborator

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?

Copy link
Contributor

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.)

Copy link
Contributor Author

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?

Copy link
Collaborator

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.

Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

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".

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

@efriedma-quic efriedma-quic left a 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
Copy link
Collaborator

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.

Copy link
Contributor Author

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

@@ -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(
Copy link
Collaborator

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.

@Fznamznon Fznamznon merged commit 6d973b4 into llvm:main Jun 17, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants