Skip to content

Commit 4ed7442

Browse files
committed
stage1: implement @prefetch()
1 parent 38c6f67 commit 4ed7442

File tree

5 files changed

+198
-0
lines changed

5 files changed

+198
-0
lines changed

src/stage1/all_types.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,18 @@ struct AstNodeFnCallExpr {
898898
bool seen; // used by @compileLog
899899
};
900900

901+
// Must be kept in sync with std.builtin.PrefetchOptions.Rw
902+
enum PrefetchRw {
903+
PrefetchRwRead,
904+
PrefetchRwWrite,
905+
};
906+
907+
// Must be kept in sync with std.builtin.PrefetchOptions.Cache
908+
enum PrefetchCache {
909+
PrefetchCacheInstruction,
910+
PrefetchCacheData,
911+
};
912+
901913
struct AstNodeArrayAccessExpr {
902914
AstNode *array_ref_expr;
903915
AstNode *subscript;
@@ -1818,6 +1830,7 @@ enum BuiltinFnId {
18181830
BuiltinFnIdReduce,
18191831
BuiltinFnIdMaximum,
18201832
BuiltinFnIdMinimum,
1833+
BuiltinFnIdPrefetch,
18211834
};
18221835

18231836
struct BuiltinFnEntry {
@@ -2021,6 +2034,7 @@ struct CodeGen {
20212034
LLVMValueRef return_err_fn;
20222035
LLVMValueRef wasm_memory_size;
20232036
LLVMValueRef wasm_memory_grow;
2037+
LLVMValueRef prefetch;
20242038
LLVMTypeRef anyframe_fn_type;
20252039

20262040
// reminder: hash tables must be initialized before use
@@ -2647,6 +2661,7 @@ enum Stage1ZirInstId : uint8_t {
26472661
Stage1ZirInstIdWasmMemorySize,
26482662
Stage1ZirInstIdWasmMemoryGrow,
26492663
Stage1ZirInstIdSrc,
2664+
Stage1ZirInstIdPrefetch,
26502665
};
26512666

26522667
// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
@@ -2743,6 +2758,7 @@ enum Stage1AirInstId : uint8_t {
27432758
Stage1AirInstIdWasmMemorySize,
27442759
Stage1AirInstIdWasmMemoryGrow,
27452760
Stage1AirInstIdExtern,
2761+
Stage1AirInstIdPrefetch,
27462762
};
27472763

27482764
struct Stage1ZirInst {
@@ -3683,6 +3699,24 @@ struct Stage1ZirInstSrc {
36833699
Stage1ZirInst base;
36843700
};
36853701

3702+
struct Stage1ZirInstPrefetch {
3703+
Stage1ZirInst base;
3704+
3705+
Stage1ZirInst *ptr;
3706+
Stage1ZirInst *options;
3707+
};
3708+
3709+
struct Stage1AirInstPrefetch {
3710+
Stage1AirInst base;
3711+
3712+
Stage1AirInst *ptr;
3713+
PrefetchRw rw;
3714+
// Must be in the range 0-3 inclusive
3715+
uint8_t locality;
3716+
PrefetchCache cache;
3717+
};
3718+
3719+
36863720
struct Stage1ZirInstSlice {
36873721
Stage1ZirInst base;
36883722

src/stage1/astgen.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) {
349349
return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstWasmMemoryGrow *>(inst));
350350
case Stage1ZirInstIdSrc:
351351
return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstSrc *>(inst));
352+
case Stage1ZirInstIdPrefetch:
353+
return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstPrefetch *>(inst));
352354
}
353355
zig_unreachable();
354356
}
@@ -941,6 +943,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSrc *) {
941943
return Stage1ZirInstIdSrc;
942944
}
943945

