Skip to content

Commit

Permalink
Improve floating point literal handling
Browse files Browse the repository at this point in the history
The configuration LIBASM_ASM_NOFLOAT, LIBASM_DIS_NOFLOAT control only
floating point literals.
  • Loading branch information
tgtakaoka committed Oct 9, 2024
1 parent e112f7a commit cc7abf1
Show file tree
Hide file tree
Showing 30 changed files with 1,212 additions and 847 deletions.
114 changes: 66 additions & 48 deletions src/asm_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,62 +337,80 @@ Error Assembler::defineDataConstant(StrScanner &scan, Insn &insn, uint8_t dataTy
const auto hasString = !(type == DATA_BYTE_NO_STRING || type == DATA_WORD_NO_STRING);
ErrorAt error;
do {
auto p = scan.skipSpaces();
scan.skipSpaces();
ErrorAt strErr;
if (hasString && isString(p, strErr) == OK) {
generateString(scan, p, insn, type, error);
continue;
if (hasString) {
auto end = scan;
const auto err = isString(end, strErr);
if (err == OK) {
generateString(scan, end, insn, type, strErr);
if (error.setErrorIf(strErr) == NO_MEMORY)
break;
continue;
}
}

const auto at = p;
ErrorAt exprErr;
auto p = scan;
const auto val = parseExpr(p, exprErr);
if (!endOfLine(p) && *p != ',')
exprErr.setErrorIf(at, ILLEGAL_CONSTANT);
if (!exprErr.hasError()) {
auto v = val.getUnsigned();
switch (type) {
case DATA_BYTE_OR_WORD:
if (val.overflowUint8())
goto emit_word;
// Fall-through
case DATA_BYTE:
case DATA_BYTE_NO_STRING:
insn.emitByte(v);
break;
case DATA_BYTE_IN_WORD:
v &= 0xFF;
// Fall-through
case DATA_WORD:
case DATA_WORD_NO_STRING:
emit_word:
big ? insn.emitUint16Be(v) : insn.emitUint16Le(v);
break;
case DATA_LONG:
big ? insn.emitUint32Be(v) : insn.emitUint32Le(v);
break;
#ifndef LIBASM_ASM_NOFLOAT
case DATA_FLOAT32:
big ? insn.emitFloat32Be(val.getFloat()) : insn.emitFloat32Le(val.getFloat());
break;
case DATA_FLOAT64:
big ? insn.emitFloat64Be(val.getFloat()) : insn.emitFloat64Le(val.getFloat());
break;
#endif
case DATA_ALIGN2:
break;
if (!endOfLine(p) && *p != ',') {
if (strErr.getError()) {
error.setErrorIf(strErr);
} else {
error.setErrorIf(scan, ILLEGAL_CONSTANT);
}
if (exprErr.getError())
error.setErrorIf(exprErr);
if (insn.getError())
error.setErrorIf(at, insn);
scan = p;
continue;
break;
}
if (exprErr.hasError()) {
error.setErrorIf(strErr.getError() ? strErr : exprErr);
break;
}

return insn.setError(strErr.getError() ? strErr : exprErr);
auto v = val.getUnsigned();
switch (type) {
case DATA_BYTE_OR_WORD:
if (val.overflowUint8())
goto emit_word;
// Fall-through
case DATA_BYTE:
case DATA_BYTE_NO_STRING:
exprErr.setErrorIf(scan, insn.emitByte(v));
break;
case DATA_BYTE_IN_WORD:
v &= 0xFF;
// Fall-through
case DATA_WORD:
case DATA_WORD_NO_STRING:
emit_word:
exprErr.setErrorIf(scan, big ? insn.emitUint16Be(v) : insn.emitUint16Le(v));
break;
case DATA_LONG:
exprErr.setErrorIf(scan, big ? insn.emitUint32Be(v) : insn.emitUint32Le(v));
break;
case DATA_FLOAT32:
#if defined(LIBASM_ASM_NOFLOAT)
exprErr.setErrorIf(scan, FLOAT_NOT_SUPPORTED);
insn.emitUint32Be(0);
#else
exprErr.setErrorIf(scan,
big ? insn.emitFloat32Be(val.getFloat()) : insn.emitFloat32Le(val.getFloat()));
#endif
break;
case DATA_FLOAT64:
#if defined(LIBASM_ASM_NOFLOAT)
exprErr.setErrorIf(scan, FLOAT_NOT_SUPPORTED);
insn.emitUint64Be(0);
#else
exprErr.setErrorIf(scan,
big ? insn.emitFloat64Be(val.getFloat()) : insn.emitFloat64Le(val.getFloat()));
#endif
break;
case DATA_ALIGN2:
break;
}
scan = p;
if (error.setErrorIf(exprErr) == NO_MEMORY)
break;
} while (scan.skipSpaces().expect(','));

return insn.setError(error);
}

Expand Down
2 changes: 0 additions & 2 deletions src/asm_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,8 @@ struct Assembler {
DATA_WORD,
DATA_WORD_NO_STRING,
DATA_LONG,
#ifndef LIBASM_ASM_NOFLOAT
DATA_FLOAT32,
DATA_FLOAT64,
#endif
DATA_ALIGN2 = 0x80,
};
Error defineDataConstant(StrScanner &scan, Insn &insn, uint8_t dataType);
Expand Down
136 changes: 80 additions & 56 deletions src/asm_i8086.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Error AsmI8086::setFpu(StrScanner &scan) {
p.iexpect('i');
if (scan.expectFalse() || scan.iequals_P(TEXT_none)) {
setFpuType(FPU_NONE);
#if !defined(LIBASM_I8086_NOFPU) && !defined(LIBASM_I8086_NOFPU)
#if !defined(LIBASM_I8086_NOFPU)
} else if (scan.expectTrue() || p.iequals_P(TEXT_FPU_8087)) {
setFpuType(FPU_I8087);
#endif
Expand Down Expand Up @@ -619,7 +619,7 @@ void AsmI8086::emitStringInst(AsmInsn &insn, const Operand &dst, const Operand &
}
}

#if !defined(LIBASM_ASM_NOFLOAT) && !defined(LIBASM_I8086_NOFPU)
#if !defined(LIBASM_ASM_NOFLOAT)

Error AsmInsn::emitPackedDecimal(int64_t val64) {
const auto sign = val64 < 0 ? 0x80 : 0;
Expand All @@ -642,66 +642,92 @@ Error AsmInsn::emitTemporaryReal(const float80_t &val80) {
#endif

Error AsmI8086::defineDataConstant(
AsmInsn &insn, StrScanner &scan, I8087Type type, ErrorAt &error) const {
AsmInsn &insn, StrScanner &scan, I8087Type type, ErrorAt &_error) const {
ErrorAt error;
do {
auto p = scan.skipSpaces();
ErrorAt strErr, exprErr;
if (type == DATA_DD && isString(p, strErr) == OK) {
generateString(scan, p, insn.insnBase(), DATA_LONG, error);
} else {
const auto at = p;
const auto val = parseExpr(p, exprErr);
if ((endOfLine(p) || *p == ',') && !exprErr.hasError()) {
switch (type) {
case DATA_DD:
if (val.isInteger()) {
if (val.overflowUint32()) {
error.setErrorIf(at, OVERFLOW_RANGE);
} else if (insn.emitUint32(val.getUnsigned())) {
error.setAt(at);
}
} else {
#if !defined(LIBASM_ASM_NOFLOAT) && !defined(LIBASM_I8086_NOFPU)
if (insn.emitFloat32(val.getFloat()))
error.setAt(at);
scan.skipSpaces();
ErrorAt strErr;
if (type == DATA_DD) {
auto end = scan;
const auto err = isString(end, strErr);
if (err == OK) {
generateString(scan, end, insn.insnBase(), DATA_LONG, strErr);
if (error.setErrorIf(strErr) == NO_MEMORY)
break;
continue;
}
}
ErrorAt exprErr;
auto p = scan;
const auto val = parseExpr(p, exprErr);
if (!endOfLine(p) && *p != ',') {
if (strErr.getError()) {
error.setErrorIf(strErr);
} else {
error.setErrorIf(scan, ILLEGAL_CONSTANT);
}
break;
}
if (exprErr.hasError()) {
error.setErrorIf(strErr.getError() ? strErr : exprErr);
break;
}
switch (type) {
case DATA_DD:
if (val.isInteger()) {
if (val.overflowUint32()) {
exprErr.setErrorIf(scan, OVERFLOW_RANGE);
} else {
exprErr.setErrorIf(scan, insn.emitUint32(val.getUnsigned()));
}
} else {
#if !defined(LIBASM_ASM_NOFLOAT)
exprErr.setErrorIf(scan, insn.emitFloat32(val.getFloat()));
#else
error.setErrorIf(at, INTEGER_REQUIRED);
exprErr.setErrorIf(scan, FLOAT_NOT_SUPPORTED);
insn.emitUint32(0);
#endif
}
break;
#if !defined(LIBASM_ASM_NOFLOAT) && !defined(LIBASM_I8086_NOFPU)
case DATA_DQ:
if (val.isInteger()) {
if (insn.emitUint64(val.getInteger()))
error.setAt(at);
} else if (insn.emitFloat64(val.getFloat())) {
error.setAt(at);
}
break;
case DATA_DT:
if (val.isInteger()) {
constexpr auto PDEC80_MAX = INT64_C(999'999'999'999'999'999);
constexpr auto PDEC80_MIN = -INT64_C(999'999'999'999'999'999);
const auto v = val.getInteger();
if (v < PDEC80_MIN || v > PDEC80_MAX) {
error.setErrorIf(at, OVERFLOW_RANGE);
} else if (insn.emitPackedDecimal(v)) {
error.setAt(at);
}
} else if (insn.emitTemporaryReal(val.getFloat())) {
error.setAt(at);
}
break;
}
break;
case DATA_DQ:
#if defined(LIBASM_ASM_NOFLOAT)
exprErr.setErrorIf(scan, FLOAT_NOT_SUPPORTED);
insn.emitUint64(0);
#else
if (val.isInteger()) {
exprErr.setErrorIf(scan, insn.emitUint64(val.getInteger()));
} else {
exprErr.setErrorIf(scan, insn.emitFloat64(val.getFloat()));
}
#endif
break;
case DATA_DT:
#if defined(LIBASM_ASM_NOFLOAT)
exprErr.setErrorIf(scan, FLOAT_NOT_SUPPORTED);
insn.emitUint16(0);
insn.emitUint64(0);
#else
if (val.isInteger()) {
constexpr auto PDEC80_MAX = INT64_C(999'999'999'999'999'999);
constexpr auto PDEC80_MIN = -INT64_C(999'999'999'999'999'999);
const auto v = val.getInteger();
if (v < PDEC80_MIN || v > PDEC80_MAX) {
exprErr.setErrorIf(scan, OVERFLOW_RANGE);
} else {
exprErr.setErrorIf(scan, insn.emitPackedDecimal(v));
}
error.setErrorIf(exprErr);
scan = p;
} else {
error.setErrorIf(strErr);
exprErr.setErrorIf(scan, insn.emitTemporaryReal(val.getFloat()));
}
#endif
break;
}
} while (scan.skipSpaces().expect(',') && !error.hasError());
return error.getError();
scan = p;
error.setErrorIf(exprErr);
if (error.setErrorIf(exprErr) == NO_MEMORY)
break;
} while (scan.skipSpaces().expect(','));
return _error.setError(error);
}

Error AsmI8086::processPseudo(StrScanner &scan, Insn &_insn) {
Expand All @@ -713,12 +739,10 @@ Error AsmI8086::processPseudo(StrScanner &scan, Insn &_insn) {
}
if (strcasecmp_P(insn.name(), TEXT_DD) == 0)
return defineDataConstant(insn, scan, DATA_DD, _insn);
#if !defined(LIBASM_ASM_NOFLOAT) && !defined(LIBASM_I8086_NOFPU)
if (strcasecmp_P(insn.name(), TEXT_DQ) == 0)
return defineDataConstant(insn, scan, DATA_DQ, _insn);
if (strcasecmp_P(insn.name(), TEXT_DT) == 0)
return defineDataConstant(insn, scan, DATA_DT, _insn);
#endif
return Assembler::processPseudo(scan, _insn);
}

Expand Down
2 changes: 0 additions & 2 deletions src/asm_i8086.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,8 @@ struct AsmI8086 final : Assembler, Config {

enum I8087Type : char {
DATA_DD = 'D', // 32-bit binary or IEEE 754 floating point number
#if !defined(LIBASM_ASM_NOFLOAT) && !defined(LIBASM_I8086_NOFPU)
DATA_DQ = 'Q', // 64-bit binary or IEEE 754 floating point number
DATA_DT = 'T' // 80-bit BCD or i8087 Temporary Real
#endif
};
Error defineDataConstant(AsmInsn &insn, StrScanner &scan, I8087Type type, ErrorAt &error) const;
Error processPseudo(StrScanner &scan, Insn &insn) override;
Expand Down
Loading

0 comments on commit cc7abf1

Please sign in to comment.