Skip to content

Commit f5f7a78

Browse files
aykevldeadprogram
authored andcommitted
compiler: add min and max builtin support
1 parent d42d49b commit f5f7a78

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed

compiler/compiler.go

+18
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,24 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
16371637
llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int")
16381638
}
16391639
return llvmLen, nil
1640+
case "min", "max":
1641+
// min and max builtins, added in Go 1.21.
1642+
// We can simply reuse the existing binop comparison code, which has all
1643+
// the edge cases figured out already.
1644+
tok := token.LSS
1645+
if callName == "max" {
1646+
tok = token.GTR
1647+
}
1648+
result := argValues[0]
1649+
typ := argTypes[0]
1650+
for _, arg := range argValues[1:] {
1651+
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
1652+
if err != nil {
1653+
return result, err
1654+
}
1655+
result = b.CreateSelect(cmp, result, arg, "")
1656+
}
1657+
return result, nil
16401658
case "print", "println":
16411659
for i, value := range argValues {
16421660
if i >= 1 && callName == "println" {

compiler/compiler_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ func TestCompiler(t *testing.T) {
5454
if goMinor >= 20 {
5555
tests = append(tests, testCase{"go1.20.go", "", ""})
5656
}
57+
if goMinor >= 21 {
58+
tests = append(tests, testCase{"go1.21.go", "", ""})
59+
}
5760

5861
for _, tc := range tests {
5962
name := tc.file

compiler/testdata/go1.21.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package main
2+
3+
func min1(a int) int {
4+
return min(a)
5+
}
6+
7+
func min2(a, b int) int {
8+
return min(a, b)
9+
}
10+
11+
func min3(a, b, c int) int {
12+
return min(a, b, c)
13+
}
14+
15+
func min4(a, b, c, d int) int {
16+
return min(a, b, c, d)
17+
}
18+
19+
func minUint8(a, b uint8) uint8 {
20+
return min(a, b)
21+
}
22+
23+
func minUnsigned(a, b uint) uint {
24+
return min(a, b)
25+
}
26+
27+
func minFloat32(a, b float32) float32 {
28+
return min(a, b)
29+
}
30+
31+
func minFloat64(a, b float64) float64 {
32+
return min(a, b)
33+
}
34+
35+
func minString(a, b string) string {
36+
return min(a, b)
37+
}
38+
39+
func maxInt(a, b int) int {
40+
return max(a, b)
41+
}
42+
43+
func maxUint(a, b uint) uint {
44+
return max(a, b)
45+
}
46+
47+
func maxFloat32(a, b float32) float32 {
48+
return max(a, b)
49+
}
50+
51+
func maxString(a, b string) string {
52+
return max(a, b)
53+
}

compiler/testdata/go1.21.ll

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
; ModuleID = 'go1.21.go'
2+
source_filename = "go1.21.go"
3+
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
4+
target triple = "wasm32-unknown-wasi"
5+
6+
%runtime._string = type { ptr, i32 }
7+
8+
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
9+
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
10+
11+
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
12+
13+
; Function Attrs: nounwind
14+
define hidden void @main.init(ptr %context) unnamed_addr #2 {
15+
entry:
16+
ret void
17+
}
18+
19+
; Function Attrs: nounwind
20+
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
21+
entry:
22+
ret i32 %a
23+
}
24+
25+
; Function Attrs: nounwind
26+
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
27+
entry:
28+
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
29+
ret i32 %0
30+
}
31+
32+
; Function Attrs: nounwind
33+
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 {
34+
entry:
35+
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
36+
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
37+
ret i32 %1
38+
}
39+
40+
; Function Attrs: nounwind
41+
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
42+
entry:
43+
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
44+
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
45+
%2 = call i32 @llvm.smin.i32(i32 %1, i32 %d)
46+
ret i32 %2
47+
}
48+
49+
; Function Attrs: nounwind
50+
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
51+
entry:
52+
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
53+
ret i8 %0
54+
}
55+
56+
; Function Attrs: nounwind
57+
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
58+
entry:
59+
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
60+
ret i32 %0
61+
}
62+
63+
; Function Attrs: nounwind
64+
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
65+
entry:
66+
%0 = fcmp olt float %a, %b
67+
%1 = select i1 %0, float %a, float %b
68+
ret float %1
69+
}
70+
71+
; Function Attrs: nounwind
72+
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
73+
entry:
74+
%0 = fcmp olt double %a, %b
75+
%1 = select i1 %0, double %a, double %b
76+
ret double %1
77+
}
78+
79+
; Function Attrs: nounwind
80+
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
81+
entry:
82+
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
83+
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
84+
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
85+
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
86+
%stackalloc = alloca i8, align 1
87+
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #4
88+
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
89+
%6 = extractvalue %runtime._string %5, 0
90+
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4
91+
ret %runtime._string %5
92+
}
93+
94+
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
95+
96+
; Function Attrs: nounwind
97+
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
98+
entry:
99+
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
100+
ret i32 %0
101+
}
102+
103+
; Function Attrs: nounwind
104+
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
105+
entry:
106+
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
107+
ret i32 %0
108+
}
109+
110+
; Function Attrs: nounwind
111+
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
112+
entry:
113+
%0 = fcmp ogt float %a, %b
114+
%1 = select i1 %0, float %a, float %b
115+
ret float %1
116+
}
117+
118+
; Function Attrs: nounwind
119+
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
120+
entry:
121+
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
122+
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
123+
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
124+
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
125+
%stackalloc = alloca i8, align 1
126+
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #4
127+
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
128+
%6 = extractvalue %runtime._string %5, 0
129+
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #4
130+
ret %runtime._string %5
131+
}
132+
133+
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
134+
declare i32 @llvm.smin.i32(i32, i32) #3
135+
136+
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
137+
declare i8 @llvm.umin.i8(i8, i8) #3
138+
139+
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
140+
declare i32 @llvm.umin.i32(i32, i32) #3
141+
142+
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
143+
declare i32 @llvm.smax.i32(i32, i32) #3
144+
145+
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
146+
declare i32 @llvm.umax.i32(i32, i32) #3
147+
148+
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
149+
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
150+
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
151+
attributes #3 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
152+
attributes #4 = { nounwind }

0 commit comments

Comments
 (0)