946+
static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) {
947+
return Stage1ZirInstIdPrefetch;
948+
}
949+
944950
template<typename T>
945951
static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {
946952
T *special_instruction = heap::c_allocator.create<T>();
@@ -2870,6 +2876,21 @@ static Stage1ZirInst *ir_build_src(Stage1AstGen *ag, Scope *scope, AstNode *sour
28702876
return &instruction->base;
28712877
}
28722878

2879+
static Stage1ZirInst *ir_build_prefetch(Stage1AstGen *ag, Scope *scope, AstNode *source_node,
2880+
Stage1ZirInst *ptr, Stage1ZirInst *options)
2881+
{
2882+
Stage1ZirInstPrefetch *prefetch_instruction = ir_build_instruction<Stage1ZirInstPrefetch>(
2883+
ag, scope, source_node);
2884+
prefetch_instruction->ptr = ptr;
2885+
prefetch_instruction->options = options;
2886+
2887+
ir_ref_instruction(ptr, ag->current_basic_block);
2888+
ir_ref_instruction(options, ag->current_basic_block);
2889+
2890+
return &prefetch_instruction->base;
2891+
}
2892+
2893+
28732894
static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, size_t *results) {
28742895
results[ReturnKindUnconditional] = 0;
28752896
results[ReturnKindError] = 0;
@@ -5416,6 +5437,29 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
54165437
Stage1ZirInst *src_inst = ir_build_src(ag, scope, node);
54175438
return ir_lval_wrap(ag, scope, src_inst, lval, result_loc);
54185439
}
5440+
case BuiltinFnIdPrefetch:
5441+
{
5442+
ZigType *options_type = get_builtin_type(ag->codegen, "PrefetchOptions");
5443+
Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type);
5444+
ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc());
5445+
5446+
AstNode *ptr_node = node->data.fn_call_expr.params.at(0);
5447+
Stage1ZirInst *ptr_value = astgen_node(ag, ptr_node, scope);
5448+
if (ptr_value == ag->codegen->invalid_inst_src)
5449+
return ptr_value;
5450+
5451+
AstNode *options_node = node->data.fn_call_expr.params.at(1);
5452+
Stage1ZirInst *options_value = astgen_node_extra(ag, options_node,
5453+
scope, LValNone, &result_loc_cast->base);
5454+
if (options_value == ag->codegen->invalid_inst_src)
5455+
return options_value;
5456+
5457+
Stage1ZirInst *casted_options_value = ir_build_implicit_cast(
5458+
ag, scope, options_node, options_value, result_loc_cast);
5459+
5460+
Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value);
5461+
return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc);
5462+
}
54195463
}
54205464
zig_unreachable();
54215465
}

src/stage1/codegen.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,24 @@ static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) {
11391139
return g->wasm_memory_grow;
11401140
}
11411141

1142+
static LLVMValueRef gen_prefetch(CodeGen *g) {
1143+
if (g->prefetch)
1144+
return g->prefetch;
1145+
1146+
// declare void @llvm.prefetch(i8*, i32, i32, i32)
1147+
LLVMTypeRef param_types[] = {
1148+
LLVMPointerType(LLVMInt8Type(), 0),
1149+
LLVMInt32Type(),
1150+
LLVMInt32Type(),
1151+
LLVMInt32Type(),
1152+
};
1153+
LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 4, false);
1154+
g->prefetch = LLVMAddFunction(g->module, "llvm.prefetch.p0i8", fn_type);
1155+
assert(LLVMGetIntrinsicID(g->prefetch));
1156+
1157+
return g->prefetch;
1158+
}
1159+
11421160
static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
11431161
if (g->stacksave_fn_val)
11441162
return g->stacksave_fn_val;
@@ -5899,6 +5917,27 @@ static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, Stage1Air *executable
58995917
return val;
59005918
}
59015919

5920+
static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1AirInstPrefetch *instruction) {
5921+
static_assert(PrefetchRwRead == 0);
5922+
static_assert(PrefetchRwWrite == 1);
5923+
assert(instruction->rw == PrefetchRwRead || instruction->rw == PrefetchRwWrite);
5924+
5925+
assert(instruction->locality >= 0 && instruction->locality <= 3);
5926+
5927+
static_assert(PrefetchCacheInstruction == 0);
5928+
static_assert(PrefetchCacheData == 1);
5929+
assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction);
5930+
5931+
LLVMValueRef params[] = {
5932+
LLVMBuildBitCast(g->builder, ir_llvm_value(g, instruction->ptr), LLVMPointerType(LLVMInt8Type(), 0), ""),
5933+
LLVMConstInt(LLVMInt32Type(), instruction->rw, false),
5934+
LLVMConstInt(LLVMInt32Type(), instruction->locality, false),
5935+
LLVMConstInt(LLVMInt32Type(), instruction->cache, false),
5936+
};
5937+
LLVMValueRef val = LLVMBuildCall(g->builder, gen_prefetch(g), params, 4, "");
5938+
return val;
5939+
}
5940+
59025941
static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) {
59035942
Error err;
59045943

@@ -7150,6 +7189,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Sta
71507189
return ir_render_wasm_memory_grow(g, executable, (Stage1AirInstWasmMemoryGrow *) instruction);
71517190
case Stage1AirInstIdExtern:
71527191
return ir_render_extern(g, executable, (Stage1AirInstExtern *) instruction);
7192+
case Stage1AirInstIdPrefetch:
7193+
return ir_render_prefetch(g, executable, (Stage1AirInstPrefetch *) instruction);
71537194
}
71547195
zig_unreachable();
71557196
}
@@ -9120,6 +9161,7 @@ static void define_builtin_fns(CodeGen *g) {
91209161
create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2);
91219162
create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);
91229163
create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);
9164+
create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2);
91239165
}
91249166

