aboutsummaryrefslogtreecommitdiff
path: root/src/stage1/codegen.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-12-10 18:54:56 -0800
committerGitHub <noreply@github.com>2021-12-10 18:54:56 -0800
commit97c0373fa7ee125d2d4e73f9b1dc8ea0e2c2e86a (patch)
treed2aa342a53aef95f88456a63fa7874f3c51ba3b8 /src/stage1/codegen.cpp
parent75f3e7a4a05db7ea805e581f78117a41768945ae (diff)
parent516945d7d9b4d8b969d037076799d4ed29cecdda (diff)
downloadzig-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.cpp67
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) {