Skip to content

Introduce callconv annotation #3977

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 8 commits into from
Jan 6, 2020
Merged

Introduce callconv annotation #3977

merged 8 commits into from
Jan 6, 2020

Conversation

LemonBoy
Copy link
Contributor

@LemonBoy LemonBoy commented Dec 24, 2019

Done according to the accepted proposal, zig fmt has been patched up to use the new notation when possible and the whole stdlib has been already updated.
A few new calling conventions have been introduced, you can now write your interrupt handlers (for x86 & AVR) with pure Zig code.

Missing:

  • Integrate with translate-c-2

Not critical but possibly wanted:

  • Validate export/extern/callconv combinations
  • Checks to prevent the use of unsupported CCs for a given target arch

A few open questions:

  • Some CCs are architecture specific, do we want to add a prefix to those (eg. Fastcall -> X86_Fastcall) ?
  • Right now we "group" all the CCs under the same name (eg. AVR interrupt & X86 interrupt are both under the Interrupt entry) and are chosen according to the target architecture. Is this ok or do we want to split them into independent entities?

I'm submitting this as-is to see if the CI is green, in case this is merged please rebase it.

Closes #661

else if (builtin.os == .windows)
// https://locklessinc.com/articles/keyed_events/
else if (builtin.os == .windows)
// https://locklessinc.com/articles/keyed_events/
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't look right to me. Created #3978

@LemonBoy LemonBoy force-pushed the cc-work branch 7 times, most recently from 63252ce to 4fbe848 Compare December 30, 2019 10:24
Copy link
Member

@andrewrk andrewrk left a comment

Choose a reason for hiding this comment

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

Some CCs are architecture specific, do we want to add a prefix to those (eg. Fastcall -> X86_Fastcall) ?

Makes sense to me, let's do it. For "fastcall" it is especially nice because I don't want people to be confused and think "fastcall" is actually somehow "faster", it's more like "quicksort" is to sorting. So it's nice to have the architecture there to imply that this is a calling convention, not a performance thing.

Right now we "group" all the CCs under the same name (eg. AVR interrupt & X86 interrupt are both under the Interrupt entry) and are chosen according to the target architecture. Is this ok or do we want to split them into independent entities?

Hmm, good question. I really can't think of a reason to favor one or the other. With "C calling convention" we already have precedent for a calling convention that means different things on different architecture, so "interrupt" meaning "the architecture's native interrupt calling convention" seems reasonable to me. I defer to your judgment on this one.


This PR is already close enough to mergeable that I would feel comfortable with a hand-off. So let me know when you're done with it, and I'll make sure it lands swiftly in master branch.

const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
buf_appendf(&fn_type->name, "%s", cc_str);
if (fn_type->data.fn.fn_type_id.cc == CallingConventionC)
buf_append_str(&fn_type->name, "extern ");
Copy link
Member

Choose a reason for hiding this comment

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

I was thinking we could drop extern for the C calling convention, once we have callconv. Any reason to keep using extern for C calling convention functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Decoupling extern from the CC is definitely a good idea, I tried not to change the status quo too much in this PR so I think I'll leave the breaking changes to you :)

Comment on lines +656 to +658
bool is_nakedcc;
bool is_stdcallcc;
bool is_async;
Copy link
Member

Choose a reason for hiding this comment

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

Feel free to delete nakedcc and stdcallcc keywords from stage1. (If you don't do it, I'll do it.) I'm happy to tell people to use the auto-fixing you added to zig fmt in order to upgrade code to the latest version.

I'll open a separate proposal to remove support for async fn in favor of callconv(.Async) for uniformity.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ditto, if you want to drop nakedcc and stdcallcc in this release cycle go for it! The less legacy cruft the better.

@@ -2162,7 +2180,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
ZigType *field_type = resolve_struct_field_type(g, field);
if (field_type == nullptr) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
return err;
return ErrorSemanticAnalyzeFail;
Copy link
Member

Choose a reason for hiding this comment

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

yikes! nice catch.

src/codegen.cpp Outdated
case CallingConventionVectorcall:
if (g->zig_target->arch == ZigLLVM_x86)
return LLVMX86VectorCallCallConv;
// XXX Enable this when the C API exports this enum member too
Copy link
Member

Choose a reason for hiding this comment

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

We should work around this with zig_llvm.h/zig_llvm.cpp. The official LLVM C API always lags behind the C++ API.

In fact:

zig/src/zig_llvm.h

Lines 74 to 75 in 86ba8c0

ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
unsigned NumArgs, unsigned CC, enum ZigLLVM_CallAttr attr, const char *Name);

zig/src/zig_llvm.cpp

Lines 275 to 297 in 86ba8c0

LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
unsigned NumArgs, unsigned CC, ZigLLVM_CallAttr attr, const char *Name)
{
CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);
call_inst->setCallingConv(CC);
switch (attr) {
case ZigLLVM_CallAttrAuto:
break;
case ZigLLVM_CallAttrNeverTail:
call_inst->setTailCallKind(CallInst::TCK_NoTail);
break;
case ZigLLVM_CallAttrNeverInline:
call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline);
break;
case ZigLLVM_CallAttrAlwaysTail:
call_inst->setTailCallKind(CallInst::TCK_MustTail);
break;
case ZigLLVM_CallAttrAlwaysInline:
call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline);
break;
}
return wrap(unwrap(B)->Insert(call_inst));
}

Looks like all we're missing is a copy-paste of LLVM's calling convention enum, with some static_asserts in zig_llvm.cpp to make sure the values don't change. See src/zig_clang.cpp for inspiration.

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've sent a patch that hopefully will get in by the time LLVM 10 is out. But moving away from the C API is also a good idea.

Copy link
Contributor Author

@LemonBoy LemonBoy left a comment

Choose a reason for hiding this comment

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

Makes sense to me, let's do it. For "fastcall" it is especially nice because I don't want people to be confused and think "fastcall" is actually somehow "faster", it's more like "quicksort" is to sorting. So it's nice to have the architecture there to imply that this is a calling convention, not a performance thing.

If we go for the prefix route then we should also split the common CCs (Vectorcall becomes X86_Vectorcall and AArch64_Vectorcall, same for Interrupt and so on). IMO it's fine to leave the enums un-prefixed and merged with some hints in the documentation about what to expect.

@andrewrk
Copy link
Member

IMO it's fine to leave the enums un-prefixed and merged with some hints in the documentation about what to expect.

👍

@LemonBoy
Copy link
Contributor Author

This is ready to go on my end, I'll send a follow-up PR to make compiler-rt use the AAPCS cc for the AEABI builtins once this is merged.

@andrewrk andrewrk added the breaking Implementing this issue could cause existing code to no longer compile or have different behavior. label Jan 6, 2020
@andrewrk andrewrk merged commit d09bd3d into ziglang:master Jan 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Implementing this issue could cause existing code to no longer compile or have different behavior.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

use a builtin enum for calling conventions instead of keywords
3 participants