From b928738d06a9fd1393d3fa68424b57e3194f0deb Mon Sep 17 00:00:00 2001 From: Daan Vanden Bosch Date: Tue, 6 Aug 2019 17:37:34 +0200 Subject: [PATCH] Float literal arguments passed via the stack are now handled correctly in the assembler and disassembler. --- src/data_formats/parsing/quest/bin.ts | 2 -- src/primitive_conversion.ts | 11 +++++++++++ src/scripting/assembly.ts | 10 +++++++++- src/scripting/disassembly.ts | 17 ++++++++++++++--- 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 src/primitive_conversion.ts diff --git a/src/data_formats/parsing/quest/bin.ts b/src/data_formats/parsing/quest/bin.ts index 39ab4803..71c89ee8 100644 --- a/src/data_formats/parsing/quest/bin.ts +++ b/src/data_formats/parsing/quest/bin.ts @@ -37,8 +37,6 @@ import { WritableCursor } from "../../cursor/WritableCursor"; import { ResizableBuffer } from "../../ResizableBuffer"; import { stack_value } from "../../../scripting/data_flow_analysis/stack_value"; -// TODO: correctly deal with stack floats (they're pushed with arg_pushl), see scroll_text in quest235.qst - const logger = Logger.get("data_formats/parsing/quest/bin"); export class BinFile { diff --git a/src/primitive_conversion.ts b/src/primitive_conversion.ts new file mode 100644 index 00000000..65748b32 --- /dev/null +++ b/src/primitive_conversion.ts @@ -0,0 +1,11 @@ +const data_view = new DataView(new ArrayBuffer(4)); + +export function reinterpret_i32_as_f32(i32: number): number { + data_view.setInt32(0, i32); + return data_view.getFloat32(0); +} + +export function reinterpret_f32_as_i32(f32: number): number { + data_view.setFloat32(0, f32); + return data_view.getInt32(0); +} diff --git a/src/scripting/assembly.ts b/src/scripting/assembly.ts index b401c064..047d51d4 100644 --- a/src/scripting/assembly.ts +++ b/src/scripting/assembly.ts @@ -40,6 +40,7 @@ import { TYPE_REG_REF, RegTupRefType, } from "./opcodes"; +import { reinterpret_f32_as_i32 } from "../primitive_conversion"; const logger = Logger.get("scripting/assembly"); @@ -482,9 +483,16 @@ class Assembler { this.add_instruction(Opcode.ARG_PUSHW, [arg]); break; case TYPE_DWORD: - case TYPE_FLOAT: this.add_instruction(Opcode.ARG_PUSHL, [arg]); break; + case TYPE_FLOAT: + this.add_instruction(Opcode.ARG_PUSHL, [ + { + value: reinterpret_f32_as_i32(arg.value), + size: 4, + }, + ]); + break; case TYPE_STRING: this.add_instruction(Opcode.ARG_PUSHS, [arg]); break; diff --git a/src/scripting/disassembly.ts b/src/scripting/disassembly.ts index 92e4404f..a0e838d4 100644 --- a/src/scripting/disassembly.ts +++ b/src/scripting/disassembly.ts @@ -7,7 +7,9 @@ import { TYPE_REG_REF_VAR, TYPE_REG_REF, RegTupRefType, + TYPE_FLOAT, } from "./opcodes"; +import { reinterpret_i32_as_f32 } from "../primitive_conversion"; /** * @param manual_stack If true, will output stack management instructions (argpush variants). Otherwise the arguments of stack management instructions will be output as arguments to the instruction that pops them from the stack. @@ -83,11 +85,12 @@ export function disassemble(object_code: Segment[], manual_stack: boolean = fals stack.splice( Math.max(0, stack.length - instruction.opcode.params.length), instruction.opcode.params.length - ) + ), + true ); } } else { - args = args_to_strings(instruction.opcode.params, instruction.args); + args = args_to_strings(instruction.opcode.params, instruction.args, false); } lines.push( @@ -108,7 +111,7 @@ export function disassemble(object_code: Segment[], manual_stack: boolean = fals return lines; } -function args_to_strings(params: Param[], args: Arg[]): string[] { +function args_to_strings(params: Param[], args: Arg[], stack: boolean): string[] { const arg_strings: string[] = []; for (let i = 0; i < params.length; i++) { @@ -121,6 +124,14 @@ function args_to_strings(params: Param[], args: Arg[]): string[] { } switch (type) { + case TYPE_FLOAT: + // Floats are pushed onto the stack as integers with arg_pushl. + if (stack) { + arg_strings.push(reinterpret_i32_as_f32(arg.value).toString()); + } else { + arg_strings.push(arg.value.toString()); + } + break; case TYPE_I_LABEL_VAR: for (; i < args.length; i++) { arg_strings.push(args[i].value.toString());