Skip to content

Commit 8364948

Browse files
committed
Add basic GCC support
If lacking musttail attribute it likely never performs TCO in Debug
1 parent 58a09f4 commit 8364948

File tree

21 files changed

+203
-118
lines changed

21 files changed

+203
-118
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ jobs:
99
matrix:
1010
image:
1111
- "clang:13"
12+
- "gcc:11"
1213
build_type: [Debug, Release]
1314

1415
runs-on: ubuntu-latest

include/lauf/asm/builder.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,3 @@ void lauf_asm_inst_store_field(lauf_asm_builder* b, lauf_asm_type type, size_t f
308308
LAUF_HEADER_END
309309

310310
#endif // LAUF_ASM_BUILDER_H_INCLUDED
311-

include/lauf/asm/module.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,3 @@ bool lauf_asm_chunk_is_empty(const lauf_asm_chunk* chunk);
156156
LAUF_HEADER_END
157157

158158
#endif // LAUF_ASM_MODULE_H_INCLUDED
159-

include/lauf/config.h

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,44 @@ typedef uint64_t lauf_uint;
3636
# error "lauf assumes 8 bit bytes"
3737
#endif
3838

39-
#if !defined(__clang__)
40-
# error "lauf currently requires clang"
41-
#endif
42-
4339
//=== optimizations ===//
44-
#define LAUF_LIKELY(Cond) __builtin_expect((Cond), 1)
45-
#define LAUF_UNLIKELY(Cond) __builtin_expect((Cond), 0)
46-
#define LAUF_TAIL_CALL [[clang::musttail]]
47-
#define LAUF_NOINLINE [[gnu::noinline]]
48-
#define LAUF_FORCE_INLINE [[gnu::always_inline]]
49-
#define LAUF_UNREACHABLE __builtin_unreachable()
40+
#if defined(__GNUC__) || defined(__GNUG__)
41+
# define LAUF_LIKELY(Cond) __builtin_expect((Cond), 1)
42+
# define LAUF_UNLIKELY(Cond) __builtin_expect((Cond), 0)
43+
# if defined(__has_cpp_attribute)
44+
# if __has_cpp_attribute(clang::musttail)
45+
# define LAUF_TAIL_CALL [[clang::musttail]]
46+
# elif defined(__clang__)
47+
# define LAUF_TAIL_CALL [[clang::musttail]]
48+
# else
49+
# define LAUF_TAIL_CALL
50+
# endif
51+
# endif
52+
# define LAUF_NOINLINE [[gnu::noinline]]
53+
# define LAUF_FORCE_INLINE [[gnu::always_inline]] inline
54+
# define LAUF_UNREACHABLE __builtin_unreachable()
55+
#endif
5056

5157
//=== configurations ===//
5258
#ifndef LAUF_CONFIG_DISPATCH_JUMP_TABLE
5359
# define LAUF_CONFIG_DISPATCH_JUMP_TABLE 1
5460
#endif
5561

56-
#endif // LAUF_CONFIG_H_INCLUDED
62+
#if defined(__has_cpp_attribute)
63+
# if __has_cpp_attribute(clang::musttail)
64+
# define LAUF_HAS_TAIL_CALL_ELIMINATION 1
65+
# endif
66+
#endif
5767

68+
//=== warnings ===//
69+
#if !defined(__clang__) && (defined(__GNUC__) || defined(__GNUG__))
70+
# define LAUF_BITFIELD_CONVERSION(...) \
71+
_Pragma("GCC diagnostic push"); \
72+
_Pragma("GCC diagnostic ignored \"-Wconversion\""); \
73+
__VA_ARGS__; \
74+
_Pragma("GCC diagnostic pop")
75+
#else
76+
# define LAUF_BITFIELD_CONVERSION(...) __VA_ARGS__
77+
#endif
78+
79+
#endif // LAUF_CONFIG_H_INCLUDED

include/lauf/runtime/builtin.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,17 @@
88

99
LAUF_HEADER_START
1010

11-
#define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section("text.lauf_builtin"), aligned(8)))
11+
#if defined(__clang__)
12+
# if defined(__APPLE__) && defined(__MACH__)
13+
# define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section(".text,lauf_builtin"), aligned(8)))
14+
# else
15+
# define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section("text.lauf_builtin"), aligned(8)))
16+
# endif
17+
#elif defined(__GNUC__) || defined(__GNUG__)
18+
# define LAUF_RUNTIME_BUILTIN_IMPL __attribute__((section(".text.lauf_builtin"), aligned(8)))
19+
#else
20+
# define LAUF_RUNTIME_BUILTIN_IMPL
21+
#endif
1222

1323
typedef union lauf_asm_inst lauf_asm_inst;
1424
typedef struct lauf_asm_type lauf_asm_type;
@@ -92,4 +102,3 @@ typedef struct lauf_runtime_builtin_library
92102
LAUF_HEADER_END
93103

94104
#endif // LAUF_RUNTIME_BUILTIN_H_INCLUDED
95-

src/lauf/asm/builder.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (C) 2022-2023 Jonathan Müller and lauf contributors
22
// SPDX-License-Identifier: BSL-1.0
33

4+
#include <algorithm>
45
#include <lauf/asm/builder.hpp>
56

67
#include <cstdio>
@@ -372,7 +373,7 @@ LAUF_NOINLINE lauf_asm_inst* emit_body(lauf_asm_inst* ip, lauf_asm_builder* b,
372373
assert(insts[dest->offset].op() == lauf::asm_op::block);
373374
auto dest_offset = dest->offset + 1;
374375

375-
jump->jump.offset = std::int32_t(dest_offset - cur_offset);
376+
LAUF_BITFIELD_CONVERSION(jump->jump.offset = std::int32_t(dest_offset - cur_offset));
376377
}
377378

378379
return ip;
@@ -437,7 +438,7 @@ void emit_debug_location(lauf_asm_builder* b)
437438
for (auto loc : block.debug_locations)
438439
{
439440
// We also have the initial block instruction that affects the inst_idx.
440-
loc.inst_idx += block.offset + 1;
441+
loc.inst_idx += static_cast<uint16_t>(block.offset + 1);
441442
cont.push_back(arena, loc);
442443
}
443444
}
@@ -489,8 +490,7 @@ bool lauf_asm_build_finish(lauf_asm_builder* b)
489490
auto result = std::size_t(0);
490491

