Add @naked attribute

This commit is contained in:
Christoffer Lerno
2021-08-22 23:48:25 +02:00
committed by Christoffer Lerno
parent fdcc189f41
commit f7803fd192
8 changed files with 58 additions and 12 deletions

View File

@@ -396,6 +396,7 @@ typedef struct
bool attr_inline : 1; bool attr_inline : 1;
bool attr_noinline : 1; bool attr_noinline : 1;
bool attr_extname : 1; bool attr_extname : 1;
bool attr_naked : 1;
}; };
TypeInfo *type_parent; TypeInfo *type_parent;

View File

@@ -628,6 +628,7 @@ unsigned attribute_zext;
unsigned attribute_sext; unsigned attribute_sext;
unsigned attribute_byval; unsigned attribute_byval;
unsigned attribute_inreg; unsigned attribute_inreg;
unsigned attribute_naked;
void llvm_codegen_setup() void llvm_codegen_setup()
{ {
@@ -709,6 +710,7 @@ void llvm_codegen_setup()
attribute_align = lookup_attribute("align"); attribute_align = lookup_attribute("align");
attribute_byval = lookup_attribute("byval"); attribute_byval = lookup_attribute("byval");
attribute_inreg = lookup_attribute("inreg"); attribute_inreg = lookup_attribute("inreg");
attribute_naked = lookup_attribute("naked");
intrinsics_setup = true; intrinsics_setup = true;
} }

View File

@@ -422,10 +422,13 @@ void llvm_emit_function_body(GenContext *context, Decl *decl)
} }
// Generate LLVMValueRef's for all parameters, so we can use them as local vars in code if (!decl->func_decl.attr_naked)
VECEACH(decl->func_decl.function_signature.params, i)
{ {
llvm_emit_parameter(context, decl->func_decl.function_signature.params[i], &arg, i); // Generate LLVMValueRef's for all parameters, so we can use them as local vars in code
VECEACH(decl->func_decl.function_signature.params, i)
{
llvm_emit_parameter(context, decl->func_decl.function_signature.params[i], &arg, i);
}
} }
LLVMSetCurrentDebugLocation2(context->builder, NULL); LLVMSetCurrentDebugLocation2(context->builder, NULL);
@@ -575,7 +578,10 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
LLVMSetSection(function, decl->section); LLVMSetSection(function, decl->section);
} }
llvm_attribute_add(c, function, attribute_nounwind, -1); llvm_attribute_add(c, function, attribute_nounwind, -1);
if (decl->func_decl.attr_naked)
{
llvm_attribute_add(c, function, attribute_naked, -1);
}
if (decl->func_decl.function_signature.call_abi == CALL_X86_STD) if (decl->func_decl.function_signature.call_abi == CALL_X86_STD)
{ {
if (platform_target.os == OS_TYPE_WIN32) if (platform_target.os == OS_TYPE_WIN32)

View File

@@ -177,6 +177,7 @@ extern unsigned attribute_zext; // zero extend
extern unsigned attribute_sext; // sign extend extern unsigned attribute_sext; // sign extend
extern unsigned attribute_byval; // ByVal (param) extern unsigned attribute_byval; // ByVal (param)
extern unsigned attribute_inreg; // inreg (param) extern unsigned attribute_inreg; // inreg (param)
extern unsigned attribute_naked; // naked function
void gencontext_begin_module(GenContext *c); void gencontext_begin_module(GenContext *c);
void gencontext_init_file_emit(GenContext *c, Context *ast); void gencontext_init_file_emit(GenContext *c, Context *ast);

View File

@@ -1086,6 +1086,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
case ATTRIBUTE_INLINE: SET_ATTR(attr_inline); case ATTRIBUTE_INLINE: SET_ATTR(attr_inline);
case ATTRIBUTE_NORETURN: SET_ATTR(attr_noreturn); case ATTRIBUTE_NORETURN: SET_ATTR(attr_noreturn);
case ATTRIBUTE_WEAK: SET_ATTR(attr_weak); case ATTRIBUTE_WEAK: SET_ATTR(attr_weak);
case ATTRIBUTE_NAKED: SET_ATTR(attr_naked);
default: default:
UNREACHABLE UNREACHABLE
} }

View File

@@ -2426,16 +2426,32 @@ bool sema_analyse_function_body(Context *context, Decl *func)
} }
Ast **asserts = NULL; Ast **asserts = NULL;
if (!sema_analyse_requires(context, func->docs, &asserts)) return false; if (!sema_analyse_requires(context, func->docs, &asserts)) return false;
if (!sema_analyse_compound_statement_no_scope(context, func->func_decl.body)) return false; if (func->func_decl.attr_naked)
assert(context->active_scope.depth == 1);
if (!context->active_scope.jump_end)
{ {
Type *canonical_rtype = signature->rtype->type->canonical; Ast **stmts = func->func_decl.body->compound_stmt.stmts;
if (canonical_rtype != type_void) VECEACH(stmts, i)
{ {
// IMPROVE better pointer to end. if (stmts[i]->ast_kind != AST_ASM_STMT)
SEMA_ERROR(func, "Missing return statement at the end of the function."); {
return false; SEMA_ERROR(stmts[i], "Only asm statements are allowed inside of a naked function.");
return false;
}
}
asserts = NULL;
}
else
{
if (!sema_analyse_compound_statement_no_scope(context, func->func_decl.body)) return false;
assert(context->active_scope.depth == 1);
if (!context->active_scope.jump_end)
{
Type *canonical_rtype = signature->rtype->type->canonical;
if (canonical_rtype != type_void)
{
// IMPROVE better pointer to end.
SEMA_ERROR(func, "Missing return statement at the end of the function.");
return false;
}
} }
} }
if (asserts) if (asserts)

View File

@@ -0,0 +1,15 @@
// #target: x64-darwin
func void test(int i) @naked
{
}
// #expect: naked_function.ll
define void @naked_function.test(i32 %0) #0 {
entry:
ret void
}
attributes #0 = { naked nounwind }

View File

@@ -0,0 +1,4 @@
func void test() @naked
{
int i; // #error: Only asm statements are allowed inside of a naked function
}