Changeset 108853 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Apr 4, 2025 2:27:50 PM (5 weeks ago)
- svn:sync-xref-src-repo-rev:
- 168303
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/target-armv8/bsd-spec-analyze.py
r108848 r108853 150 150 def fromJson(oJson): 151 151 """ Decodes an AST/Values expression. """ 152 print('debug ast: %s' % oJson['_type'])152 #print('debug ast: %s' % oJson['_type']) 153 153 return ArmAstBase.kfnTypeMap[oJson['_type']](oJson); 154 154 … … 178 178 self.oRight = oRight; 179 179 180 # Switch value == field non-sense (simplifies transferConditionsToEncoding and such): 181 if ( isinstance(oRight, ArmAstIdentifier) 182 and isinstance(oLeft, [ArmAstValue, ArmAstInteger]) 183 and sOp in ['==', '!=']): 184 self.oLeft = oRight; 185 self.oRight = oLeft; 186 187 @staticmethod 188 def needParentheses(oNode, sOp = '&&'): 189 if isinstance(oNode, ArmAstBinaryOp): 190 if sOp != '&&' or oNode.sOp in ('||', '+'): 191 return True; 192 return False; 193 194 def toString(self): 195 sLeft = self.oLeft.toString(); 196 if ArmAstBinaryOp.needParentheses(self.oLeft, self.sOp): 197 sLeft = '(%s)' % (sLeft); 198 199 sRight = self.oRight.toString(); 200 if ArmAstBinaryOp.needParentheses(self.oRight, self.sOp): 201 sRight = '(%s)' % (sRight); 202 203 return '%s %s %s' % (sLeft, self.sOp, sRight); 180 204 181 205 class ArmAstUnaryOp(ArmAstBase): … … 191 215 self.oExpr = oExpr; 192 216 217 def toString(self): 218 if ArmAstBinaryOp.needParentheses(self.oExpr): 219 return '%s(%s)' % (self.sOp, self.oExpr.toString(),); 220 return '%s%s' % (self.sOp, self.oExpr.toString(),); 193 221 194 222 class ArmAstSquareOp(ArmAstBase): … … 197 225 self.aoValues = aoValues; 198 226 227 def toString(self): 228 return '<%s>' % (','.join([oValue.toString() for oValue in self.aoValues]),); 229 199 230 200 231 class ArmAstConcat(ArmAstBase): … … 203 234 self.aoValues = aoValues; 204 235 236 def toString(self): 237 sRet = ''; 238 for oValue in self.aoValues: 239 if sRet: 240 sRet += ':' 241 if isinstance(oValue, ArmAstIdentifier): 242 sRet += oValue.sName; 243 else: 244 sRet += '(%s)' % (oValue.toString()); 245 return sRet; 205 246 206 247 class ArmAstFunction(ArmAstBase): … … 210 251 ArmAstBase.__init__(self, ArmAstBase.kTypeFunction); 211 252 assert self.s_oReValidName.match(sName), 'sName=%s' % (sName); 212 self.sName = sName; 213 self.aoValues = aoArgs; 214 253 self.sName = sName; 254 self.aoArgs = aoArgs; 255 256 def toString(self): 257 return '%s(%s)' % (self.sName, ','.join([oArg.toString() for oArg in self.aoArgs]),); 215 258 216 259 class ArmAstIdentifier(ArmAstBase): … … 222 265 self.sName = sName; 223 266 267 def toString(self): 268 return self.sName; 224 269 225 270 class ArmAstBool(ArmAstBase): … … 229 274 self.fValue = fValue; 230 275 276 def toString(self): 277 return 'true' if self.fValue is True else 'false'; 278 231 279 232 280 class ArmAstInteger(ArmAstBase): … … 235 283 self.iValue = int(iValue); 236 284 285 def toString(self): 286 return '%#x' % (self.iValue,); 237 287 238 288 class ArmAstSet(ArmAstBase): … … 241 291 self.aoValues = aoValues; 242 292 293 def toString(self): 294 return '(%s)' % (', '.join([oValue.toString() for oValue in self.aoValues]),); 243 295 244 296 class ArmAstValue(ArmAstBase): … … 246 298 ArmAstBase.__init__(self, ArmAstBase.kTypeValue); 247 299 self.sValue = sValue; 300 301 def toString(self): 302 return self.sValue; 248 303 249 304 … … 284 339 285 340 @staticmethod 286 def fromJson(oJson): 287 """ """ 288 assert oJson['_type'] in ('Instruction.Encodeset.Field', 'Instruction.Encodeset.Bits'), oJson['_type']; 289 290 oRange = oJson['range']; 291 assert oRange['_type'] == 'Range'; 292 iFirstBit = int(oRange['start']); 293 cBitsWidth = int(oRange['width']); 294 295 sValue = oJson['value']['value']; 341 def parseValue(sValue, cBitsWidth): 342 """ 343 Returns (fValue, fFixed) tuple on success, raises AssertionError otherwise. 344 """ 296 345 assert sValue[0] == '\'' and sValue[-1] == '\'', sValue; 297 346 sValue = sValue[1:-1]; … … 307 356 if ch == '1': 308 357 fValue |= 1; 309 310 sName = oJson['name'] if oJson['_type'] == 'Instruction.Encodeset.Field' else None; 358 return (fValue, fFixed); 359 360 @staticmethod 361 def fromJson(oJson): 362 """ """ 363 assert oJson['_type'] in ('Instruction.Encodeset.Field', 'Instruction.Encodeset.Bits'), oJson['_type']; 364 365 oRange = oJson['range']; 366 assert oRange['_type'] == 'Range'; 367 iFirstBit = int(oRange['start']); 368 cBitsWidth = int(oRange['width']); 369 sName = oJson['name'] if oJson['_type'] == 'Instruction.Encodeset.Field' else None; 370 (fValue, fFixed) = ArmEncodesetField.parseValue(oJson['value']['value'], cBitsWidth); 311 371 return ArmEncodesetField(oJson, iFirstBit, cBitsWidth, fFixed, fValue, sName); 312 372 … … 384 444 parseInstructions([oJson,] + aoStack, oJson['children']); 385 445 elif oJson['_type'] == "Instruction.Instruction": 446 sInstrNm = oJson['name']; 447 386 448 (aoEncodesets, fCovered) = ArmEncodesetField.fromJsonEncodeset(oJson['encoding'], [], 0); 387 449 for oParent in aoStack: 388 450 if 'encoding' in oParent: 389 451 (aoEncodesets, fCovered) = ArmEncodesetField.fromJsonEncodeset(oParent['encoding'], aoEncodesets, fCovered); 452 390 453 oCondition = ArmAstBase.fromJson(oJson['condition']); 391 oInstr = ArmInstruction(oJson, oJson['name'], oJson['name'], aoEncodesets, oCondition); 454 print('debug transfer in: %s' % (oCondition.toString())); 455 (oCondition, fMod) = transferConditionsToEncoding(oCondition, aoEncodesets, collections.defaultdict(list), sInstrNm); 456 if fMod: 457 print('debug transfer out: %s' % (oCondition.toString())); 458 459 oInstr = ArmInstruction(oJson, sInstrNm, sInstrNm, aoEncodesets, oCondition); 392 460 393 461 g_aoAllArmInstructions.append(oInstr); … … 395 463 g_dAllArmInstructionsByName[oInstr.sName] = oInstr; 396 464 return True; 465 466 def transferConditionsToEncoding(oCondition, aoEncodesets, dPendingNotEq, sInstrNm, uDepth = 0, fMod = False): 467 """ 468 This is for dealing with stuff like asr_z_p_zi_ and lsr_z_p_zi_ which has 469 the same fixed encoding fields in the specs, but differs in the value of 470 the named field 'U' as expressed in the conditions. 471 472 This function will recursively take 'Field == value/integer' expression out 473 of the condition tree and add them to the encodeset conditions when possible. 474 475 The dPendingNotEq stuff is a hack to deal with stuff like this: 476 sdot_z_zzz_: U == '0' && size != '01' && size != '00' 477 && (IsFeatureImplemented(FEAT_SVE) || IsFeatureImplemented(FEAT_SME)) 478 The checks can be morphed into the 'size' field encoding criteria as '0b0x'. 479 """ 480 def isBoolTrue(oNode): 481 return isinstance(oNode, ArmAstBool) and oNode.fValue is True; 482 483 if isinstance(oCondition, ArmAstBinaryOp): 484 if oCondition.sOp == '&&': 485 print('debug transfer: %s: recursion...' % (sInstrNm,)); 486 # Recurse into each side of an AND expression. 487 (oCondition.oLeft, fMod) = transferConditionsToEncoding(oCondition.oLeft, aoEncodesets, dPendingNotEq, 488 sInstrNm, uDepth + 1, fMod); 489 (oCondition.oRight, fMod) = transferConditionsToEncoding(oCondition.oRight, aoEncodesets, dPendingNotEq, 490 sInstrNm, uDepth + 1, fMod); 491 if isBoolTrue(oCondition.oLeft): 492 return (oCondition.oRight, fMod); 493 if isBoolTrue(oCondition.oRight): 494 return (oCondition.oLeft, fMod); 495 496 elif oCondition.sOp in ('==', '!='): 497 # The pattern we're looking for is identifier (field) == fixed value. 498 print('debug transfer: %s: binaryop %s vs %s ...' % (sInstrNm, oCondition.oLeft.sType, oCondition.oRight.sType)); 499 if ( isinstance(oCondition.oLeft, ArmAstIdentifier) 500 and isinstance(oCondition.oRight, (ArmAstValue, ArmAstInteger))): 501 sFieldName = oCondition.oLeft.sName; 502 oValue = oCondition.oRight; 503 print('debug transfer: %s: binaryop step 2...' % (sInstrNm,)); 504 for oField in aoEncodesets: # ArmEncodesetField 505 if oField.sName and oField.sName == sFieldName: 506 # ArmAstInteger (unlikely): 507 if isinstance(oValue, ArmAstInteger): 508 if oField.fFixed != 0: 509 raise Exception('%s: Condition checks fixed field value: %s (%#x/%#x) %s %s' 510 % (sInstrNm, oField.sName, oField.fValue, oField.fFixed, 511 oCondition.sOp, oValue.iValue,)); 512 assert oField.fValue == 0; 513 if oValue.iValue.bit_length() > oField.cBitsWidth: 514 raise Exception('%s: Condition field value check too wide: %s is %u bits, test value is %s (%u bits)' 515 % (sInstrNm, oField.sName, oField.cBitsWidth, oValue.iValue, 516 oValue.iValue.bit_count(),)); 517 if oValue.iValue < 0: 518 raise Exception('%s: Condition field checks against negative value: %s, test value is %s' 519 % (sInstrNm, oField.sName, oValue.iValue)); 520 fFixed = (1 << oField.cBitsWidth) - 1; 521 if oCondition.sOp == '!=' and oField.cBitsWidth > 1: 522 dPendingNotEq[oField.sName] += [(oField, oValue.iValue, fFixed, oCondition)]; 523 break; 524 525 print('debug transfer: %s: integer binaryop -> encoding!' % (sInstrNm,)); 526 if oCondition.sOp == '==': 527 oField.fValue = oValue.iValue; 528 else: 529 oField.fValue = ~oValue.iValue & fFixed; 530 oField.fFixed = fFixed; 531 return (ArmAstBool(True), True); 532 533 # ArmAstValue. 534 assert isinstance(oValue, ArmAstValue); 535 (fValue, fFixed) = ArmEncodesetField.parseValue(oValue.sValue, oField.cBitsWidth); 536 537 if oCondition.sOp == '!=' and oField.cBitsWidth > 1 and (fFixed & (fFixed - 1)) != 0: 538 dPendingNotEq[oField.sName] += [(oField, fValue, fFixed, oCondition)]; 539 break; 540 if fFixed & oField.fFixed: 541 raise Exception('%s: Condition checks fixed field value: %s (%#x/%#x) %s %s (%#x/%#x)' 542 % (sInstrNm, oField.sName, oField.fValue, oField.fFixed, oCondition.sOp, 543 oValue.sValue, fValue, fFixed)); 544 print('debug transfer: %s: value binaryop -> encoding! %s %s %#x (fFixed=%#x)' 545 % (sInstrNm, oField.sName, oCondition.sOp, fValue, fFixed,)); 546 if oCondition.sOp == '==': 547 oField.fValue |= fValue; 548 else: 549 oField.fValue |= ~fValue & fFixed; 550 oField.fFixed |= fFixed; 551 return (ArmAstBool(True), True); 552 553 # 554 # Deal with pending '!=' optimizations for fields larger than a single bit. 555 # Currently we only deal with two bit fields. 556 # 557 if uDepth == 0 and dPendingNotEq: 558 for sFieldNm, atOccurences in dPendingNotEq.items(): 559 # For a two bit field, we need at least two occurences to get any kind of fixed value. 560 oField = atOccurences[0][0]; 561 if oField.cBitsWidth == 2 and len(atOccurences) >= 2: 562 dValues = {}; 563 dFixed = {}; 564 for oCurField, fValue, fFixed, _ in atOccurences: 565 assert oCurField is oField; 566 dValues[fValue] = 1; 567 dFixed[fFixed] = 1; 568 if len(dValues) in (2, 3) and len(dFixed) == 1 and 3 in dFixed: 569 afValues = list(dValues); 570 if len(dValues) == 2: 571 fFixed = 2 if (afValues[0] ^ afValues[1]) & 1 else 1; # One of the bits are fixed, the other ignored. 572 else: 573 fFixed = 3; # Both bits are fixed. 574 fValue = afValues[0] & fFixed; 575 print('debug transfer: %s: %u binaryops -> encoding! %s != %#x/%#x' 576 % (sInstrNm, len(atOccurences), oField.sName, fValue, fFixed,)); 577 578 # Remove the associated conditions (they'll be leaves). 579 aoToRemove = [oCondition for _, _, _, oCondition in atOccurences]; 580 def recursiveRemove(oCondition): 581 if isinstance(oCondition, ArmAstBinaryOp): 582 if oCondition.sOp == '&&': 583 oCondition.oLeft = recursiveRemove(oCondition.oLeft); 584 oCondition.oRight = recursiveRemove(oCondition.oLeft); 585 if isBoolTrue(oCondition.oLeft): return oCondition.oRight; 586 if isBoolTrue(oCondition.oRight): return oCondition.oLeft; 587 elif oCondition in aoToRemove: 588 assert isinstance(oCondition.oLeft, ArmAstIdentifier); 589 assert isinstance(oCondition.oRight, (ArmAstValue, ArmAstInteger)); 590 assert oCondition.sOp == '!='; 591 return ArmAstBool(True); 592 return oCondition; 593 oCondition = recursiveRemove(oCondition); 594 fMod = True; 595 else: 596 print('info: %s: transfer cond to enc failed for: %s dValues=%s dFixed=%s' 597 % (sInstrNm, oField.sName, dValues, dFixed)); 598 elif oField.cBitsWidth == 3 and len(atOccurences) >= 7: 599 print('info: %s: TODO: transfer cond to enc for 3 bit field: %s (%s)' % (sInstrNm, oField.sName, atOccurences,)); 600 601 return (oCondition, fMod); 602 397 603 398 604 #
Note:
See TracChangeset
for help on using the changeset viewer.