491492
for (auto& block : b->blocks)
492-
if (block.vstack.max_size() > result)
493-
result = block.vstack.max_size();
493+
result = std::max(block.vstack.max_size(), result);
494494

495495
if (result > UINT16_MAX)
496496
b->error(context, "per-function vstack size limit exceeded");
@@ -541,7 +541,7 @@ lauf_asm_local* lauf_asm_build_local(lauf_asm_builder* b, lauf_asm_layout layout
541541

542542
// The offset is the current size, we don't need to worry about alignment.
543543
offset = std::uint16_t(b->local_allocation_size + sizeof(lauf_runtime_stack_frame));
544-
b->local_allocation_size += layout.size;
544+
b->local_allocation_size += static_cast<uint16_t>(layout.size);
545545
}
546546
else
547547
{
@@ -553,7 +553,7 @@ lauf_asm_local* lauf_asm_build_local(lauf_asm_builder* b, lauf_asm_layout layout
553553
// for a pointer.
554554
// Since `layout.alignment` is a multiple of it (as a power of two bigger than it), and
555555
// size a multiple of alignment, `layout.alignment + layout.size` is as well.
556-
b->local_allocation_size += layout.alignment + layout.size;
556+
b->local_allocation_size += static_cast<uint16_t>(layout.alignment + layout.size);
557557
// Since we don't know the exact alignment offset, we can't compute it statically.
558558
offset = UINT16_MAX;
559559
}
@@ -708,6 +708,8 @@ const lauf_asm_block* lauf_asm_inst_branch(lauf_asm_builder* b, const lauf_asm_b
708708
b->cur->next[0] = if_false;
709709
b->cur->next[1] = if_true;
710710
break;
711+
default:
712+
LAUF_UNREACHABLE;
711713
}
712714
}
713715
else
@@ -1006,7 +1008,7 @@ void lauf_asm_inst_global_addr(lauf_asm_builder* b, const lauf_asm_global* globa
10061008
b->cur->insts.push_back(*b, LAUF_BUILD_INST_VALUE(global_addr, global->allocation_idx));
10071009
b->cur->vstack.push_constant(*b, [&] {
10081010
lauf_runtime_value result;
1009-
result.as_address.allocation = global->allocation_idx;
1011+
LAUF_BITFIELD_CONVERSION(result.as_address.allocation = global->allocation_idx);
10101012
result.as_address.offset = 0;
10111013
result.as_address.generation = 0; // Always true for globals.
10121014
return result;
@@ -1240,7 +1242,7 @@ void lauf_asm_inst_aggregate_member(lauf_asm_builder* b, size_t member_index,
12401242

12411243
namespace
12421244
{
1243-
enum load_store_constant
1245+
enum load_store_constant : uint8_t
12441246
{
12451247
load_store_dynamic,
12461248
load_store_local,
@@ -1381,4 +1383,3 @@ void lauf_asm_inst_store_field(lauf_asm_builder* b, lauf_asm_type type, size_t f
13811383
lauf_asm_inst_call_builtin(b, builtin);
13821384
}
13831385
}
1384-

src/lauf/asm/builder.hpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#ifndef SRC_LAUF_ASM_BUILDER_HPP_INCLUDED
55
#define SRC_LAUF_ASM_BUILDER_HPP_INCLUDED
66

7+
#include <algorithm>
78
#include <lauf/asm/builder.h>
89
#include <lauf/asm/instruction.hpp>
910
#include <lauf/asm/module.hpp>
@@ -32,7 +33,7 @@ class builder_vstack
3233
public:
3334
struct value
3435
{
35-
enum type_t
36+
enum type_t : uint8_t
3637
{
3738
unknown,
3839
constant,
@@ -66,8 +67,7 @@ class builder_vstack
6667
void push(arena_base& arena, value v)
6768
{
6869
_stack.push_back(arena, v);
69-
if (size() > _max)
70-
_max = size();
70+
_max = std::max(size(), _max);
7171
}
7272
void push_output(arena_base& arena, std::size_t n)
7373
{
@@ -176,7 +176,7 @@ struct lauf_asm_block
176176
lauf::array_list<lauf_asm_inst> insts;
177177
lauf::array_list<lauf::inst_debug_location> debug_locations;
178178

179-
enum
179+
enum : uint8_t
180180
{
181181
unterminated,
182182
terminated,
@@ -262,14 +262,14 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
262262
{ \
263263
if (LAUF_UNLIKELY(!(Cond))) \
264264
b->error(LAUF_BUILD_ASSERT_CONTEXT, Msg); \
265-
} while (0)
265+
} while (false)
266266

267267
#define LAUF_BUILD_CHECK_CUR \
268268
do \
269269
{ \
270270
if (LAUF_UNLIKELY(b->cur == nullptr)) \
271271
return; \
272-
} while (0)
272+
} while (false)
273273

274274
//=== instruction building ===//
275275
#define LAUF_BUILD_INST_NONE(Name) \
@@ -282,7 +282,7 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
282282
#define LAUF_BUILD_INST_OFFSET(Name, Offset) \
283283
[&](const char* context, std::ptrdiff_t offset) { \
284284
lauf_asm_inst result; \
285-
result.Name = {lauf::asm_op::Name, std::int32_t(offset)}; \
285+
LAUF_BITFIELD_CONVERSION(result.Name = {lauf::asm_op::Name, std::int32_t(offset)}); \
286286
if (result.Name.offset != offset) \
287287
b->error(context, "offset too big"); \
288288
return result; \
@@ -315,7 +315,7 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
315315
#define LAUF_BUILD_INST_VALUE(Name, Value) \
316316
[&](const char* context, std::size_t value) { \
317317
lauf_asm_inst result; \
318-
result.Name = {lauf::asm_op::Name, std::uint32_t(value)}; \
318+
LAUF_BITFIELD_CONVERSION(result.Name = {lauf::asm_op::Name, std::uint32_t(value)}); \
319319
if (value != result.Name.value) \
320320
b->error(context, "invalid value"); \
321321
return result; \
@@ -331,4 +331,3 @@ struct lauf_asm_builder : lauf::intrinsic_arena<lauf_asm_builder>
331331
}(LAUF_BUILD_ASSERT_CONTEXT, Index)
332332

333333
#endif // SRC_LAUF_ASM_BUILDER_HPP_INCLUDED
334-

src/lauf/backend/qbe.hpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515

1616
namespace lauf
1717
{
18-
enum class qbe_type
18+
enum class qbe_type : uint8_t
1919
{
20-
word,
21-
long_,
22-
single,
23-
double_,
24-
byte,
25-
halfword,
20+
word = 0,
21+
long_ = 1,
22+
single = 2,
23+
double_ = 3,
24+
byte = 4,
25+
halfword = 5,
2626

2727
value = long_,
2828
};
@@ -62,7 +62,7 @@ enum class qbe_block : std::size_t
6262
{
6363
};
6464

65-
enum class qbe_cc
65+
enum class qbe_cc : uint8_t
6666
{
6767
ieq,
6868
ine,
@@ -426,6 +426,7 @@ class qbe_writer
426426
case qbe_type::halfword:
427427
return "h";
428428
}
429+
LAUF_UNREACHABLE;
429430
}
430431

431432
const char* cc_name(qbe_cc cc)
@@ -453,6 +454,7 @@ class qbe_writer
453454
case qbe_cc::ugt:
454455
return "ugt";
455456
}
457+
LAUF_UNREACHABLE;
456458
}
457459

458460
lauf_writer* _writer;
@@ -462,4 +464,3 @@ class qbe_writer
462464
} // namespace lauf
463465

464466
#endif // SRC_LAUF_BACKEND_QBE_HPP_INCLUDED
465-

0 commit comments

Comments
 (0)