Skip to content

Commit 48e9289

Browse files
authored
Basic support for Win64 C lib ABI (#9387)
* Split general ABI specs from x86_64-specific ones, run on every platform To confirm that the newly added file only moves things: $ git diff -w HEAD~:spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr spec/compiler/codegen/c_abi/c_abi_spec.cr * Implement basics of Win64 lib ABI Also un-does #5851
1 parent df026e1 commit 48e9289

File tree

10 files changed

+58
-25
lines changed

10 files changed

+58
-25
lines changed

spec/compiler/codegen/c_abi/c_abi_spec.cr

+8-8
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ describe "Code gen: C ABI" do
3232
test_c(
3333
%(
3434
struct s {
35-
long x;
35+
long long x;
3636
short y;
3737
};
3838
39-
long foo(struct s a) {
39+
long long foo(struct s a) {
4040
return a.x + a.y;
4141
}
4242
),
@@ -59,12 +59,12 @@ describe "Code gen: C ABI" do
5959
test_c(
6060
%(
6161
struct s {
62-
long x;
63-
long y;
62+
long long x;
63+
long long y;
6464
char z;
6565
};
6666
67-
long foo(struct s a) {
67+
long long foo(struct s a) {
6868
return a.x + a.y + a.z;
6969
}
7070
),
@@ -116,7 +116,7 @@ describe "Code gen: C ABI" do
116116
test_c(
117117
%(
118118
struct s {
119-
long x;
119+
long long x;
120120
short y;
121121
};
122122
@@ -144,8 +144,8 @@ describe "Code gen: C ABI" do
144144
test_c(
145145
%(
146146
struct s {
147-
long x;
148-
long y;
147+
long long x;
148+
long long y;
149149
char z;
150150
};
151151

spec/compiler/codegen/c_abi/c_abi_x86_64_spec.cr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require "../../../spec_helper"
22

3-
{% if flag?(:x86_64) %}
3+
{% if flag?(:x86_64) && !flag?(:win32) %}
44
describe "Code gen: C ABI x86_64" do
55
it "passes struct less than 64 bits as { i64 }" do
66
mod = codegen(%(

spec/compiler/codegen/extern_spec.cr

+3-3
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,9 @@ describe "Codegen: extern struct" do
431431
test_c(
432432
%(
433433
struct Struct {
434-
long x;
435-
long y;
436-
long z;
434+
long long x;
435+
long long y;
436+
long long z;
437437
};
438438
439439
struct Struct foo(struct Struct (*callback)(struct Struct)) {

spec/compiler/codegen/primitives_spec.cr

+16-13
Original file line numberDiff line numberDiff line change
@@ -239,22 +239,25 @@ describe "Code gen: primitives" do
239239
end
240240

241241
describe "va_arg" do
242-
it "uses llvm's va_arg instruction" do
243-
mod = codegen(%(
244-
struct VaList
245-
@[Primitive(:va_arg)]
246-
def next(type)
242+
# On Windows llvm's va_arg instruction works incorrectly.
243+
{% unless flag?(:win32) %}
244+
it "uses llvm's va_arg instruction" do
245+
mod = codegen(%(
246+
struct VaList
247+
@[Primitive(:va_arg)]
248+
def next(type)
249+
end
247250
end
248-
end
249251
250-
list = VaList.new
251-
list.next(Int32)
252-
))
253-
str = mod.to_s
254-
str.should contain("va_arg %VaList* %list")
255-
end
252+
list = VaList.new
253+
list.next(Int32)
254+
))
255+
str = mod.to_s
256+
str.should contain("va_arg %VaList* %list")
257+
end
258+
{% end %}
256259

257-
it "works with C code" do
260+
pending_win32 "works with C code" do
258261
test_c(
259262
%(
260263
extern int foo_f(int,...);

src/compiler/crystal/semantic/main_visitor.cr

+3
Original file line numberDiff line numberDiff line change
@@ -2431,6 +2431,9 @@ module Crystal
24312431
end
24322432

24332433
def visit_va_arg(node)
2434+
if program.has_flag? "windows"
2435+
node.raise "va_arg is not yet supported on Windows"
2436+
end
24342437
arg = call.not_nil!.args[0]? || node.raise("requires type argument")
24352438
node.type = arg.type.instance_type
24362439
end

src/llvm/abi.cr

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Based on https://github.com/rust-lang/rust/blob/29ac04402d53d358a1f6200bea45a301ff05b2d1/src/librustc_trans/trans/cabi.rs
12
abstract class LLVM::ABI
23
getter target_data : TargetData
34
getter? osx : Bool

src/llvm/abi/x86.cr

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require "../abi"
22

3+
# Based on https://github.com/rust-lang/rust/blob/29ac04402d53d358a1f6200bea45a301ff05b2d1/src/librustc_trans/trans/cabi_x86.rs
34
class LLVM::ABI::X86 < LLVM::ABI
45
def abi_info(atys : Array(Type), rty : Type, ret_def : Bool, context : Context)
56
ret_ty = compute_return_type(rty, ret_def, context)

src/llvm/abi/x86_64.cr

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require "../abi"
22

3+
# Based on https://github.com/rust-lang/rust/blob/29ac04402d53d358a1f6200bea45a301ff05b2d1/src/librustc_trans/trans/cabi_x86_64.rs
34
class LLVM::ABI::X86_64 < LLVM::ABI
45
def abi_info(atys : Array(Type), rty : Type, ret_def : Bool, context : Context)
56
arg_tys = Array(LLVM::Type).new(atys.size)

src/llvm/abi/x86_win64.cr

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require "../abi"
2+
3+
# Based on https://github.com/rust-lang/rust/blob/29ac04402d53d358a1f6200bea45a301ff05b2d1/src/librustc_trans/trans/cabi_x86_win64.rs
4+
class LLVM::ABI::X86_Win64 < LLVM::ABI::X86
5+
private def compute_arg_types(atys, context)
6+
atys.map do |t|
7+
case t.kind
8+
when Type::Kind::Struct
9+
size = target_data.abi_size(t)
10+
case size
11+
when 1 then ArgType.direct(t, context.int8)
12+
when 2 then ArgType.direct(t, context.int16)
13+
when 4 then ArgType.direct(t, context.int32)
14+
when 8 then ArgType.direct(t, context.int64)
15+
else ArgType.indirect(t, LLVM::Attribute::ByVal)
16+
end
17+
else
18+
non_struct(t, context)
19+
end
20+
end
21+
end
22+
end

src/llvm/target_machine.cr

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class LLVM::TargetMachine
4343
def abi
4444
triple = self.triple
4545
case triple
46+
when /x86_64.+windows-msvc/
47+
ABI::X86_Win64.new(self)
4648
when /x86_64|amd64/
4749
ABI::X86_64.new(self)
4850
when /i386|i486|i586|i686/

0 commit comments

Comments
 (0)