diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-12-10 18:54:56 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-10 18:54:56 -0800 |
| commit | 97c0373fa7ee125d2d4e73f9b1dc8ea0e2c2e86a (patch) | |
| tree | d2aa342a53aef95f88456a63fa7874f3c51ba3b8 /src/stage1/codegen.cpp | |
| parent | 75f3e7a4a05db7ea805e581f78117a41768945ae (diff) | |
| parent | 516945d7d9b4d8b969d037076799d4ed29cecdda (diff) | |
| download | zig-97c0373fa7ee125d2d4e73f9b1dc8ea0e2c2e86a.tar.gz zig-97c0373fa7ee125d2d4e73f9b1dc8ea0e2c2e86a.zip | |
Merge pull request #10295 from ifreund/prefetch
Implement @prefetch()
Diffstat (limited to 'src/stage1/codegen.cpp')
| -rw-r--r-- | src/stage1/codegen.cpp | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index cba820037e..44600ffa45 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -1139,6 +1139,24 @@ static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) { return g->wasm_memory_grow; } +static LLVMValueRef gen_prefetch(CodeGen *g) { + if (g->prefetch) + return g->prefetch; + + // declare void @llvm.prefetch(i8*, i32, i32, i32) + LLVMTypeRef param_types[] = { + LLVMPointerType(LLVMInt8Type(), 0), + LLVMInt32Type(), + LLVMInt32Type(), + LLVMInt32Type(), + }; + LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 4, false); + g->prefetch = LLVMAddFunction(g->module, "llvm.prefetch.p0i8", fn_type); + assert(LLVMGetIntrinsicID(g->prefetch)); + + return g->prefetch; +} + static LLVMValueRef get_stacksave_fn_val(CodeGen *g) { if (g->stacksave_fn_val) return g->stacksave_fn_val; @@ -5899,6 +5917,52 @@ static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, Stage1Air *executable return val; } +static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1AirInstPrefetch *instruction) { + static_assert(PrefetchRwRead == 0, ""); + static_assert(PrefetchRwWrite == 1, ""); + assert(instruction->rw == PrefetchRwRead || instruction->rw == PrefetchRwWrite); + + assert(instruction->locality >= 0 && instruction->locality <= 3); + + static_assert(PrefetchCacheInstruction == 0, ""); + static_assert(PrefetchCacheData == 1, ""); + assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction); + + // LLVM fails during codegen of instruction cache prefetchs for these architectures. + // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target. + // To work around this, simply don't emit llvm.prefetch in this case. + // See https://bugs.llvm.org/show_bug.cgi?id=21037 + if (instruction->cache == PrefetchCacheInstruction) { + switch (g->zig_target->arch) { + case ZigLLVM_x86: + case ZigLLVM_x86_64: + return nullptr; + default: + break; + } + } + + // Another case of the same LLVM bug described above + if (instruction->rw == PrefetchRwWrite && instruction->cache == PrefetchCacheInstruction) { + switch (g->zig_target->arch) { + case ZigLLVM_arm: + return nullptr; + default: + break; + } + + } + + LLVMValueRef params[] = { + LLVMBuildBitCast(g->builder, ir_llvm_value(g, instruction->ptr), LLVMPointerType(LLVMInt8Type(), 0), ""), + LLVMConstInt(LLVMInt32Type(), instruction->rw, false), + LLVMConstInt(LLVMInt32Type(), instruction->locality, false), + LLVMConstInt(LLVMInt32Type(), instruction->cache, false), + }; + LLVMValueRef val = LLVMBuildCall(g->builder, gen_prefetch(g), params, 4, ""); + return val; +} + static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) { Error err; @@ -7150,6 +7214,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Sta return ir_render_wasm_memory_grow(g, executable, (Stage1AirInstWasmMemoryGrow *) instruction); case Stage1AirInstIdExtern: return ir_render_extern(g, executable, (Stage1AirInstExtern *) instruction); + case Stage1AirInstIdPrefetch: + return ir_render_prefetch(g, executable, (Stage1AirInstPrefetch *) instruction); } zig_unreachable(); } @@ -9120,6 +9186,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2); create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2); create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2); + create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2); } static const char *bool_to_str(bool b) { |