91259167
static const char *bool_to_str(bool b) {

src/stage1/ir.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,8 @@ void destroy_instruction_gen(Stage1AirInst *inst) {
467467
return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstWasmMemoryGrow *>(inst));
468468
case Stage1AirInstIdExtern:
469469
return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstExtern *>(inst));
470+
case Stage1AirInstIdPrefetch:
471+
return heap::c_allocator.destroy(reinterpret_cast<Stage1AirInstPrefetch *>(inst));
470472
}
471473
zig_unreachable();
472474
}
@@ -1115,6 +1117,10 @@ static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstExtern *) {
11151117
return Stage1AirInstIdExtern;
11161118
}
11171119

1120+
static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPrefetch *) {
1121+
return Stage1AirInstIdPrefetch;
1122+
}
1123+
11181124
template<typename T>
11191125
static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
11201126
T *special_instruction = heap::c_allocator.create<T>();
@@ -24775,6 +24781,52 @@ static Stage1AirInst *ir_analyze_instruction_src(IrAnalyze *ira, Stage1ZirInstSr
2477524781
return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, result);
2477624782
}
2477724783

24784+
static Stage1AirInst *ir_analyze_instruction_prefetch(IrAnalyze *ira, Stage1ZirInstPrefetch *instruction) {
24785+
Stage1AirInst *ptr = instruction->ptr->child;
24786+
if (type_is_invalid(ptr->value->type))
24787+
return ira->codegen->invalid_inst_gen;
24788+
24789+
Stage1AirInst *raw_options_inst = instruction->options->child;
24790+
if (type_is_invalid(raw_options_inst->value->type))
24791+
return ira->codegen->invalid_inst_gen;
24792+
24793+
ZigType *options_type = get_builtin_type(ira->codegen, "PrefetchOptions");
24794+
Stage1AirInst *options_inst = ir_implicit_cast(ira, raw_options_inst, options_type);
24795+
if (type_is_invalid(options_inst->value->type))
24796+
return ira->codegen->invalid_inst_gen;
24797+
24798+
ZigValue *options_val = ir_resolve_const(ira, options_inst, UndefBad);
24799+
if (options_val == nullptr)
24800+
return ira->codegen->invalid_inst_gen;
24801+
24802+
ZigValue *rw_val = get_const_field(ira, options_inst->source_node, options_val, "rw", 0);
24803+
if (rw_val == nullptr)
24804+
return ira->codegen->invalid_inst_gen;
24805+
PrefetchRw rw = (PrefetchRw)bigint_as_u8(&rw_val->data.x_enum_tag);
24806+
24807+
ZigValue *locality_val = get_const_field(ira, options_inst->source_node, options_val, "locality", 1);
24808+
if (locality_val == nullptr)
24809+
return ira->codegen->invalid_inst_gen;
24810+
uint8_t locality = bigint_as_u8(&locality_val->data.x_bigint);
24811+
assert(locality <= 3);
24812+
24813+
ZigValue *cache_val = get_const_field(ira, options_inst->source_node, options_val, "cache", 2);
24814+
if (cache_val == nullptr)
24815+
return ira->codegen->invalid_inst_gen;
24816+
PrefetchCache cache = (PrefetchCache)bigint_as_u8(&cache_val->data.x_enum_tag);
24817+
24818+
Stage1AirInstPrefetch *air_instruction = ir_build_inst_void<Stage1AirInstPrefetch>(&ira->new_irb,
24819+
instruction->base.scope, instruction->base.source_node);
24820+
air_instruction->ptr = ptr;
24821+
air_instruction->rw = rw;
24822+
air_instruction->locality = locality;
24823+
air_instruction->cache = cache;
24824+
24825+
ir_ref_inst_gen(ptr);
24826+
24827+
return &air_instruction->base;
24828+
}
24829+
2477824830
static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst *instruction) {
2477924831
switch (instruction->id) {
2478024832
case Stage1ZirInstIdInvalid:
@@ -25060,6 +25112,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst
2506025112
return ir_analyze_instruction_wasm_memory_grow(ira, (Stage1ZirInstWasmMemoryGrow *)instruction);
2506125113
case Stage1ZirInstIdSrc:
2506225114
return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction);
25115+
case Stage1ZirInstIdPrefetch:
25116+
return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction);
2506325117
}
2506425118
zig_unreachable();
2506525119
}
@@ -25227,6 +25281,7 @@ bool ir_inst_gen_has_side_effects(Stage1AirInst *instruction) {
2522725281
case Stage1AirInstIdSpillBegin:
2522825282
case Stage1AirInstIdWasmMemoryGrow:
2522925283
case Stage1AirInstIdExtern:
25284+
case Stage1AirInstIdPrefetch:
2523025285
return true;
2523125286

2523225287
case Stage1AirInstIdPhi:
@@ -25366,6 +25421,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) {
2536625421
case Stage1ZirInstIdAwait:
2536725422
case Stage1ZirInstIdSpillBegin:
2536825423
case Stage1ZirInstIdWasmMemoryGrow:
25424+
case Stage1ZirInstIdPrefetch:
2536925425
return true;
2537025426

2537125427
case Stage1ZirInstIdPhi:

src/stage1/ir_print.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) {
371371
return "SrcWasmMemoryGrow";
372372
case Stage1ZirInstIdSrc:
373373
return "SrcSrc";
374+
case Stage1ZirInstIdPrefetch:
375+
return "SrcPrefetch";
374376
}
375377
zig_unreachable();
376378
}
@@ -559,6 +561,8 @@ const char* ir_inst_gen_type_str(Stage1AirInstId id) {
559561
return "GenWasmMemoryGrow";
560562
case Stage1AirInstIdExtern:
561563
return "GenExtern";
564+
case Stage1AirInstIdPrefetch:
565+
return "GenPrefetch";
562566
}
563567
zig_unreachable();
564568
}
@@ -2436,6 +2440,18 @@ static void ir_print_extern(IrPrintSrc *irp, Stage1ZirInstExtern *instruction) {
24362440
fprintf(irp->f, ")");
24372441
}
24382442

