Repository navigation
RV64F Support #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
RV64F Support #22
Changes from all commits
12df70b
9ff0027
de428ac
d8558a1
95b2957
e3de017
041256b
21295f5
56a7c54
16c6237
72cb1fd
4ad58e9
2d3b54f
95f0ef2
f1b3e2b
01d5616
2f20c1d
93f50e1
b27676e
bfe12c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # softfloat: floating point arithmetic library | ||
| CPMAddPackage( | ||
| NAME softfloat | ||
| GITHUB_REPOSITORY ucb-bar/berkeley-softfloat-3 | ||
| GIT_TAG a0c6494cdc11865811dec815d5c0049fba9d82a8 | ||
| DOWNLOAD_ONLY YES | ||
| EXCLUDE_FROM_ALL True | ||
| SYSTEM True) | ||
|
|
||
| # Generate platform.h | ||
| set(SOFTFLOAT_PLATFORM_H ${CMAKE_CURRENT_BINARY_DIR}/platform.h) | ||
| file(WRITE ${SOFTFLOAT_PLATFORM_H} | ||
| "#ifndef SOFTFLOAT_PLATFORM_H | ||
| #define SOFTFLOAT_PLATFORM_H | ||
|
|
||
| #include <stdint.h> | ||
| #include <stdbool.h> | ||
|
|
||
| #endif | ||
| ") | ||
|
|
||
| # Collect all required source files | ||
| file(GLOB SOFTFLOAT_SRC | ||
| ${softfloat_SOURCE_DIR}/source/*.c | ||
| ${softfloat_SOURCE_DIR}/source/s_*.c | ||
| ${softfloat_SOURCE_DIR}/source/specialize/*.c | ||
| ) | ||
|
|
||
| # Use the RISC-V specialization so NaN handling, default-NaN values and | ||
| # float-to-int saturation match the RISC-V F/D spec (e.g. default NaN | ||
| # 0x7FC00000, i32_fromNaN 0x7FFFFFFF) rather than the 8086/x86 semantics. | ||
| file(GLOB SOFTFLOAT_PLATFORM_SRC | ||
| ${softfloat_SOURCE_DIR}/source/RISCV/*.c | ||
| ) | ||
| set(SOFTFLOAT_PLATFORM_DIR ${softfloat_SOURCE_DIR}/source/RISCV) | ||
|
|
||
| list(APPEND SOFTFLOAT_SRC ${SOFTFLOAT_PLATFORM_SRC}) | ||
|
|
||
| # Exclude unsupported formats | ||
| list(FILTER SOFTFLOAT_SRC EXCLUDE REGEX ".*F80.*") | ||
| list(FILTER SOFTFLOAT_SRC EXCLUDE REGEX ".*F128.*") | ||
| list(FILTER SOFTFLOAT_SRC EXCLUDE REGEX ".*bf16.*") | ||
| list(FILTER SOFTFLOAT_SRC EXCLUDE REGEX ".*f16_.*") | ||
|
|
||
| # Create the static library | ||
| add_library(softfloat STATIC ${SOFTFLOAT_SRC}) | ||
|
|
||
| target_include_directories(softfloat PUBLIC | ||
| ${softfloat_SOURCE_DIR}/source/include | ||
| ${softfloat_SOURCE_DIR}/source | ||
| ${SOFTFLOAT_PLATFORM_DIR} | ||
| ${CMAKE_CURRENT_BINARY_DIR} | ||
| ) | ||
|
|
||
| target_compile_definitions(softfloat PRIVATE | ||
| SOFTFLOAT_FAST_INT64 | ||
| SOFTFLOAT_FAST_INT64 | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,13 @@ | ||
| require 'Utility/helper_cpp' | ||
| require 'Utility/fp_helper_cpp' | ||
| require 'code_gen/fp_cpp_gen' | ||
| # frozen_string_literal: true | ||
|
|
||
| # Semantics Generator: Converts IR to C++ code | ||
| module CodeGen | ||
| class CppGenerator | ||
| include FPEmitters | ||
|
|
||
| attr_reader :emitter, :mapping | ||
|
|
||
| def initialize(emitter, mapping = {}) | ||
|
|
@@ -22,6 +26,20 @@ def binary_operation(emitter, operation, op_str) | |
| emitter.emit_line("#{dst} = #{src1} #{op_str} #{src2};") | ||
| end | ||
|
|
||
| # Helpers for easier operand mapping in operations emitters | ||
| def map_n_operands(op, n) | ||
| ops = [] | ||
| (0...n).each do |i| | ||
| ops[i] = map_operand(op[:oprnds][i]) | ||
| end | ||
| ops | ||
| end | ||
|
|
||
| def map_operand(op) | ||
| val = @mapping[op[:name]] || op[:name] | ||
| val.nil? ? op[:value] : val | ||
| end | ||
|
|
||
| def self.generate_statement(operation) | ||
| emitter = Utility::GenEmitter.new | ||
| CppGenerator.new(emitter, operation[:attrs][:mapping]).generate_statement(operation) | ||
|
|
@@ -36,15 +54,18 @@ def cpu_read_reg(dst) | |
| "cpu.get#{dst[:regset]}" | ||
| end | ||
|
|
||
| def cpu_write_mem(addr, val) | ||
| "cpu.m_memory->write(#{addr}, #{val})" | ||
| def cpu_write_mem(addr, val, val_op) | ||
| "cpu.m_memory->write<#{Utility::HelperCpp.gen_small_type(val_op[:type])}>(#{addr}, #{val})" | ||
| end | ||
|
|
||
| def cpu_read_mem(dst, addr) | ||
| "cpu.m_memory->read<#{Utility::HelperCpp.gen_small_type(dst[:type])}>(#{addr})" | ||
| end | ||
|
|
||
| def generate_statement(operation) | ||
| # Extract rm from attrs if present. | ||
| rm = operation[:attrs] if operation[:attrs].is_a?(Integer) | ||
|
|
||
| case operation[:name] | ||
| when :add | ||
| binary_operation(@emitter, operation, '+') | ||
|
|
@@ -102,7 +123,6 @@ def generate_statement(operation) | |
| src_name = @mapping[operation[:oprnds][1][:name]] || operation[:oprnds][1][:name] | ||
| expr = @mapping[operation[:oprnds][0][:name]] || operation[:oprnds][0][:name] | ||
| expr = expr.nil? ? operation[:oprnds][0][:value] : expr | ||
|
|
||
| @emitter.emit_line("#{expr} = #{cpu_read_reg(src)}<#{Utility::HelperCpp.gen_small_type(src[:type])}>(#{src_name});") | ||
| when :writeReg | ||
| dst = operation[:oprnds][0] | ||
|
|
@@ -121,21 +141,197 @@ def generate_statement(operation) | |
| when :writeMem | ||
| addr = @mapping[operation[:oprnds][0][:name]] || operation[:oprnds][0][:name] | ||
| val = @mapping[operation[:oprnds][1][:name]] || operation[:oprnds][1][:name] | ||
| @emitter.emit_line("#{cpu_write_mem addr, val};") | ||
| @emitter.emit_line("#{cpu_write_mem addr, val, operation[:oprnds][1]};") | ||
| when :extract | ||
| dst = @mapping[operation[:oprnds][0][:name]] || operation[:oprnds][0][:name] | ||
| src = @mapping[operation[:oprnds][1][:name]] || operation[:oprnds][1][:name] | ||
|
|
||
| @emitter.emit_line("#{dst} = static_cast<#{Utility::HelperCpp.gen_small_type operation[:oprnds][0][:type]}>(#{src} << #{operation[:oprnds][3][:value]});") | ||
| when :sysCall | ||
| @emitter.emit_line('cpu.doExit();') | ||
| when :readCSR | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we accept it? @egorshamshura
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's not good to create separate operation for every external call I think we need to add something like "externCall" or just "call" operation |
||
| dst = @mapping[operation[:oprnds][0][:name]] || operation[:oprnds][0][:name] | ||
| csr = @mapping[operation[:oprnds][1][:name]] || operation[:oprnds][1][:name] | ||
| csr = csr.nil? ? operation[:oprnds][1][:value] : csr | ||
| @emitter.emit_line("#{dst} = cpu.readCSR(#{csr});") | ||
| when :writeCSR | ||
| csr = @mapping[operation[:oprnds][0][:name]] || operation[:oprnds][0][:name] | ||
| csr = csr.nil? ? operation[:oprnds][0][:value] : csr | ||
| val = @mapping[operation[:oprnds][1][:name]] || operation[:oprnds][1][:name] | ||
| val = val.nil? ? operation[:oprnds][1][:value] : val | ||
| @emitter.emit_line("cpu.writeCSR(#{csr}, #{val});") | ||
| when :select | ||
| dst = @mapping[operation[:oprnds][0][:name]] || operation[:oprnds][0][:name] | ||
| cond = @mapping[operation[:oprnds][1][:name]] || operation[:oprnds][1][:name] | ||
| true_val = @mapping[operation[:oprnds][2][:name]] || operation[:oprnds][2][:name] | ||
| false_val = @mapping[operation[:oprnds][3][:name]] || operation[:oprnds][3][:name] | ||
|
|
||
| @emitter.emit_line("#{dst} = #{cond} ? #{true_val} : #{false_val};") | ||
|
|
||
| # Add emitters for RV64F | ||
| # Floating point arithmetic operations WITH rounding mode (SoftFloat global) | ||
| when :f32_add then emit_fp_binary('f32_add', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32], | ||
| rm: rm) | ||
|
|
||
| when :f64_add then emit_fp_binary('f64_add', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64], | ||
| rm: rm) | ||
|
|
||
| when :f32_sub then emit_fp_binary('f32_sub', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32], | ||
| rm: rm) | ||
|
|
||
| when :f64_sub then emit_fp_binary('f64_sub', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64], | ||
| rm: rm) | ||
|
|
||
| when :f32_mul then emit_fp_binary('f32_mul', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32], | ||
| rm: rm) | ||
|
|
||
| when :f64_mul then emit_fp_binary('f64_mul', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64], | ||
| rm: rm) | ||
|
|
||
| when :f32_div then emit_fp_binary('f32_div', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32], | ||
| rm: rm) | ||
|
|
||
| when :f64_div then emit_fp_binary('f64_div', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64], | ||
| rm: rm) | ||
| when :f32_sqrt then emit_fp_unary('f32_sqrt', operation, | ||
| dst_type: :f32, | ||
| src_type: :f32, | ||
| rm: rm) | ||
|
|
||
| when :f64_sqrt then emit_fp_unary('f64_sqrt', operation, | ||
| dst_type: :f64, | ||
| src_type: :f64, | ||
| rm: rm) | ||
| when :f32_mul_add then emit_fp_ternary('f32_mulAdd', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32 f32], | ||
| rm: rm) | ||
|
|
||
| when :f64_mul_add then emit_fp_ternary('f64_mulAdd', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64 f64], | ||
| rm: rm) | ||
|
|
||
| # Fused Multiply-Add with Negation | ||
| when :f32_mul_add_n then emit_fp_ternary('f32_mulAdd', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32 f32], | ||
| negate_src: [0, 2], | ||
| rm: rm) | ||
|
|
||
| when :f64_mul_add_n then emit_fp_ternary('f64_mulAdd', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64 f64], | ||
| negate_src: [0, 2], | ||
| rm: rm) | ||
|
|
||
| when :f32_mul_sub then emit_fp_ternary('f32_mulAdd', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32 f32], | ||
| negate_src: [2], | ||
| rm: rm) | ||
|
|
||
| when :f64_mul_sub then emit_fp_ternary('f64_mulAdd', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64 f64], | ||
| negate_src: [2], | ||
| rm: rm) | ||
|
|
||
| when :f32_mul_sub_n then emit_fp_ternary('f32_mulAdd', operation, | ||
| dst_type: :f32, | ||
| src_types: %i[f32 f32 f32], | ||
| negate_src: [0], | ||
| rm: rm) | ||
|
|
||
| when :f64_mul_sub_n then emit_fp_ternary('f64_mulAdd', operation, | ||
| dst_type: :f64, | ||
| src_types: %i[f64 f64 f64], | ||
| negate_src: [0], | ||
| rm: rm) | ||
|
|
||
| # Floating point comparisons (no rm) | ||
| when :f32_eq then emit_fp_binary('f32_eq', operation, | ||
| dst_type: :i32, | ||
| src_types: %i[f32 f32]) | ||
| when :f64_eq then emit_fp_binary('f64_eq', operation, | ||
| dst_type: :i32, | ||
| src_types: %i[f64 f64]) | ||
| when :f32_lt then emit_fp_binary('f32_lt', operation, | ||
| dst_type: :i32, | ||
| src_types: %i[f32 f32]) | ||
| when :f64_lt then emit_fp_binary('f64_lt', operation, | ||
| dst_type: :i32, | ||
| src_types: %i[f64 f64]) | ||
| when :f32_le then emit_fp_binary('f32_le', operation, | ||
| dst_type: :i32, | ||
| src_types: %i[f32 f32]) | ||
| when :f64_le then emit_fp_binary('f64_le', operation, | ||
| dst_type: :i32, | ||
| src_types: %i[f64 f64]) | ||
|
|
||
| when :f32_min then emit_fp_min_max('f32_min', operation, type: :f32) | ||
| when :f64_min then emit_fp_min_max('f64_min', operation, type: :f64) | ||
| when :f32_max then emit_fp_min_max('f32_max', operation, type: :f32) | ||
| when :f64_max then emit_fp_min_max('f64_max', operation, type: :f64) | ||
|
|
||
| # Floating point injections | ||
| when :f32_sign_injection then emit_sign_inject(operation, width: 32, mode: :copy) | ||
| when :f64_sign_injection then emit_sign_inject(operation, width: 64, mode: :copy) | ||
|
|
||
| when :f32_sign_injection_n then emit_sign_inject(operation, width: 32, mode: :neg) | ||
| when :f64_sign_injection_n then emit_sign_inject(operation, width: 64, mode: :neg) | ||
|
|
||
| when :f32_sign_xor then emit_sign_inject(operation, width: 32, mode: :xor) | ||
| when :f64_sign_xor then emit_sign_inject(operation, width: 64, mode: :xor) | ||
|
|
||
| # Floating point conversions with rm | ||
| when :f32_to_i32 then emit_fp_to_int_conv('f32_to_i32', operation, dst_type: :i32, src_type: :f32, | ||
| rounding_mode: rm) | ||
| when :f32_to_u32 then emit_fp_to_int_conv('f32_to_ui32', operation, dst_type: :u32, src_type: :f32, | ||
| rounding_mode: rm) | ||
| when :f32_to_i64 then emit_fp_to_int_conv('f32_to_i64', operation, dst_type: :i64, src_type: :f32, | ||
| rounding_mode: rm) | ||
| when :f32_to_u64 then emit_fp_to_int_conv('f32_to_ui64', operation, dst_type: :u64, src_type: :f32, | ||
| rounding_mode: rm) | ||
|
|
||
| when :i32_to_f32 then emit_fp_unary('i32_to_f32', operation, | ||
| dst_type: :f32, src_type: :i32, rm: rm) | ||
|
|
||
| when :u32_to_f32 then emit_fp_unary('ui32_to_f32', operation, | ||
| dst_type: :f32, src_type: :u32, rm: rm) | ||
|
|
||
| when :i64_to_f32 then emit_fp_unary('i64_to_f32', operation, | ||
| dst_type: :f32, src_type: :i64, rm: rm) | ||
|
|
||
| when :u64_to_f32 then emit_fp_unary('ui64_to_f32', operation, | ||
| dst_type: :f32, src_type: :u64, rm: rm) | ||
|
|
||
| # Classification | ||
| when :f32_classify | ||
| dst, src = map_n_operands(operation, 2) | ||
| @emitter.emit_line("#{dst} = kArchSupport.f32_classify(static_cast<uint32_t>(#{src}));") | ||
|
|
||
| when :f64_classify | ||
| dst, src = map_n_operands(operation, 2) | ||
| @emitter.emit_line("#{dst} = kArchSupport.f64_classify(static_cast<uint64_t>(#{src}));") | ||
|
|
||
| else raise "Unknown statement type: #{operation[:name]}, terminating program" | ||
| end | ||
| end | ||
| end | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider architecture specific.