mirror of
https://github.com/odin-lang/Odin.git
synced 2026-05-25 13:18:14 +00:00
Add @(fast_math={...}) + intrinsics.Fast_Math_Flags
This commit is contained in:
@@ -4,6 +4,7 @@ package intrinsics
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
|
||||
// Package-Related
|
||||
is_package_imported :: proc(package_name: string) -> bool ---
|
||||
|
||||
|
||||
@@ -23,6 +23,23 @@ package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
/*
|
||||
Fast_Math_Flag :: enum u8 {
|
||||
Allow_Reassoc = 0,
|
||||
No_NaNs = 1,
|
||||
No_Infs = 2,
|
||||
No_Signed_Zeros = 3,
|
||||
Allow_Reciprocal = 4,
|
||||
Allow_Contract = 5,
|
||||
Approx_Func = 6,
|
||||
}
|
||||
*/
|
||||
Fast_Math_Flag :: intrinsics.Fast_Math_Flag
|
||||
|
||||
// Fast_Math_Flags :: distinct bit_set[Fast_Math_Flag; u32]
|
||||
Fast_Math_Flags :: intrinsics.Fast_Math_Flags
|
||||
|
||||
|
||||
// NOTE(bill): This must match the compiler's
|
||||
Calling_Convention :: enum u8 {
|
||||
Invalid = 0,
|
||||
|
||||
@@ -455,6 +455,7 @@ enum IntegerDivisionByZeroKind : u8 {
|
||||
IntegerDivisionByZero_AllBits,
|
||||
};
|
||||
|
||||
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
// Constants
|
||||
|
||||
@@ -1480,6 +1480,8 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
e->Procedure.no_sanitize_memory = ac.no_sanitize_memory;
|
||||
e->Procedure.no_sanitize_thread = ac.no_sanitize_thread;
|
||||
|
||||
e->Procedure.fast_math_flags = ac.fast_math_flags;
|
||||
|
||||
e->deprecated_message = ac.deprecated_message;
|
||||
e->warning_message = ac.warning_message;
|
||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix, ac.link_suffix);
|
||||
|
||||
@@ -1042,14 +1042,14 @@ struct GlobalEnumValue {
|
||||
i64 value;
|
||||
};
|
||||
|
||||
gb_internal Slice<Entity *> add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count, Type **enum_type_ = nullptr) {
|
||||
gb_internal Slice<Entity *> add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count, Type **enum_type_ = nullptr, Type *backing_type = nullptr) {
|
||||
Scope *scope = create_scope(nullptr, builtin_pkg->scope);
|
||||
Entity *entity = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved);
|
||||
|
||||
Type *enum_type = alloc_type_enum();
|
||||
Type *named_type = alloc_type_named(type_name, enum_type, entity);
|
||||
set_base_type(named_type, enum_type);
|
||||
enum_type->Enum.base_type = t_int;
|
||||
enum_type->Enum.base_type = backing_type ? backing_type : t_int;
|
||||
enum_type->Enum.scope = scope;
|
||||
entity->type = named_type;
|
||||
|
||||
@@ -1250,6 +1250,41 @@ gb_internal void init_universal(void) {
|
||||
add_global_enum_constant(fields, "ODIN_ERROR_POS_STYLE", build_context.ODIN_ERROR_POS_STYLE);
|
||||
}
|
||||
|
||||
{
|
||||
GlobalEnumValue values[OdinFastMath_COUNT] = {};
|
||||
for (unsigned i = 0; i < OdinFastMath_COUNT; i++) {
|
||||
values[i] = {OdinFastMathFlag_strings[i], i};
|
||||
}
|
||||
|
||||
auto fields = add_global_enum_type(str_lit("Fast_Math_Flag"), values, gb_count_of(values), &t_fast_math_flag, t_u8);
|
||||
|
||||
GB_ASSERT(t_fast_math_flag->kind == Type_Named);
|
||||
scope_insert(intrinsics_pkg->scope, t_fast_math_flag->Named.type_name);
|
||||
|
||||
Type *bs = alloc_type_bit_set();
|
||||
bs->BitSet.elem = t_fast_math_flag;
|
||||
bs->BitSet.underlying = t_u32;
|
||||
bs->BitSet.lower = 0;
|
||||
bs->BitSet.upper = OdinFastMath_COUNT-1;
|
||||
bs->BitSet.node = nullptr;
|
||||
|
||||
|
||||
{
|
||||
String type_name = str_lit("Fast_Math_Flags");
|
||||
|
||||
Scope *scope = create_scope(nullptr, builtin_pkg->scope);
|
||||
Entity *entity = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved);
|
||||
|
||||
Type *named_type = alloc_type_named(type_name, bs, entity);
|
||||
set_base_type(named_type, bs);
|
||||
entity->type = named_type;
|
||||
|
||||
t_fast_math_flags = named_type;
|
||||
|
||||
scope_insert(intrinsics_pkg->scope, entity);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
GlobalEnumValue values[OdinAtomicMemoryOrder_COUNT] = {
|
||||
{OdinAtomicMemoryOrder_strings[OdinAtomicMemoryOrder_relaxed], OdinAtomicMemoryOrder_relaxed},
|
||||
@@ -3554,11 +3589,17 @@ gb_internal void init_preload(Checker *c) {
|
||||
init_core_objc_c(c);
|
||||
}
|
||||
|
||||
gb_internal ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) {
|
||||
gb_internal void check_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *t);
|
||||
|
||||
gb_internal ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value, Type *type_hint = nullptr) {
|
||||
ExactValue ev = {};
|
||||
if (value != nullptr) {
|
||||
Operand op = {};
|
||||
check_expr(c, &op, value);
|
||||
if (type_hint != nullptr) {
|
||||
check_expr_with_type_hint(c, &op, value, type_hint);
|
||||
} else {
|
||||
check_expr(c, &op, value);
|
||||
}
|
||||
if (op.mode) {
|
||||
if (op.mode == Addressing_Constant) {
|
||||
ev = op.value;
|
||||
@@ -4126,6 +4167,18 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||
}
|
||||
ac->no_sanitize_thread = true;
|
||||
return true;
|
||||
} else if (name == "fast_math") {
|
||||
if (value == nullptr) {
|
||||
error(elem, "Expected a constant bit_set of type 'intrinsics.Fast_Math_Flags' for '%.*s'", LIT(name));
|
||||
} else {
|
||||
ExactValue ev = check_decl_attribute_value(c, value, t_fast_math_flags);
|
||||
if (ev.kind != ExactValue_Integer) {
|
||||
error(elem, "Expected a constant bit_set of type 'intrinsics.Fast_Math_Flags' for '%.*s'", LIT(name));
|
||||
} else {
|
||||
ac->fast_math_flags = exact_value_to_u64(ev);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -163,6 +163,8 @@ struct AttributeContext {
|
||||
String require_target_feature; // required by the target micro-architecture
|
||||
String enable_target_feature; // will be enabled for the procedure only
|
||||
|
||||
u64 fast_math_flags;
|
||||
|
||||
bool raddbg_type_view;
|
||||
String raddbg_type_view_string;
|
||||
};
|
||||
|
||||
@@ -256,6 +256,9 @@ struct Entity {
|
||||
struct GenProcsData *gen_procs;
|
||||
BlockingMutex gen_procs_mutex;
|
||||
ProcedureOptimizationMode optimization_mode;
|
||||
|
||||
u64 fast_math_flags;
|
||||
|
||||
bool is_foreign : 1;
|
||||
bool is_export : 1;
|
||||
bool generated_from_polymorphic : 1;
|
||||
|
||||
@@ -270,6 +270,55 @@ gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_mac
|
||||
optimization of Odin programs
|
||||
**************************************************************************/
|
||||
|
||||
gb_internal void lb_run_fast_float_math_pass(lbProcedure *p) {
|
||||
Entity *e = p->entity;
|
||||
if (e == nullptr) {
|
||||
return;
|
||||
}
|
||||
GB_ASSERT(e->kind == Entity_Procedure);
|
||||
|
||||
|
||||
u64 fast_math_flags = e->Procedure.fast_math_flags;
|
||||
LLVMFastMathFlags llvm_flags = 0;
|
||||
if (fast_math_flags & OdinFastMath_Allow_Reassoc) llvm_flags |= LLVMFastMathAllowReassoc;
|
||||
if (fast_math_flags & OdinFastMath_No_NaNs) llvm_flags |= LLVMFastMathNoNaNs;
|
||||
if (fast_math_flags & OdinFastMath_No_Infs) llvm_flags |= LLVMFastMathNoInfs;
|
||||
if (fast_math_flags & OdinFastMath_No_Signed_Zeros) llvm_flags |= LLVMFastMathNoSignedZeros;
|
||||
if (fast_math_flags & OdinFastMath_Allow_Reciprocal) llvm_flags |= LLVMFastMathAllowReciprocal;
|
||||
if (fast_math_flags & OdinFastMath_Allow_Contract) llvm_flags |= LLVMFastMathAllowContract;
|
||||
if (fast_math_flags & OdinFastMath_Approx_Func) llvm_flags |= LLVMFastMathApproxFunc;
|
||||
|
||||
if (llvm_flags == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(p->value);
|
||||
block != nullptr;
|
||||
block = LLVMGetNextBasicBlock(block)) {
|
||||
for (LLVMValueRef instr = LLVMGetFirstInstruction(block);
|
||||
instr != nullptr;
|
||||
instr = LLVMGetNextInstruction(instr)) {
|
||||
switch (LLVMGetInstructionOpcode(instr)) {
|
||||
case LLVMFNeg:
|
||||
case LLVMFAdd:
|
||||
case LLVMFSub:
|
||||
case LLVMFMul:
|
||||
case LLVMFDiv:
|
||||
case LLVMFRem:
|
||||
case LLVMFPToUI:
|
||||
case LLVMFPToSI:
|
||||
case LLVMUIToFP:
|
||||
case LLVMSIToFP:
|
||||
case LLVMFPTrunc:
|
||||
case LLVMFPExt:
|
||||
case LLVMFCmp:
|
||||
LLVMSetFastMathFlags(instr, llvm_flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
|
||||
unsigned debug_declare_id = LLVMLookupIntrinsicID("llvm.dbg.declare", 16);
|
||||
GB_ASSERT(debug_declare_id != 0);
|
||||
@@ -475,6 +524,9 @@ gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedur
|
||||
if (p == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
lb_run_fast_float_math_pass(p);
|
||||
|
||||
// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
|
||||
// which means we cannot rely upon it
|
||||
// This is also useful for read the .ll for debug purposes because a lot of instructions
|
||||
|
||||
@@ -805,6 +805,34 @@ gb_global Type *t_atomic_memory_order = nullptr;
|
||||
|
||||
|
||||
|
||||
enum OdinFastMathFlag : u8 {
|
||||
OdinFastMath_Allow_Reassoc = 0,
|
||||
OdinFastMath_No_NaNs = 1,
|
||||
OdinFastMath_No_Infs = 2,
|
||||
OdinFastMath_No_Signed_Zeros = 3,
|
||||
OdinFastMath_Allow_Reciprocal = 4,
|
||||
OdinFastMath_Allow_Contract = 5,
|
||||
OdinFastMath_Approx_Func = 6,
|
||||
|
||||
OdinFastMath_COUNT,
|
||||
};
|
||||
|
||||
char const *OdinFastMathFlag_strings[OdinFastMath_COUNT] = {
|
||||
"Allow_Reassoc",
|
||||
"No_NaNs",
|
||||
"No_Infs",
|
||||
"No_Signed_Zeros",
|
||||
"Allow_Reciprocal",
|
||||
"Allow_Contract",
|
||||
"Approx_Func",
|
||||
};
|
||||
|
||||
gb_global Type *t_fast_math_flag = nullptr; // named enum
|
||||
gb_global Type *t_fast_math_flags = nullptr; // named bit_set
|
||||
|
||||
|
||||
|
||||
|
||||
gb_global RecursiveMutex g_type_mutex;
|
||||
|
||||
struct TypePath;
|
||||
|
||||
Reference in New Issue
Block a user