2443+
static void ir_print_prefetch(IrPrintSrc *irp, Stage1ZirInstPrefetch *instruction) {
2444+
fprintf(irp->f, "@prefetch(");
2445+
ir_print_other_inst_src(irp, instruction->ptr);
2446+
fprintf(irp->f, ",");
2447+
ir_print_other_inst_src(irp, instruction->options);
2448+
fprintf(irp->f, ")");
2449+
}
2450+
2451+
static void ir_print_prefetch(IrPrintGen *irp, Stage1AirInstPrefetch *instruction) {
2452+
fprintf(irp->f, "@prefetch(...)");
2453+
}
2454+
24392455
static void ir_print_error_return_trace(IrPrintSrc *irp, Stage1ZirInstErrorReturnTrace *instruction) {
24402456
fprintf(irp->f, "@errorReturnTrace(");
24412457
switch (instruction->optional) {
@@ -3108,6 +3124,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool
31083124
case Stage1ZirInstIdSrc:
31093125
ir_print_builtin_src(irp, (Stage1ZirInstSrc *)instruction);
31103126
break;
3127+
case Stage1ZirInstIdPrefetch:
3128+
ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction);
3129+
break;
31113130
}
31123131
fprintf(irp->f, "\n");
31133132
}
@@ -3387,6 +3406,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool
33873406
case Stage1AirInstIdExtern:
33883407
ir_print_extern(irp, (Stage1AirInstExtern *)instruction);
33893408
break;
3409+
case Stage1AirInstIdPrefetch:
3410+
ir_print_prefetch(irp, (Stage1AirInstPrefetch *)instruction);
3411+
break;
33903412

33913413
}
33923414
fprintf(irp->f, "\n");

0 commit comments

Comments
 (0)