From 7813068e218457b074576d3dac8926b7923f97ba Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 5 Mar 2021 12:37:49 +0100 Subject: stage1: Follow the C ABI for return types The current implementation of the target C ABI rules is hopelessly bad, let's tack some more rules on top in order to prevent some miscompilations. Truth to be told the same rule should be applied also to parameters, but I really can't stand stage1. --- src/stage1/codegen.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'src') 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); -- cgit v1.2.3