Build signextension of 32-bit imm in 64-bit "hack"(?) into getImmediate
MODIFY
src/assembler/instruction.h
src/assembler/instruction.h
@@ -194,15 +194,7 @@ struct Imm : public Field<Reg_T, Instr_T> {
symbolTransformer(_symbolTransformer) {}
int64_t getImm(const QString& immToken, bool& success) const {
- int64_t value = getImmediate(immToken, success);
-
- // This seems a tad too specific for RISC-V, but the official RISC-V tests expects the immediate of
- // i.e., "andi x14, x1, 0xffffff0f" to be accepted as a signed immediate, even in 64-bit.
- if (success && repr == Repr::Signed && (static_cast<uint32_t>(value >> 32) == 0) &&
- isInt(width, static_cast<int32_t>(value))) {
- value = static_cast<int32_t>(value);
- }
- return value;
+ return repr == Repr::Signed ? getImmediateSext32(immToken, success) : getImmediate(immToken, success);
}
std::optional<Error> apply(const TokenizedSrcLine& line, Instr_T& instruction,

MODIFY
src/assembler/parserutilities.cpp
src/assembler/parserutilities.cpp
@@ -7,6 +7,7 @@ namespace Assembler {
int64_t getImmediate(const QString& string, bool& canConvert, ImmConvInfo* convInfo) {
QString upperString = string.toUpper();
+ QString trimmed;
canConvert = false;
int64_t immediate = upperString.toLongLong(&canConvert, 10);
int64_t sign = 1;
@@ -18,15 +19,19 @@ int64_t getImmediate(const QString& string, bool& canConvert, ImmConvInfo* convI
upperString.remove(0, 1);
}
if (upperString.startsWith(QLatin1String("0X"))) {
+ trimmed = upperString.remove("0X");
if (convInfo) {
convInfo->isUnsigned = true;
+ convInfo->is32bit = trimmed.size() <= 8;
}
- immediate = upperString.remove("0X").toULongLong(&canConvert, 16);
+ immediate = trimmed.toULongLong(&canConvert, 16);
} else if (upperString.startsWith(QLatin1String("0B"))) {
+ trimmed = upperString.remove("0B");
if (convInfo) {
convInfo->isUnsigned = true;
+ convInfo->is32bit = trimmed.size() <= 32;
}
- immediate = upperString.remove("0B").toULongLong(&canConvert, 2);
+ immediate = trimmed.toULongLong(&canConvert, 2);
} else {
canConvert = false;
}
@@ -35,6 +40,18 @@ int64_t getImmediate(const QString& string, bool& canConvert, ImmConvInfo* convI
return sign * immediate;
}
+int64_t getImmediateSext32(const QString& string, bool& success) {
+ ImmConvInfo convInfo;
+ int64_t value = getImmediate(string, success, &convInfo);
+
+ // This seems a tad too specific for RISC-V, but the official RISC-V tests expects the immediate of
+ // i.e., "andi x14, x1, 0xffffff0f" to be accepted as a signed immediate, even in 64-bit.
+ if (success && (static_cast<uint32_t>(value >> 32) == 0) && convInfo.is32bit) {
+ value = static_cast<int32_t>(value);
+ }
+ return value;
+}
+
/**
* @brief joinParentheses takes a number of tokens and merges together tokens contained within top-level parentheses.
* For example:

MODIFY
src/assembler/parserutilities.h
src/assembler/parserutilities.h
@@ -11,9 +11,11 @@ namespace Assembler {
struct ImmConvInfo {
bool isUnsigned = false;
+ bool is32bit = false;
};
int64_t getImmediate(const QString& string, bool& canConvert, ImmConvInfo* convInfo = nullptr);
+int64_t getImmediateSext32(const QString& string, bool& canConvert);
/**
* @brief joinParentheses takes a number of tokens and merges together tokens contained within top-level parentheses.

MODIFY
src/assembler/rv32i_assembler.h
src/assembler/rv32i_assembler.h
@@ -205,7 +205,7 @@ void RV32I_Assembler::extI<Reg__T, Instr__T>::enable(const ISAInfoBase* isa, _In
bool canConvert;
bool liveDstReg = false;
bool unsignedFitErr = false;
- int64_t immediate = getImmediate(line.tokens.at(2), canConvert);
+ int64_t immediate = getImmediateSext32(line.tokens.at(2), canConvert);
if (!canConvert) {
// Check if the immediate has been made available in the symbol set at this point...
@@ -231,10 +231,7 @@ void RV32I_Assembler::extI<Reg__T, Instr__T>::enable(const ISAInfoBase* isa, _In
* code.
*/
std::function<PseudoExpandRes(int64_t, bool)> genInstrSeq = [&](int64_t val, bool isRV64) {
- // LLVM has preconversion of all immediates into a sign-extended 64-bit version, and only checks
- // int32. getImmediate, as used above, does not sign-extend unsigned immediates. Therefore we must
- // go into the terminal case when @p val is either representable as uint32 or int32.
- if (isUInt<32>(val) || isInt<32>(val)) {
+ if (isInt<32>(val)) {
int64_t Hi20 = ((val + 0x800) >> 12) & 0xFFFFF;
int64_t Lo12 = vsrtl::signextend<12>(val);
if (Hi20) {

Build signextension of 32-bit imm in 64-bit "hack"(?) into getImmediate