aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-03-12 20:12:36 -0500
committerGitHub <noreply@github.com>2021-03-12 20:12:36 -0500
commitce14bc7176f9e441064ffdde2d85e35fd78977f2 (patch)
tree3b1d25c042403d9e6d071bfd6de71b0b6ec4b21a /src
parent95eb711ca8c0843ede117f61025c5eda0102f845 (diff)
parent36c4037144bdc3d80530205c0e2e9c31bee0f114 (diff)
downloadzig-ce14bc7176f9e441064ffdde2d85e35fd78977f2.tar.gz
zig-ce14bc7176f9e441064ffdde2d85e35fd78977f2.zip
Merge pull request #8152 from LemonBoy/fix-riscv-ret
stage1: Follow the C ABI for return types
Diffstat (limited to 'src')
-rw-r--r--src/stage1/codegen.cpp47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp
index 97daf249b1..5c37a1247b 100644
--- a/src/stage1/codegen.cpp
+++ b/src/stage1/codegen.cpp
@@ -487,6 +487,53 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
addLLVMFnAttr(llvm_fn, "noreturn");
}
+ if (!calling_convention_allows_zig_types(cc)) {
+ // A simplistic and desperate attempt at making the compiler respect the
+ // target ABI for return types.
+ // This is just enough to avoid miscompiling the test suite, it will be
+ // better in stage2.
+ ZigType *int_type = return_type->id == ZigTypeIdInt ? return_type :
+ return_type->id == ZigTypeIdEnum ? return_type->data.enumeration.tag_int_type :
+ nullptr;
+
+ if (int_type != nullptr) {
+ const bool is_signed = int_type->data.integral.is_signed;
+ const uint32_t bit_width = int_type->data.integral.bit_count;
+ bool should_extend = false;
+
+ // Rough equivalent of Clang's isPromotableIntegerType.
+ switch (bit_width) {
+ case 1: // bool
+ case 8: // {un,}signed char
+ case 16: // {un,}signed short
+ should_extend = true;
+ break;
+ default:
+ break;
+ }
+
+ switch (g->zig_target->arch) {
+ case ZigLLVM_sparcv9:
+ case ZigLLVM_riscv64:
+ case ZigLLVM_ppc64:
+ case ZigLLVM_ppc64le:
+ // Always extend to the register width.
+ should_extend = bit_width < 64;
+ break;
+ default:
+ break;
+ }
+
+ // {zero,sign}-extend the result.
+ if (should_extend) {
+ if (is_signed)
+ addLLVMAttr(llvm_fn, 0, "signext");
+ else
+ addLLVMAttr(llvm_fn, 0, "zeroext");
+ }
+ }
+ }
+
if (fn->body_node != nullptr) {
maybe_export_dll(g, llvm_fn, linkage);