stage1: implement @prefetch() builtin

This commit is contained in:
Isaac Freund
2021-12-07 19:35:46 +01:00
committed by Isaac Freund
parent 175463d75d
commit 7bb6393b59
7 changed files with 251 additions and 0 deletions

View File

@@ -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) {