Library calls for complex types and terminate scopes.

Hi all,

I came across an issue that happens to trigger an assertion in clang if an operation with type type is implemented in a scope that happens to install a terminate scope in the exceptions stack. I see the issue while using complex arithmetic in OpenMP regions, but I believe that could also be a problem for non-openMP codes.

The problem happens in ComplexExprEmitter::EmitComplexBinOpLibCall and is caused by an assertion in:


RValue Res = CGF.EmitCall(FuncInfo, Func, ReturnValueSlot(), Args,
nullptr, &Call);
cast<llvm::CallInst>(Call)->setCallingConv(CGF.CGM.getBuiltinCC());
cast<llvm::CallInst>(Call)->setDoesNotThrow();

EHStack.requiresLandingPad() is used by EmitCall and is true if we have a scope installed in the exceptions stack. This causes EmitCall to produce an invoke instruction instead of a call instruction.

One of the ways to tackle the issue is use the proper attributes for the library function (e.g. no unwind). Is this the right thing to do? Or can these library calls throw in some cases?

Any thoughts?

Here is a simple code that replicates the problem:


int main (int argc, char *argv[]){
double _Complex dc = (double)argc + 3*I;

dc *= dc;
#pragma omp parallel
{
dc *= dc;
}

printf("%lf %lf\n",creal(dc),cimag(dc));
return 0;
}

Thanks!

Samuel

Maybe you could mark the runtime function nounwind when you get its declaration here:

llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName /pass an AttributeSet here/);

Then you won’t have to call setDoesNotThrow() later.

Maybe you could mark the runtime function nounwind when you get its
declaration here:
  llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName
/*pass an AttributeSet here*/);

Then you won't have to call setDoesNotThrow() later.

The by-design way to do this is to add a noexcept specification to the
ExtInfo being passed to arrangeFreeFunctionCall.

John.

Reid, John,

Thanks for the feedback!

Oops! Sorry, I forgot about a layer of abstraction here. It turns out that we have this information on the ExtProtoInfo, but not the ordinary ExtInfo, and we only find it for normal calls by examining the called Decl.

Putting an attribute on the Function isn’t going to help, unfortunately; you’ll need some way to propagate this down to ConstructAttributeList. I see two options here.

The first option is just to construct a FunctionDecl with the appropriate FunctionProtoType that includes a noexcept specification or a nothrow attribute or something. This is probably the easiest thing to do, and if done properly it would solve any potential problems with fetching the global declaration as well.

The second option — and this is more involved — is that it would generally make sense to have a better abstraction for the abstract callee. Right now, we’re just passing around a Decl*, but that has some significant drawbacks. First, it glosses over some very important differences, like the difference between a direct call and a virtual call to the same C++ member function. Second, it means we lose the ability to remember anything interesting about callees that (as here) aren’t tied to specific declarations. An example of the latter issue that’s closely related to this one is that you can make a function pointer type in C++ with an exception specification, and it’s intended to be illegal (under C++'s weird informal type system around exception specifications; [except.spec]p6) for a call to a value of such a type to violate the specification, but we don’t take advantage of that in IRGen because we tie these things purely to calls; whereas we totally could take advantage of it if you could define an abstract callee with just a FunctionProtoType.

I would prefer to solve this the second way, but I can sympathize if you see that as out-of-scope for your patch.

John.

Hi John,