Commit 567945ef authored by Milan P. Stanić's avatar Milan P. Stanić
Browse files

community/crystal: upgrade to 1.0.0

remove obsolete patches
parent ee8afc72
......@@ -2,13 +2,13 @@
# Contributor: Milan P. Stanić <mps@arvanta.net>
# Maintainer: Jakub Jirutka <jakub@jirutka.cz>
pkgname=crystal
pkgver=0.35.1
pkgver=1.0.0
pkgrel=0
_bootver=0.35.0
_llvmver=10
_llvmver=11
pkgdesc="The Crystal Programming Language"
url="https://crystal-lang.org/"
arch="x86_64 aarch64" # reenable aarch64
arch="x86_64 aarch64"
license="Apache-2.0"
depends="gc-dev libatomic_ops libevent-dev libevent-static gcc gmp-dev pcre-dev"
checkdepends="openssl-dev libxml2-dev tzdata yaml-dev zlib-dev"
......@@ -20,10 +20,6 @@ subpackages="$pkgname-doc
source="$pkgname-$pkgver.tar.gz::https://github.com/crystal-lang/$pkgname/archive/$pkgver.tar.gz
https://dev.alpinelinux.org/archive/crystal/crystal-$_bootver-x86_64-alpine-linux-musl.tar.gz
https://dev.alpinelinux.org/archive/crystal/crystal-$_bootver-aarch64-alpine-linux-musl.tar.gz
fix-version-string.patch
global_isel.patch
c_abi.patch
valist.patch
"
builddir="$srcdir/$pkgname-$pkgver"
......@@ -72,6 +68,7 @@ prepare() {
build() {
make crystal \
CRYSTAL_CONFIG_BUILD_COMMIT= \
CRYSTAL_CONFIG_PATH="lib:$_shardsdir:$_coredir" \
PATH="$srcdir/$pkgname-$_bootver-$CBUILD/bin:$PATH" \
LLVM_CONFIG="llvm-config" \
......@@ -115,10 +112,6 @@ zshcomp() {
"$subpkgdir"/usr/share/zsh/site-functions/_$pkgname
}
sha512sums="0381568330802de5838f8e66600567817b60ba0087bb3cc2b5df2944c5c42779039b606c81e0207bef34082bf25331b590a8140830f65ba4106ae465f717000b crystal-0.35.1.tar.gz
sha512sums="aa56eb0131aecad15bebc6ef0ce2f34f0992a8362441dd662a518ddbc5e3818762c1c7228bc5b06aafdb8815e59d791654add9da8ba9a47a6a4fd34f6b039a8b crystal-1.0.0.tar.gz
885c6e76590515bac07d76313c1e453414a08be100f61c9cde02cbc93218ed3048cec2ec060bd413a861a1e5eb51e38213ddc90f41f87bdd517fd22a0af1554f crystal-0.35.0-x86_64-alpine-linux-musl.tar.gz
8ae89267dbc10f3fb9a292843725c792bfdb7dadbd48ca46564e6e58bfe816a4747bcc62058b148c673c0c145f5e637cac230150065c12e8b57a71e7ea830973 crystal-0.35.0-aarch64-alpine-linux-musl.tar.gz
1bb7d649841a7b0f66fdebbb75647ef8958ce7fb3437f0a6303ad21750af79becdcad87ddcf9353d48d466495a6c5837171b571a46412fd746c741296a67ad93 fix-version-string.patch
6c41e0e9b50711cbd1979a4a7734346630ef8aa73cfdbe6592c3930681a7e7efb7c75b20653e6f11dc744db53fd45c1c55f58b7994f979f11edec39c2a11c360 global_isel.patch
a870ac1129fbca7ec503022e20c714d7f45b9502852d5eed691dbcf4d305003bd952d36e214c28cdc43ac9334e9e7ff5f68321cd0118595519b963e7bd015fd0 c_abi.patch
5bdb0163fcd22e7871800a56a4a0229c391ab47fdd23e3ca642a997b871e683302daefd8cb9ebc042a0791332f491e38660005bd5e889ce57e2e32ac1a7e2053 valist.patch"
8ae89267dbc10f3fb9a292843725c792bfdb7dadbd48ca46564e6e58bfe816a4747bcc62058b148c673c0c145f5e637cac230150065c12e8b57a71e7ea830973 crystal-0.35.0-aarch64-alpine-linux-musl.tar.gz"
From 99eff6acb33fc754b09d5418b69a25848da1b92e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonne=20Ha=C3=9F?= <me@jhass.eu>
Date: Fri, 5 Jun 2020 01:11:32 +0200
Subject: [PATCH] Fix C ABI for AArch64
I don't claim to understand why this is more correct, I just compared
the LLVM IR from one failing spec to what Clang would generate for
the equivalent code.
It doesn't seemm to break any other specs
---
spec/compiler/codegen/c_abi/c_abi_spec.cr | 2 +-
spec/std/llvm/aarch64_spec.cr | 2 +-
src/llvm/abi/aarch64.cr | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/spec/compiler/codegen/c_abi/c_abi_spec.cr b/spec/compiler/codegen/c_abi/c_abi_spec.cr
index 1a772b897ae..8250abffa6e 100644
--- a/spec/compiler/codegen/c_abi/c_abi_spec.cr
+++ b/spec/compiler/codegen/c_abi/c_abi_spec.cr
@@ -55,7 +55,7 @@ describe "Code gen: C ABI" do
), &.to_i.should eq(3))
end
- it "passes struct bigger than128 bits (for real)" do
+ it "passes struct bigger than 128 bits (for real)" do
test_c(
%(
struct s {
diff --git a/spec/std/llvm/aarch64_spec.cr b/spec/std/llvm/aarch64_spec.cr
index ee30468f0d2..caaa9d8e0ff 100644
--- a/spec/std/llvm/aarch64_spec.cr
+++ b/spec/std/llvm/aarch64_spec.cr
@@ -140,7 +140,7 @@ class LLVM::ABI
info = abi.abi_info(arg_types, return_type, true, ctx)
info.arg_types.size.should eq(1)
- info.arg_types[0].should eq(ArgType.indirect(str, Attribute::ByVal))
+ info.arg_types[0].should eq(ArgType.indirect(str, nil))
info.return_type.should eq(ArgType.indirect(str, Attribute::StructRet))
end
end
diff --git a/src/llvm/abi/aarch64.cr b/src/llvm/abi/aarch64.cr
index 52cf84ae4b8..14a576d415e 100644
--- a/src/llvm/abi/aarch64.cr
+++ b/src/llvm/abi/aarch64.cr
@@ -136,7 +136,7 @@ class LLVM::ABI::AArch64 < LLVM::ABI
end
ArgType.direct(aty, cast)
else
- ArgType.indirect(aty, LLVM::Attribute::ByVal)
+ ArgType.indirect(aty, nil)
end
end
end
--- a/src/compiler/crystal/config.cr 2019-09-23 16:08:27.000000000 +0000
+++ b/src/compiler/crystal/config.cr 2019-09-26 14:50:47.795131257 +0000
@@ -17,7 +17,7 @@
def self.description
formatted_sha = "[#{build_commit}] " if build_commit
<<-DOC
- Crystal #{version} #{formatted_sha}(#{date})
+ Crystal #{version} (#{date})
LLVM: #{llvm_version}
Default target: #{self.default_target}
From b0435958a0cf91f6d72aae299ec18baddeab026b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonne=20Ha=C3=9F?= <me@jhass.eu>
Date: Sun, 31 May 2020 23:01:18 +0200
Subject: [PATCH] Disable LLVM Global Isel
It's not enabled by default on x86, but on other targets it is.
At least until https://reviews.llvm.org/D80898 is released, it
doesn't like us generating a value of a zero sized type
We may need to fix doing that, but until then this workarounds
the issue.
See https://github.com/crystal-lang/crystal/issues/9297#issuecomment-636512270
for more background.
---
spec/std/llvm/aarch64_spec.cr | 1 +
spec/std/llvm/arm_abi_spec.cr | 1 +
spec/std/llvm/x86_64_abi_spec.cr | 1 +
spec/std/llvm/x86_abi_spec.cr | 1 +
src/compiler/crystal/codegen/target.cr | 9 ++-
src/llvm/ext/llvm_ext.cc | 84 +++++++++++++++++++++++++-
src/llvm/jit_compiler.cr | 2 +-
src/llvm/lib_llvm_ext.cr | 3 +
src/llvm/target_machine.cr | 4 ++
9 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/spec/std/llvm/aarch64_spec.cr b/spec/std/llvm/aarch64_spec.cr
index ee30468f0d2..b6ce65ea278 100644
--- a/spec/std/llvm/aarch64_spec.cr
+++ b/spec/std/llvm/aarch64_spec.cr
@@ -9,6 +9,7 @@ private def abi
triple = "aarch64-unknown-linux-gnu"
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
+ machine.enable_global_isel = false
LLVM::ABI::AArch64.new(machine)
end
diff --git a/spec/std/llvm/arm_abi_spec.cr b/spec/std/llvm/arm_abi_spec.cr
index 1bc7d32d559..98ae9b588a4 100644
--- a/spec/std/llvm/arm_abi_spec.cr
+++ b/spec/std/llvm/arm_abi_spec.cr
@@ -9,6 +9,7 @@ private def abi
triple = "arm-unknown-linux-gnueabihf"
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
+ machine.enable_global_isel = false
LLVM::ABI::ARM.new(machine)
end
diff --git a/spec/std/llvm/x86_64_abi_spec.cr b/spec/std/llvm/x86_64_abi_spec.cr
index e9dcc70423c..2e2514e209d 100644
--- a/spec/std/llvm/x86_64_abi_spec.cr
+++ b/spec/std/llvm/x86_64_abi_spec.cr
@@ -9,6 +9,7 @@ private def abi
triple = LLVM.default_target_triple.gsub(/^(.+?)-/, "x86_64-")
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
+ machine.enable_global_isel = false
LLVM::ABI::X86_64.new(machine)
end
diff --git a/spec/std/llvm/x86_abi_spec.cr b/spec/std/llvm/x86_abi_spec.cr
index e3ae341756b..5f69be12df8 100644
--- a/spec/std/llvm/x86_abi_spec.cr
+++ b/spec/std/llvm/x86_abi_spec.cr
@@ -13,6 +13,7 @@ private def abi
{% end %}
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
+ machine.enable_global_isel = false
LLVM::ABI::X86.new(machine)
end
diff --git a/src/compiler/crystal/codegen/target.cr b/src/compiler/crystal/codegen/target.cr
index 4e469fef9d4..1a9c7727571 100644
--- a/src/compiler/crystal/codegen/target.cr
+++ b/src/compiler/crystal/codegen/target.cr
@@ -143,7 +143,14 @@ class Crystal::Codegen::Target
opt_level = release ? LLVM::CodeGenOptLevel::Aggressive : LLVM::CodeGenOptLevel::None
target = LLVM::Target.from_triple(self.to_s)
- target.create_target_machine(self.to_s, cpu: cpu, features: features, opt_level: opt_level, code_model: code_model).not_nil!
+ machine = target.create_target_machine(self.to_s, cpu: cpu, features: features, opt_level: opt_level, code_model: code_model).not_nil!
+ # We need to disable global isel until https://reviews.llvm.org/D80898 is released,
+ # or we fixed generating values for 0 sized types.
+ # When removing this, also remove it from the ABI specs and jit compiler.
+ # See https://github.com/crystal-lang/crystal/issues/9297#issuecomment-636512270
+ # for background info
+ machine.enable_global_isel = false
+ machine
end
def to_s(io : IO) : Nil
diff --git a/src/llvm/ext/llvm_ext.cc b/src/llvm/ext/llvm_ext.cc
index b418dabb571..760653d5717 100644
--- a/src/llvm/ext/llvm_ext.cc
+++ b/src/llvm/ext/llvm_ext.cc
@@ -9,6 +9,12 @@
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/ADT/Triple.h>
+#include <llvm-c/TargetMachine.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm-c/ExecutionEngine.h>
+#include <llvm/ExecutionEngine/ExecutionEngine.h>
+#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
+#include <llvm/Target/CodeGenCWrappers.h>
using namespace llvm;
@@ -475,10 +481,84 @@ char *LLVMExtBasicBlockName(LLVMBasicBlockRef BB) {
#endif
}
+static TargetMachine *unwrap(LLVMTargetMachineRef P) {
+ return reinterpret_cast<TargetMachine *>(P);
+}
+
+void LLVMExtTargetMachineEnableGlobalIsel(LLVMTargetMachineRef T, LLVMBool Enable) {
+ unwrap(T)->setGlobalISel(Enable);
+}
+
+// Copy paste of https://github.com/llvm/llvm-project/blob/dace8224f38a31636a02fe9c2af742222831f70c/llvm/lib/ExecutionEngine/ExecutionEngineBindings.cpp#L160-L214
+// but with a parameter to set global isel state
+LLVMBool LLVMExtCreateMCJITCompilerForModule(
+ LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M,
+ LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions,
+ LLVMBool EnableGlobalISel,
+ char **OutError) {
+ LLVMMCJITCompilerOptions options;
+ // If the user passed a larger sized options struct, then they were compiled
+ // against a newer LLVM. Tell them that something is wrong.
+ if (SizeOfPassedOptions > sizeof(options)) {
+ *OutError = strdup(
+ "Refusing to use options struct that is larger than my own; assuming "
+ "LLVM library mismatch.");
+ return 1;
+ }
+
+
+ // Defend against the user having an old version of the API by ensuring that
+ // any fields they didn't see are cleared. We must defend against fields being
+ // set to the bitwise equivalent of zero, and assume that this means "do the
+ // default" as if that option hadn't been available.
+ LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
+ memcpy(&options, PassedOptions, SizeOfPassedOptions);
+
+
+ TargetOptions targetOptions;
+ targetOptions.EnableFastISel = options.EnableFastISel;
+ targetOptions.EnableGlobalISel = EnableGlobalISel;
+ std::unique_ptr<Module> Mod(unwrap(M));
+
+ if (Mod)
+ // Set function attribute "frame-pointer" based on
+ // NoFramePointerElim.
+ for (auto &F : *Mod) {
+ auto Attrs = F.getAttributes();
+ StringRef Value = options.NoFramePointerElim ? "all" : "none";
+ Attrs = Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex,
+ "frame-pointer", Value);
+ F.setAttributes(Attrs);
+ }
+
+
+ std::string Error;
+ EngineBuilder builder(std::move(Mod));
+ builder.setEngineKind(EngineKind::JIT)
+ .setErrorStr(&Error)
+ .setOptLevel((CodeGenOpt::Level)options.OptLevel)
+ .setTargetOptions(targetOptions);
+ bool JIT;
+ if (Optional<CodeModel::Model> CM = unwrap(options.CodeModel, JIT))
+ builder.setCodeModel(*CM);
+ if (options.MCJMM)
+ builder.setMCJITMemoryManager(
+ std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM)));
+
+ TargetMachine* tm = builder.selectTarget();
+ tm->setGlobalISel(EnableGlobalISel);
+
+ if (ExecutionEngine *JIT = builder.create(tm)) {
+ *OutJIT = wrap(JIT);
+ return 0;
+ }
+ *OutError = strdup(Error.c_str());
+ return 1;
+}
+
LLVMMetadataRef LLVMExtDIBuilderGetOrCreateArraySubrange(
DIBuilderRef Dref, uint64_t Lo,
uint64_t Count) {
return wrap(Dref->getOrCreateSubrange(Lo, Count));
-}
-
+ }
}
diff --git a/src/llvm/jit_compiler.cr b/src/llvm/jit_compiler.cr
index 8fb45068b99..b881e06ee8d 100644
--- a/src/llvm/jit_compiler.cr
+++ b/src/llvm/jit_compiler.cr
@@ -5,7 +5,7 @@ class LLVM::JITCompiler
mod.take_ownership { raise "Can't create two JIT compilers for the same module" }
# if LibLLVM.create_jit_compiler_for_module(out @unwrap, mod, 3, out error) != 0
- if LibLLVM.create_mc_jit_compiler_for_module(out @unwrap, mod, nil, 0, out error) != 0
+ if LibLLVMExt.create_mc_jit_compiler_for_module(out @unwrap, mod, nil, 0, false, out error) != 0
raise LLVM.string_and_dispose(error)
end
diff --git a/src/llvm/lib_llvm_ext.cr b/src/llvm/lib_llvm_ext.cr
index b7bae30dcd4..7c29cf3f6c2 100644
--- a/src/llvm/lib_llvm_ext.cr
+++ b/src/llvm/lib_llvm_ext.cr
@@ -162,4 +162,7 @@ lib LibLLVMExt
fun normalize_target_triple = LLVMExtNormalizeTargetTriple(triple : Char*) : Char*
fun basic_block_name = LLVMExtBasicBlockName(basic_block : LibLLVM::BasicBlockRef) : Char*
fun di_builder_get_or_create_array_subrange = LLVMExtDIBuilderGetOrCreateArraySubrange(builder : DIBuilder, lo : UInt64, count : UInt64) : Metadata
+
+ fun target_machine_enable_global_isel = LLVMExtTargetMachineEnableGlobalIsel(machine : LibLLVM::TargetMachineRef, enable : Bool)
+ fun create_mc_jit_compiler_for_module = LLVMExtCreateMCJITCompilerForModule(jit : LibLLVM::ExecutionEngineRef*, m : LibLLVM::ModuleRef, options : LibLLVM::JITCompilerOptions*, options_length : UInt32, enable_global_isel : Bool, error : UInt8**) : Int32
end
diff --git a/src/llvm/target_machine.cr b/src/llvm/target_machine.cr
index e9c8b793aa7..a0583d16586 100644
--- a/src/llvm/target_machine.cr
+++ b/src/llvm/target_machine.cr
@@ -32,6 +32,10 @@ class LLVM::TargetMachine
emit_to_file llvm_mod, filename, LLVM::CodeGenFileType::AssemblyFile
end
+ def enable_global_isel=(enable : Bool)
+ LibLLVMExt.target_machine_enable_global_isel(self, enable)
+ end
+
private def emit_to_file(llvm_mod, filename, type)
status = LibLLVM.target_machine_emit_to_file(self, llvm_mod, filename, type, out error_msg)
unless status == 0
From 759f6a35cafd3aaad5cc290ee085918ebf400058 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonne=20Ha=C3=9F?= <me@jhass.eu>
Date: Thu, 4 Jun 2020 14:27:40 +0200
Subject: [PATCH] Fix VaList and disable va_arg for AArch64
va_arg is broken on most platforms, including AArch64
---
spec/compiler/codegen/primitives_spec.cr | 50 +++++++++----------
spec/spec_helper.cr | 6 +--
spec/std/spec_helper.cr | 11 ++++
spec/std/va_list_spec.cr | 40 +++++++++++++++
spec/support/tempfile.cr | 10 ++++
spec/win32_std_spec.cr | 1 +
src/compiler/crystal/semantic/main_visitor.cr | 3 --
src/lib_c/aarch64-linux-gnu/c/stdarg.cr | 9 +++-
src/lib_c/aarch64-linux-musl/c/stdarg.cr | 14 +++---
src/va_list.cr | 12 ++++-
10 files changed, 114 insertions(+), 42 deletions(-)
create mode 100644 spec/std/va_list_spec.cr
diff --git a/spec/compiler/codegen/primitives_spec.cr b/spec/compiler/codegen/primitives_spec.cr
index 20e768e6608..7d6fba92ec3 100644
--- a/spec/compiler/codegen/primitives_spec.cr
+++ b/spec/compiler/codegen/primitives_spec.cr
@@ -239,8 +239,8 @@ describe "Code gen: primitives" do
end
describe "va_arg" do
- # On Windows llvm's va_arg instruction works incorrectly.
- {% unless flag?(:win32) %}
+ # On Windows and AArch64 llvm's va_arg instruction works incorrectly.
+ {% unless flag?(:win32) || flag?(:aarch64) %}
it "uses llvm's va_arg instruction" do
mod = codegen(%(
struct VaList
@@ -255,33 +255,33 @@ describe "Code gen: primitives" do
str = mod.to_s
str.should contain("va_arg %VaList* %list")
end
- {% end %}
- pending_win32 "works with C code" do
- test_c(
- %(
- extern int foo_f(int,...);
- int foo() {
- return foo_f(3,1,2,3);
- }
- ),
- %(
- lib LibFoo
- fun foo() : LibC::Int
- end
+ it "works with C code" do
+ test_c(
+ %(
+ extern int foo_f(int,...);
+ int foo() {
+ return foo_f(3,1,2,3);
+ }
+ ),
+ %(
+ lib LibFoo
+ fun foo() : LibC::Int
+ end
- fun foo_f(count : Int32, ...) : LibC::Int
- sum = 0
- VaList.open do |list|
- count.times do |i|
- sum += list.next(Int32)
+ fun foo_f(count : Int32, ...) : LibC::Int
+ sum = 0
+ VaList.open do |list|
+ count.times do |i|
+ sum += list.next(Int32)
+ end
end
+ sum
end
- sum
- end
- LibFoo.foo
- ), &.to_i.should eq(6))
- end
+ LibFoo.foo
+ ), &.to_i.should eq(6))
+ end
+ {% end %}
end
end
diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr
index 0a67b2f9f80..ee121a3a603 100644
--- a/spec/spec_helper.cr
+++ b/spec/spec_helper.cr
@@ -257,11 +257,7 @@ def run(code, filename = nil, inject_primitives = true, debug = Crystal::Debug::
end
def test_c(c_code, crystal_code, *, file = __FILE__)
- with_tempfile("temp_abi.c", "temp_abi.o", file: file) do |c_filename, o_filename|
- File.write(c_filename, c_code)
-
- `#{Crystal::Compiler::CC} #{Process.quote(c_filename)} -c -o #{Process.quote(o_filename)}`.should be_truthy
-
+ with_temp_c_object_file(c_code, file: file) do |o_filename|
yield run(%(
require "prelude"
diff --git a/spec/std/spec_helper.cr b/spec/std/spec_helper.cr
index b8759032724..943c90a9bde 100644
--- a/spec/std/spec_helper.cr
+++ b/spec/std/spec_helper.cr
@@ -108,3 +108,14 @@ def compile_and_run_source(source, flags = %w(--debug), file = __FILE__)
compile_and_run_file(source_file, flags, file: file)
end
end
+
+def compile_and_run_source_with_c(c_code, crystal_code, flags = %w(--debug), file = __FILE__)
+ with_temp_c_object_file(c_code, file: file) do |o_filename|
+ yield compile_and_run_source(%(
+ require "prelude"
+
+ @[Link(ldflags: #{o_filename.inspect})]
+ #{crystal_code}
+ ))
+ end
+end
diff --git a/spec/std/va_list_spec.cr b/spec/std/va_list_spec.cr
new file mode 100644
index 00000000000..79347c0638f
--- /dev/null
+++ b/spec/std/va_list_spec.cr
@@ -0,0 +1,40 @@
+require "./spec_helper"
+
+describe VaList do
+ it "works with C code" do
+ compile_and_run_source_with_c(
+ %(
+ #include <stdarg.h>
+ extern int foo_f(int,...);
+ int foo() {
+ return foo_f(3,1,2,3);
+ }
+
+ int read_arg(va_list *ap) {
+ return va_arg(*ap, int);
+ }
+ ),
+ %(
+ lib LibFoo
+ fun foo : LibC::Int
+ fun read_arg(ap : LibC::VaList*) : LibC::Int
+ end
+
+ fun foo_f(count : LibC::Int, ...) : LibC::Int
+ sum = 0
+ VaList.open do |list|
+ ap = list.to_unsafe
+ count.times do |i|
+ sum += LibFoo.read_arg(pointerof(ap))
+ end
+ end
+ sum
+ end
+
+ puts LibFoo.foo
+ )) do |status, output|
+ status.success?.should be_true
+ output.to_i.should eq(6)
+ end
+ end
+end
diff --git a/spec/support/tempfile.cr b/spec/support/tempfile.cr
index 0c47ee765e9..42001785d1c 100644
--- a/spec/support/tempfile.cr
+++ b/spec/support/tempfile.cr
@@ -43,6 +43,16 @@ def with_temp_executable(name, file = __FILE__)
end
end
+def with_temp_c_object_file(c_code, file = __FILE__)
+ with_tempfile("temp_c.c", "temp_c.o", file: file) do |c_filename, o_filename|
+ File.write(c_filename, c_code)
+
+ `#{ENV["CC"]? || "cc"} #{Process.quote(c_filename)} -c -o #{Process.quote(o_filename)}`.should be_truthy
+
+ yield o_filename
+ end
+end
+
if SPEC_TEMPFILE_CLEANUP
at_exit do
FileUtils.rm_r(SPEC_TEMPFILE_PATH) if Dir.exists?(SPEC_TEMPFILE_PATH)
diff --git a/spec/win32_std_spec.cr b/spec/win32_std_spec.cr
index dbf3f13c8a0..2bc3be97806 100644
--- a/spec/win32_std_spec.cr
+++ b/spec/win32_std_spec.cr
@@ -221,6 +221,7 @@ require "./std/uint_spec.cr"
require "./std/uri/punycode_spec.cr"
require "./std/uri_spec.cr"
require "./std/uuid_spec.cr"
+# require "./std/va_list_spec.cr"
require "./std/weak_ref_spec.cr"
require "./std/xml/builder_spec.cr"
require "./std/xml/html_spec.cr"
diff --git a/src/compiler/crystal/semantic/main_visitor.cr b/src/compiler/crystal/semantic/main_visitor.cr
index a4cff837c39..c6b4ec4009c 100644
--- a/src/compiler/crystal/semantic/main_visitor.cr
+++ b/src/compiler/crystal/semantic/main_visitor.cr
@@ -2431,9 +2431,6 @@ module Crystal
end
def visit_va_arg(node)
- if program.has_flag? "windows"
- node.raise "va_arg is not yet supported on Windows"
- end
arg = call.not_nil!.args[0]? || node.raise("requires type argument")
node.type = arg.type.instance_type
end
diff --git a/src/lib_c/aarch64-linux-gnu/c/stdarg.cr b/src/lib_c/aarch64-linux-gnu/c/stdarg.cr
index 882d4f51d35..965355556d7 100644
--- a/src/lib_c/aarch64-linux-gnu/c/stdarg.cr
+++ b/src/lib_c/aarch64-linux-gnu/c/stdarg.cr
@@ -1,3 +1,10 @@
lib LibC
- type VaList = Void*
+ # based on https://github.com/llvm/llvm-project/blob/bf1cdc2c6c0460b7121ac653c796ef4995b1dfa9/clang/lib/AST/ASTContext.cpp#L7678-L7739
+ struct VaList
+ __stack : Void*
+ __gr_top : Void*
+ __vr_top : Void*
+ __gr_offs : Int32
+ __vr_offs : Int32
+ end
end
diff --git a/src/lib_c/aarch64-linux-musl/c/stdarg.cr b/src/lib_c/aarch64-linux-musl/c/stdarg.cr
index fcad7714f16..965355556d7 100644
--- a/src/lib_c/aarch64-linux-musl/c/stdarg.cr
+++ b/src/lib_c/aarch64-linux-musl/c/stdarg.cr
@@ -1,10 +1,10 @@
lib LibC
- struct VaListTag
- gp_offset : UInt
- fp_offset : UInt
- overflow_arg_area : Void*
- reg_save_area : Void*
+ # based on https://github.com/llvm/llvm-project/blob/bf1cdc2c6c0460b7121ac653c796ef4995b1dfa9/clang/lib/AST/ASTContext.cpp#L7678-L7739
+ struct VaList
+ __stack : Void*
+ __gr_top : Void*
+ __vr_top : Void*
+ __gr_offs : Int32
+ __vr_offs : Int32
end
-
- type VaList = VaListTag[1]
end
diff --git a/src/va_list.cr b/src/va_list.cr
index eb0d0121f61..b24304c32e4 100644
--- a/src/va_list.cr
+++ b/src/va_list.cr
@@ -18,7 +18,17 @@ struct VaList
end
end
- {% if compare_versions(Crystal::VERSION, "0.33.0-0") > 0 %}
+ {% if flag?(:aarch64) || flag?(:win32) %}
+ {% platform = flag?(:aarch64) ? "AArch64" : "Windows" %}
+ {% clang_impl = flag?(:aarch64) ? "https://github.com/llvm/llvm-project/blob/a574edbba2b24fcfb733aa2d82308131f5b7d2d6/clang/lib/CodeGen/TargetInfo.cpp#L5677-L5921" : "https://github.com/llvm/llvm-project/blob/a574edbba2b24fcfb733aa2d82308131f5b7d2d6/clang/lib/CodeGen/TargetInfo.cpp#L5958-L5964" %}
+ # Do not call this, instead use C wrappers calling the va_arg macro for the types you need.
+ #
+ # Clang implements va_arg on {{platform.id}} like this: {{clang_impl.id}}
+ # If somebody wants to fix the LLVM IR va_arg instruction on {{platform}} upstream, or port the above here, that would be welcome.
+ def next(type)
+ \{% raise "Cannot get variadic argument on {{platform.id}}. As a workaround implement wrappers in C calling the va_arg macro for the types you need and bind to those." %}
+ end
+ {% else %}
@[Primitive(:va_arg)]
def next(type)
end
Markdown is supported