better way of doing BIT instructions

This commit is contained in:
Irmen de Jong
2024-12-26 02:02:30 +01:00
parent 827df04b32
commit 056c0a24d9
13 changed files with 236 additions and 290 deletions
@@ -42,8 +42,6 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
"ror" -> funcRolRor(call)
"rol2" -> funcRolRor(call)
"ror2" -> funcRolRor(call)
"prog8_ifelse_bittest_set" -> throw AssemblyError("prog8_ifelse_bittest_set() should have been translated as part of an ifElse/ifExpression statement")
"prog8_ifelse_bittest_notset" -> throw AssemblyError("prog8_ifelse_bittest_notset() should have been translated as part of an ifElse/ifExpression statement")
"prog8_lib_stringcompare" -> funcStringCompare(call)
"prog8_lib_square_byte" -> funcSquare(call, IRDataType.BYTE)
"prog8_lib_square_word" -> funcSquare(call, IRDataType.WORD)
@@ -96,15 +96,46 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
if((ifExpr.condition as? PtPrefix)?.operator=="not")
throw AssemblyError("not prefix in ifexpression should have been replaced by swapped values")
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
val condTr = translateExpression(ifExpr.condition)
val result = mutableListOf<IRCodeChunkBase>()
val trueTr = translateExpression(ifExpr.truevalue)
val falseTr = translateExpression(ifExpr.falsevalue)
val irDt = irType(ifExpr.type)
val result = mutableListOf<IRCodeChunkBase>()
val falseLabel = codeGen.createLabelName()
val endLabel = codeGen.createLabelName()
val irDt = irType(ifExpr.type)
if(ifExpr.condition is PtBinaryExpression) {
val useBIT = checkIfConditionCanUseBIT(ifExpr.condition as PtBinaryExpression)
if(useBIT!=null) {
// use a BIT instruction to test for bit 7 or 6 set/clear
val (testBitSet, variable, bitmask) = useBIT
val bitBranchOpcode = when(testBitSet) {
true -> when(bitmask) {
64 -> Opcode.BSTVC
128 -> Opcode.BSTPOS
else -> throw AssemblyError("need bit 6 or 7")
}
false -> when(bitmask) {
64 -> Opcode.BSTVS
128 -> Opcode.BSTNEG
else -> throw AssemblyError("need bit 6 or 7")
}
}
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.BIT, IRDataType.BYTE, labelSymbol = variable.name)
it += IRInstruction(bitBranchOpcode, labelSymbol = falseLabel)
}
addToResult(result, trueTr, trueTr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null)
result += IRCodeChunk(falseLabel, null)
addToResult(result, falseTr, trueTr.resultReg, -1)
result += IRCodeChunk(endLabel, null)
return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1)
}
}
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
val condTr = translateExpression(ifExpr.condition)
addToResult(result, condTr, condTr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=condTr.resultReg, immediate = 0), null)
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = falseLabel), null)
@@ -533,7 +564,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
}
fun translate(fcall: PtFunctionCall): ExpressionCodeResult {
internal fun translate(fcall: PtFunctionCall): ExpressionCodeResult {
val callTarget = codeGen.symbolTable.flat.getValue(fcall.name)
if(callTarget.scopedName in listOf("sys.push", "sys.pushw", "sys.pop", "sys.popw", "floats.push", "floats.pop")) {
@@ -725,6 +756,31 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
}
internal fun checkIfConditionCanUseBIT(condition: PtBinaryExpression): Triple<Boolean, PtIdentifier, Int>? {
// test for occurrence of: x & 64 != 0 (or 128) , this can be performed with a BIT instruction
if(condition.operator == "==" || condition.operator == "!=") {
if (condition.right.asConstInteger() == 0) {
val and = condition.left as? PtBinaryExpression
if (and != null && and.operator == "&" && and.type.isUnsignedByte) {
val bitmask = and.right.asConstInteger()
if(bitmask==128 || bitmask==64) {
val variable = and.left as? PtIdentifier
if (variable != null && variable.type.isByte) {
return Triple(condition.operator=="!=", variable, bitmask)
}
val typecast = and.left as? PtTypeCast
if (typecast != null && typecast.type.isUnsignedByte) {
val castedVariable = typecast.value as? PtIdentifier
if(castedVariable!=null && castedVariable.type.isByte)
return Triple(condition.operator=="!=", castedVariable, bitmask)
}
}
}
}
}
return null
}
private fun translateStackFunctions(fcall: PtFunctionCall, callTarget: StNode): ExpressionCodeResult {
val chunk = mutableListOf<IRCodeChunkBase>()
when(callTarget.scopedName) {
@@ -1453,53 +1453,6 @@ class IRCodeGen(
val result = mutableListOf<IRCodeChunkBase>()
fun translateSimple(condition: PtExpression, jumpFalseOpcode: Opcode, addCmpiZero: Boolean) {
fun ifElseUsingBIT(testBitSet: Boolean, value: PtIdentifier, bitnumber: Int) {
addInstr(result, IRInstruction(Opcode.BIT, IRDataType.BYTE, labelSymbol = value.name), null)
val bitBranchOpcode = when(testBitSet) {
true -> when(bitnumber) {
6 -> Opcode.BSTVC
7 -> Opcode.BSTPOS
else -> throw AssemblyError("need bit 6 or 7")
}
false -> when(bitnumber) {
6 -> Opcode.BSTVS
7 -> Opcode.BSTNEG
else -> throw AssemblyError("need bit 6 or 7")
}
}
if(ifElse.hasElse()) {
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(bitBranchOpcode, labelSymbol = elseLabel), null)
result += translateNode(ifElse.ifScope)
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
result += IRCodeChunk(afterIfLabel, null)
} else {
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(bitBranchOpcode, labelSymbol = afterIfLabel), null)
result += translateNode(ifElse.ifScope)
result += IRCodeChunk(afterIfLabel, null)
}
}
if(condition is PtBuiltinFunctionCall && condition.name.startsWith("prog8_ifelse_bittest_")) {
// use a BIT instruction to test for bit 8 or 7
when(condition.name) {
"prog8_ifelse_bittest_set" -> {
ifElseUsingBIT(true, condition.args[0] as PtIdentifier, condition.args[1].asConstInteger()!!)
return
}
"prog8_ifelse_bittest_notset" -> {
ifElseUsingBIT(false, condition.args[0] as PtIdentifier, condition.args[1].asConstInteger()!!)
return
}
else -> throw AssemblyError("weird bittest")
}
}
val tr = expressionEval.translateExpression(condition)
if(addCmpiZero)
tr.chunks.last().instructions.add(IRInstruction(Opcode.CMPI, tr.dt, reg1 = tr.resultReg, immediate = 0))
@@ -1524,6 +1477,41 @@ class IRCodeGen(
if(condition.operator in LogicalOperators)
return translateSimple(condition, Opcode.BSTEQ, false)
val useBIT = expressionEval.checkIfConditionCanUseBIT(condition)
if(useBIT!=null) {
// use a BIT instruction to test for bit 7 or 6 set/clear
val (testBitSet, variable, bitmask) = useBIT
addInstr(result, IRInstruction(Opcode.BIT, IRDataType.BYTE, labelSymbol = variable.name), null)
val bitBranchOpcode = when(testBitSet) {
true -> when(bitmask) {
64 -> Opcode.BSTVC
128 -> Opcode.BSTPOS
else -> throw AssemblyError("need bit 6 or 7")
}
false -> when(bitmask) {
64 -> Opcode.BSTVS
128 -> Opcode.BSTNEG
else -> throw AssemblyError("need bit 6 or 7")
}
}
if(ifElse.hasElse()) {
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(bitBranchOpcode, labelSymbol = elseLabel), null)
result += translateNode(ifElse.ifScope)
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
result += IRCodeChunk(afterIfLabel, null)
} else {
val afterIfLabel = createLabelName()
addInstr(result, IRInstruction(bitBranchOpcode, labelSymbol = afterIfLabel), null)
result += translateNode(ifElse.ifScope)
result += IRCodeChunk(afterIfLabel, null)
}
return
}
val signed = condition.left.type.isSigned
val elseBranchFirstReg: Int
val elseBranchSecondReg: Int