mirror of
https://github.com/irmen/prog8.git
synced 2026-04-24 05:25:49 +00:00
better way of doing BIT instructions
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user