FoxAssembler.Mod 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. MODULE FoxAssembler; (** AUTHOR "fof"; PURPOSE "Oberon Assembler: Generic Part"; **)
  2. (* (c) fof ETH Zürich, 2009 *)
  3. IMPORT Streams, Strings, Diagnostics,D := Debugging, Commands, BinaryCode := FoxBinaryCode, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal,
  4. IntermediateCode := FoxIntermediateCode, Sections := FoxSections, Scanner := FoxScanner, Basic := FoxBasic, SYSTEM, ObjectFile;
  5. CONST
  6. Trace* = FALSE; (* debugging output *)
  7. MaxOperands* = 3;
  8. (*
  9. currently there is conceptual support for one-pass assembly with a fixup mechanism for section-local references
  10. disadvantages of one-pass assembly:
  11. - expressions with labels would not work
  12. - fixup mechanism complicated and not generic
  13. *)
  14. MaxPasses* = 2;
  15. ConstantInteger* = 0;
  16. ConstantFloat* = 1;
  17. Fixup* = 2;
  18. Offset* = 3;
  19. ConstantIntegerOrOffset* = {ConstantInteger, Offset};
  20. TYPE
  21. OperandString=ARRAY 256 OF CHAR;
  22. Position= Basic.Position;
  23. FixupElement=POINTER TO RECORD
  24. fixup: BinaryCode.Fixup; next: FixupElement;
  25. END;
  26. NamedLabel*= OBJECT
  27. VAR
  28. section: IntermediateCode.Section;
  29. offset, displacement: LONGINT; (* in contrast to offset, displacement will be reset each round of assembling. This is to make sure that GetFixup generates the right displacement in the fixup *)
  30. name-: Scanner.IdentifierString;
  31. nextNamedLabel-: NamedLabel;
  32. fixupList: FixupElement;
  33. PROCEDURE &InitNamedLabel(section: IntermediateCode.Section; CONST name: ARRAY OF CHAR);
  34. BEGIN
  35. fixupList := NIL;
  36. SELF.offset := 0; (* must be zero to be able to track local displacement *)
  37. SELF.section := section;
  38. COPY(name,SELF.name);
  39. nextNamedLabel := NIL;
  40. END InitNamedLabel;
  41. PROCEDURE GetFixup(): BinaryCode.Fixup;
  42. VAR fixup: BinaryCode.Fixup; element: FixupElement; identifier: ObjectFile.Identifier;
  43. BEGIN
  44. identifier.name := section.name;
  45. fixup := BinaryCode.NewFixup(BinaryCode.Absolute,0,identifier,0,displacement,0,NIL);
  46. NEW(element); element.fixup := fixup; element.next := fixupList; fixupList := element;
  47. RETURN fixup;
  48. END GetFixup;
  49. PROCEDURE ResetDisplacements;
  50. VAR element: FixupElement;
  51. BEGIN
  52. displacement := 0;
  53. element := fixupList;
  54. WHILE element # NIL DO
  55. element.fixup.SetSymbol(section.name,0,0,0);
  56. element := element.next;
  57. END;
  58. END ResetDisplacements;
  59. PROCEDURE SetOffset*(ofs: LONGINT);
  60. VAR element: FixupElement;
  61. BEGIN
  62. SELF.offset := ofs;
  63. displacement := ofs;
  64. element := fixupList;
  65. WHILE element # NIL DO
  66. element.fixup.SetSymbol(section.name,0,0,element.fixup.displacement (* must be here to take into account modifications of code emission *) +displacement);
  67. element := element.next;
  68. END;
  69. END SetOffset;
  70. END NamedLabel;
  71. NamedLabelList*=OBJECT
  72. VAR first-,last-: NamedLabel;
  73. PROCEDURE & InitNamedLabelList;
  74. BEGIN first := NIL; last := NIL
  75. END InitNamedLabelList;
  76. PROCEDURE Add*(n: NamedLabel);
  77. BEGIN
  78. IF first = NIL THEN first := n ELSE last.nextNamedLabel := n; last.nextNamedLabel := n; END; last := n;
  79. END Add;
  80. PROCEDURE ResetDisplacements;
  81. VAR label: NamedLabel;
  82. BEGIN
  83. label := first;
  84. WHILE label # NIL DO label.ResetDisplacements; label := label.nextNamedLabel END;
  85. END ResetDisplacements;
  86. PROCEDURE Find*(CONST name: ARRAY OF CHAR): NamedLabel;
  87. VAR label: NamedLabel;
  88. BEGIN
  89. label := first;
  90. WHILE (label # NIL) & (label.name # name) DO
  91. label := label.nextNamedLabel;
  92. END;
  93. RETURN label
  94. END Find;
  95. END NamedLabelList;
  96. Result*= RECORD
  97. type*: INTEGER; (* ConstantInteger, ConstantFloat, Fixup, Offset *)
  98. sizeInBits*: INTEGER;
  99. value*: LONGINT; (*! implementation restriction: operations between hugeints do not yet work *)
  100. valueR*: LONGREAL;
  101. fixup*: BinaryCode.Fixup;
  102. END;
  103. NamedResult*=POINTER TO RECORD (Result)
  104. name: Scanner.IdentifierString;
  105. nextResult: NamedResult;
  106. END;
  107. NamedResultList*=OBJECT
  108. VAR first, last: NamedResult; number: LONGINT;
  109. PROCEDURE & InitNamedResultList;
  110. BEGIN first := NIL; last := NIL; number := 0;
  111. END InitNamedResultList;
  112. PROCEDURE Add*(n: NamedResult);
  113. BEGIN
  114. IF first = NIL THEN first := n ELSE last.nextResult := n END; last := n; INC(number);
  115. END Add;
  116. PROCEDURE Find*(CONST name: ARRAY OF CHAR): NamedResult;
  117. VAR result: NamedResult;
  118. BEGIN
  119. result := first;
  120. WHILE (result # NIL) & (result.name # name) DO
  121. result := result.nextResult;
  122. END;
  123. RETURN result
  124. END Find;
  125. END NamedResultList;
  126. Assembler*= OBJECT
  127. VAR
  128. diagnostics: Diagnostics.Diagnostics;
  129. error-: BOOLEAN;
  130. errorPosition-: Position;
  131. symbol-: Scanner.Symbol;
  132. scanner: Scanner.AssemblerScanner;
  133. orgOffset: LONGINT;
  134. section-: IntermediateCode.Section;
  135. code-: BinaryCode.Section;
  136. labels: NamedLabelList;
  137. results: NamedResultList;
  138. scope: SyntaxTree.Scope;
  139. module: Sections.Module;
  140. pass-: LONGINT;
  141. PROCEDURE &Init*(diagnostics: Diagnostics.Diagnostics);
  142. BEGIN
  143. SELF.diagnostics := diagnostics; errorPosition := Basic.invalidPosition; orgOffset := 0;
  144. END Init;
  145. PROCEDURE SetContext(CONST context: Scanner.Context);
  146. BEGIN
  147. scanner.SetContext(context); NextSymbol;
  148. END SetContext;
  149. PROCEDURE Error*(pos: SyntaxTree.Position; CONST msg: ARRAY OF CHAR);
  150. BEGIN
  151. error := TRUE;
  152. Basic.Error(diagnostics, scanner.source^,pos, msg);
  153. END Error;
  154. PROCEDURE ErrorSS*(pos: SyntaxTree.Position; CONST s1,s2: ARRAY OF CHAR);
  155. VAR msg: Basic.MessageString;
  156. BEGIN COPY(s1,msg); Strings.Append(msg,s2); Error(pos, msg);
  157. END ErrorSS;
  158. PROCEDURE NextSymbol*;
  159. BEGIN error := error OR ~scanner.GetNextSymbol(symbol); errorPosition := symbol.position;
  160. END NextSymbol;
  161. PROCEDURE ThisToken*(x: LONGINT): BOOLEAN;
  162. BEGIN
  163. IF ~error & (symbol.token = x) THEN NextSymbol; RETURN TRUE ELSE RETURN FALSE END;
  164. END ThisToken;
  165. PROCEDURE GetIdentifier*(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
  166. BEGIN
  167. pos := symbol.position;
  168. IF symbol.token # Scanner.Identifier THEN RETURN FALSE
  169. ELSE COPY(symbol.identifierString,identifier); NextSymbol; RETURN TRUE
  170. END;
  171. END GetIdentifier;
  172. PROCEDURE ThisIdentifier*(CONST this: ARRAY OF CHAR): BOOLEAN;
  173. BEGIN
  174. IF ~error & (symbol.token = Scanner.Identifier) & (this = symbol.identifierString) THEN NextSymbol; RETURN TRUE ELSE RETURN FALSE END;
  175. END ThisIdentifier;
  176. PROCEDURE ExpectIdentifier*(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
  177. BEGIN
  178. IF ~GetIdentifier(pos,identifier)THEN Error(errorPosition,"identifier expected"); RETURN FALSE
  179. ELSE RETURN TRUE
  180. END;
  181. END ExpectIdentifier;
  182. PROCEDURE ExpectToken*(x: LONGINT): BOOLEAN;
  183. VAR s: Basic.MessageString;
  184. BEGIN
  185. IF ThisToken(x) THEN RETURN TRUE
  186. ELSE
  187. s := "expected token "; Strings.Append(s,Scanner.tokens[x]); Strings.Append(s," but got "); Strings.Append(s,Scanner.tokens[symbol.token]);
  188. Error(errorPosition,s);RETURN FALSE
  189. END;
  190. END ExpectToken;
  191. PROCEDURE ExpectConstantInteger*(VAR x: Result; critical: BOOLEAN): BOOLEAN;
  192. VAR result: Result;
  193. BEGIN
  194. IF ~Expression(result,critical) OR (result.type # ConstantInteger) THEN
  195. result.value := 0;
  196. IF critical THEN Error(errorPosition,"constant integer expected") END;
  197. RETURN ~critical
  198. ELSE RETURN TRUE
  199. END
  200. END ExpectConstantInteger;
  201. PROCEDURE Section;
  202. VAR sectionType: Scanner.IdentifierString; pos: Position;
  203. BEGIN
  204. IF ExpectToken(Scanner.Period) THEN
  205. IF ExpectIdentifier(pos,sectionType) THEN
  206. IF sectionType = "data" THEN
  207. IF Trace THEN D.String("data section"); D.Ln END;
  208. (*! generate section here, if allowed *)
  209. ELSIF sectionType = "code" THEN
  210. IF Trace THEN D.String("code section"); D.Ln END;
  211. (*! generate section here, if allowed *)
  212. ELSE Error(pos,"expected data or code");
  213. END;
  214. END;
  215. END;
  216. END Section;
  217. PROCEDURE DefineLabel(pos: Position; CONST name: ARRAY OF CHAR);
  218. VAR label: NamedLabel;
  219. BEGIN
  220. IF Trace THEN D.String("define label: "); D.String(name); D.Ln END;
  221. IF labels.Find(name) # NIL THEN
  222. Error(pos,"multiply declared identifier")
  223. ELSE
  224. NEW(label,section,name);
  225. labels.Add(label);
  226. ASSERT(labels.Find(name) =label);
  227. END;
  228. END DefineLabel;
  229. PROCEDURE SetLabel(pos: Position; CONST name: ARRAY OF CHAR);
  230. VAR label: NamedLabel;
  231. BEGIN
  232. IF Trace THEN D.String("set label: "); D.String(name); D.String(" "); D.Int(code.pc,1); D.Ln END;
  233. label := labels.Find(name);
  234. label.SetOffset(code.pc);
  235. END SetLabel;
  236. PROCEDURE CopyResult(CONST from: Result; VAR to: Result);
  237. BEGIN
  238. to.type := from.type;
  239. to.sizeInBits := from.sizeInBits;
  240. to.value := from.value;
  241. to.valueR := from.valueR;
  242. to.fixup := from.fixup;
  243. END CopyResult;
  244. PROCEDURE DefineResult(pos: Position; CONST name: ARRAY OF CHAR; CONST r: Result);
  245. VAR result: NamedResult;
  246. BEGIN
  247. IF Trace THEN D.String("define result: "); D.String(name); D.Ln END;
  248. IF results.Find(name) # NIL THEN
  249. Error(pos,"multiply declared identifier")
  250. ELSE
  251. NEW(result); COPY(name,result.name);
  252. CopyResult(r,result^);
  253. results.Add(result);
  254. ASSERT(results.Find(name) =result);
  255. END;
  256. END DefineResult;
  257. PROCEDURE SetResult(CONST name: ARRAY OF CHAR; CONST r: Result);
  258. VAR result: NamedResult;
  259. BEGIN
  260. IF Trace THEN D.String("define result: "); D.String(name); D.Ln END;
  261. result := results.Find(name);
  262. CopyResult(r,result^);
  263. END SetResult;
  264. PROCEDURE SymbolInScope(CONST ident: ARRAY OF CHAR): SyntaxTree.Symbol;
  265. VAR sym: SyntaxTree.Symbol; localScope: SyntaxTree.Scope; identifier: SyntaxTree.Identifier;
  266. CONST Trace=FALSE;
  267. BEGIN
  268. IF scope = NIL THEN RETURN NIL END;
  269. localScope := scope;
  270. identifier := SyntaxTree.NewIdentifier(ident);
  271. IF Trace THEN D.String("GetScopeSymbol:"); D.String(ident); D.Ln; END;
  272. WHILE (sym = NIL) & (localScope # NIL) DO
  273. sym := localScope.FindSymbol(identifier);
  274. localScope := localScope.outerScope
  275. END;
  276. IF (sym # NIL) & (sym IS SyntaxTree.Import) THEN
  277. NextSymbol;
  278. IF ExpectToken(Scanner.Period) & (symbol.token = Scanner.Identifier) THEN
  279. identifier := SyntaxTree.NewIdentifier(symbol.identifierString);
  280. IF Trace THEN D.String("GetScopeSymbol :"); D.String(symbol.identifierString); D.Ln; END;
  281. localScope := sym(SyntaxTree.Import).module.moduleScope;
  282. sym := NIL;
  283. WHILE (sym = NIL) & (localScope # NIL) DO
  284. sym := localScope.FindSymbol(identifier);
  285. IF (sym # NIL) & (sym.access * SyntaxTree.Public = {}) THEN sym := NIL END;
  286. localScope := localScope.outerScope
  287. END;
  288. ELSE RETURN NIL
  289. END;
  290. END;
  291. IF Trace THEN IF sym = NIL THEN D.String("not found") ELSE D.String("found"); END; D.Ln; END;
  292. RETURN sym
  293. END SymbolInScope;
  294. PROCEDURE ConstantSymbol(pos: Position; constant: SyntaxTree.Constant; VAR result: Result): BOOLEAN;
  295. BEGIN
  296. IF constant.type.resolved IS SyntaxTree.CharacterType THEN
  297. result.value := ORD(constant.value.resolved(SyntaxTree.CharacterValue).value);
  298. result.valueR := result.value;
  299. result.type := ConstantInteger;
  300. ELSIF constant.type.resolved IS SyntaxTree.IntegerType THEN
  301. result.value := constant.value.resolved(SyntaxTree.IntegerValue).value;
  302. result.valueR := result.value;
  303. result.type := ConstantInteger;
  304. ELSIF constant.type.resolved IS SyntaxTree.FloatType THEN
  305. result.valueR := constant.value.resolved(SyntaxTree.RealValue).value;
  306. result.type := ConstantFloat;
  307. ELSE
  308. Error(pos,"incompatible constant");
  309. RETURN FALSE;
  310. END;
  311. result.sizeInBits := SHORT(module.system.SizeOf(constant.type));
  312. RETURN TRUE
  313. END ConstantSymbol;
  314. PROCEDURE GetFingerprint(symbol: SyntaxTree.Symbol): LONGINT;
  315. BEGIN
  316. IF (symbol # NIL) THEN RETURN symbol.fingerprint.shallow END;
  317. END GetFingerprint;
  318. PROCEDURE NonConstantSymbol(pos: Position; symbol: SyntaxTree.Symbol; VAR result: Result): BOOLEAN;
  319. VAR
  320. name: Basic.SegmentedName; moduleScope: SyntaxTree.Scope; fixupSection: IntermediateCode.Section;
  321. fixupPatternList: ObjectFile.FixupPatterns; identifier: ObjectFile.Identifier;
  322. BEGIN
  323. IF scope = NIL THEN RETURN FALSE END;
  324. moduleScope := scope.ownerModule.moduleScope;
  325. Global.GetSymbolSegmentedName(symbol,name);
  326. identifier.name := name;
  327. identifier.fingerprint := GetFingerprint(symbol);
  328. IF symbol.scope IS SyntaxTree.ModuleScope THEN (* symbol in module scope *)
  329. IF symbol IS SyntaxTree.Variable THEN (* global variable *)
  330. result.type := Fixup;
  331. result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
  332. (* generic fixup pattern list for generic implementation of data instruction etc. -- otherwise replaced during encoding *)
  333. NEW(fixupPatternList, 1);
  334. fixupPatternList[0].bits := result.sizeInBits;
  335. fixupPatternList[0].offset := 0;
  336. result.fixup := BinaryCode.NewFixup(BinaryCode.Absolute, 0, identifier, 0, 0, 0, fixupPatternList);
  337. ELSIF symbol IS SyntaxTree.Procedure THEN (* procedure *)
  338. IF symbol(SyntaxTree.Procedure).isInline THEN
  339. Error(pos,"forbidden reference to inline procedure"); RETURN FALSE
  340. ELSE
  341. result.type := Fixup;
  342. result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
  343. (* generic fixup pattern list for generic implementation of data instruction etc. -- otherwise replaced during encoding *)
  344. NEW(fixupPatternList, 1);
  345. fixupPatternList[0].bits := result.sizeInBits;
  346. fixupPatternList[0].offset := 0;
  347. result.fixup := BinaryCode.NewFixup(BinaryCode.Absolute, 0, identifier, 0, 0, 0, fixupPatternList);
  348. END;
  349. ELSE HALT(100);
  350. END;
  351. ELSIF symbol.scope IS SyntaxTree.ProcedureScope THEN (* symbol in procedure (local) scope *)
  352. IF symbol.scope # scope THEN
  353. Error(pos,"local symbol not in current scope");
  354. ELSE
  355. RETURN FALSE;
  356. IF (symbol IS SyntaxTree.Variable) OR (symbol IS SyntaxTree.Parameter) THEN
  357. result.type := Offset;
  358. result.value := symbol.offsetInBits DIV module.system.dataUnit;
  359. ASSERT(symbol.offsetInBits MOD module.system.dataUnit = 0);
  360. result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
  361. ELSE Error(pos,"forbidden symbol in local scope");
  362. END;
  363. END
  364. ELSIF symbol.scope IS SyntaxTree.RecordScope THEN (* symbol in record scope *)
  365. ELSE Error(pos,"symbol in forbidden scope"); RETURN FALSE
  366. END;
  367. RETURN TRUE
  368. END NonConstantSymbol;
  369. PROCEDURE GetNonConstant*(pos: Position; CONST ident: ARRAY OF CHAR; VAR result: Result): BOOLEAN;
  370. VAR symbol: SyntaxTree.Symbol; namedLabel: NamedLabel;
  371. name: Basic.SegmentedName;fixupPatternList: ObjectFile.FixupPatterns;
  372. string: ARRAY 256 OF CHAR;
  373. identifier: ObjectFile.Identifier;
  374. BEGIN
  375. namedLabel := labels.Find(ident);
  376. IF (namedLabel # NIL) THEN
  377. result.type := Fixup;
  378. result.fixup := namedLabel.GetFixup();
  379. RETURN TRUE
  380. END;
  381. IF ident[0] = "@" THEN
  382. result.type := Fixup;
  383. COPY(ident, string);
  384. Strings.Delete(string,0,1);
  385. Basic.ToSegmentedName(string, name);
  386. result.sizeInBits := 32;
  387. NEW(fixupPatternList, 1);
  388. fixupPatternList[0].bits := result.sizeInBits;
  389. fixupPatternList[0].offset := 0;
  390. identifier.name := name;
  391. identifier.fingerprint := 0;
  392. result.fixup := BinaryCode.NewFixup(BinaryCode.Absolute, 0, identifier, 0, 0, 0, fixupPatternList);
  393. RETURN TRUE
  394. END;
  395. symbol := SymbolInScope(ident);
  396. IF symbol = NIL THEN RETURN FALSE
  397. ELSIF symbol IS SyntaxTree.Constant THEN RETURN FALSE
  398. ELSE RETURN NonConstantSymbol(pos,symbol,result)
  399. END;
  400. END GetNonConstant;
  401. PROCEDURE LocalOffset(pos: Position; symbol: SyntaxTree.Symbol; VAR result: Result): BOOLEAN;
  402. BEGIN
  403. IF symbol.scope IS SyntaxTree.ProcedureScope THEN (* symbol in procedure (local) scope *)
  404. IF symbol.scope = scope THEN
  405. IF (symbol IS SyntaxTree.Variable) OR (symbol IS SyntaxTree.Parameter) THEN
  406. result.type := ConstantInteger;
  407. result.value := symbol.offsetInBits DIV module.system.dataUnit;
  408. ASSERT(symbol.offsetInBits MOD module.system.dataUnit = 0);
  409. result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
  410. RETURN TRUE
  411. END;
  412. END;
  413. END;
  414. RETURN FALSE
  415. END LocalOffset;
  416. PROCEDURE GetConstant*(pos: Position; CONST ident: ARRAY OF CHAR; VAR result: Result): BOOLEAN;
  417. VAR symbol: SyntaxTree.Symbol; namedResult: NamedResult;
  418. BEGIN
  419. namedResult := results.Find(ident);
  420. IF namedResult # NIL THEN CopyResult(namedResult^,result); RETURN TRUE END;
  421. symbol := SymbolInScope(ident);
  422. IF symbol = NIL THEN RETURN FALSE
  423. ELSIF symbol IS SyntaxTree.Constant THEN RETURN ConstantSymbol(pos,symbol(SyntaxTree.Constant),result)
  424. ELSIF LocalOffset(pos,symbol,result) THEN RETURN TRUE
  425. ELSE RETURN FALSE
  426. END;
  427. END GetConstant;
  428. PROCEDURE Factor (VAR x: Result; critical: BOOLEAN): BOOLEAN;
  429. VAR label: NamedLabel; identifier: Scanner.IdentifierString; pos: Position;
  430. BEGIN
  431. IF ThisToken(Scanner.Number) THEN
  432. (* ASSERT(symbol.numberType = Scanner.Integer); *)
  433. IF symbol.numberType = Scanner.Integer THEN
  434. x.value := symbol.integer
  435. ELSIF symbol.numberType = Scanner.Hugeint THEN
  436. (* note that 64 bit integer constants are not (yet) supported in expressions by the assembler.
  437. however, the scanner interprets large 32 bit integers as hugeints (because integers are always assumed to be signed). *)
  438. x.value := SYSTEM.VAL(LONGINT, symbol.hugeint); (* TODO: how to do that? *)
  439. ASSERT(x.value < 0); (* the resulting 32 bit integer must be negative when interpreted as a signed value *)
  440. END;
  441. x.type := ConstantInteger;
  442. RETURN TRUE;
  443. ELSIF ThisToken(Scanner.PC) THEN (* pc IN units ! *)
  444. x.value := code.pc;
  445. x.type := ConstantInteger; (* TODO: should it be 'x.type := Offset'? *)
  446. RETURN TRUE;
  447. ELSIF ThisToken(Scanner.PCOffset) THEN
  448. x.value := code.pc-orgOffset;
  449. x.type := ConstantInteger; (* TODO: should it be 'x.type := Offset'? *)
  450. RETURN TRUE;
  451. ELSIF GetIdentifier(pos,identifier) THEN
  452. label := labels.Find (identifier);
  453. IF label # NIL THEN
  454. x.value := label.offset;
  455. x.type := Offset;
  456. (*! deal with fixups ? / enter fixup ? *)
  457. RETURN TRUE;
  458. ELSIF GetConstant(errorPosition, identifier,x) THEN RETURN TRUE
  459. ELSIF ~critical & (pass # MaxPasses) THEN
  460. x.value := 0; x.type := ConstantInteger; RETURN TRUE
  461. ELSE Error(pos,"undefined symbol"); RETURN FALSE
  462. END;
  463. ELSIF ThisToken(Scanner.LeftParenthesis) THEN
  464. RETURN Expression (x, critical) & ExpectToken(Scanner.RightParenthesis);
  465. END;
  466. RETURN FALSE
  467. END Factor;
  468. (* term = Factor { ( "*" | "/" | "%" ) Factor } *)
  469. PROCEDURE Term (VAR x: Result; critical: BOOLEAN): BOOLEAN;
  470. VAR y: Result; op : LONGINT;
  471. BEGIN
  472. IF Factor (x, critical) THEN
  473. WHILE (symbol.token = Scanner.Times) OR (symbol.token = Scanner.Div) OR (symbol.token = Scanner.Mod) DO
  474. op := symbol.token; NextSymbol;
  475. IF Factor (y, critical) THEN
  476. IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
  477. IF op = Scanner.Times THEN x.value := x.value * y.value
  478. ELSIF op = Scanner.Div THEN x.value := x.value DIV y.value
  479. ELSE x.value := x.value MOD y.value
  480. END;
  481. ELSIF (x.type = ConstantFloat) OR (y.type = ConstantFloat) THEN
  482. IF op = Scanner.Times THEN x.valueR := x.valueR * y.valueR
  483. ELSIF op = Scanner.Div THEN x.valueR := x.valueR / y.valueR
  484. ELSE RETURN FALSE
  485. END;
  486. ELSE RETURN FALSE
  487. END;
  488. ELSE
  489. RETURN FALSE;
  490. END;
  491. END;
  492. RETURN TRUE;
  493. ELSE
  494. RETURN FALSE;
  495. END;
  496. END Term;
  497. (* Expression = [ "-" | "+" | "~" ] Term { ( "+" | "-" ) Term } *)
  498. PROCEDURE Expression*(VAR x: Result; critical: BOOLEAN): BOOLEAN;
  499. VAR y: Result; op : LONGINT;
  500. BEGIN
  501. op := symbol.token;
  502. IF ThisToken(Scanner.Minus) THEN
  503. IF Term (x, critical) THEN
  504. IF x.type IN ConstantIntegerOrOffset THEN
  505. x.value := -x.value; x.valueR := x.value
  506. ELSIF x.type = ConstantFloat THEN
  507. x.valueR := -x.valueR
  508. ELSE
  509. RETURN FALSE
  510. END;
  511. ELSE
  512. RETURN FALSE;
  513. END;
  514. ELSIF ThisToken(Scanner.Plus) THEN
  515. IF ~Term (x, critical) THEN RETURN FALSE
  516. ELSE
  517. RETURN (x.type IN ConstantIntegerOrOffset) OR (x.type = ConstantFloat)
  518. END;
  519. ELSIF ThisToken(Scanner.Not) THEN
  520. IF Term (x, critical) THEN
  521. IF x.type IN ConstantIntegerOrOffset THEN
  522. x.value := -x.value-1; x.valueR := x.value
  523. ELSE
  524. RETURN FALSE
  525. END
  526. END;
  527. ELSIF ~Term (x, critical) THEN RETURN FALSE
  528. END;
  529. WHILE (symbol.token = Scanner.Plus) OR (symbol.token = Scanner.Minus) DO
  530. op := symbol.token; NextSymbol;
  531. IF Term (y, critical) THEN
  532. IF op = Scanner.Plus THEN
  533. IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
  534. x.value := x.value+y.value; x.valueR := x.value;
  535. ELSIF (x.type = ConstantFloat) & (y.type = ConstantFloat) THEN
  536. x.valueR := x.valueR + y.valueR;
  537. ELSE RETURN FALSE
  538. END;
  539. ELSE
  540. IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
  541. x.value := x.value-y.value; x.valueR := x.value;
  542. ELSIF (x.type = ConstantFloat) & (y.type = ConstantFloat) THEN
  543. x.valueR := x.valueR - y.valueR;
  544. ELSE RETURN FALSE
  545. END;
  546. END;
  547. ELSE
  548. RETURN FALSE;
  549. END;
  550. END;
  551. RETURN TRUE;
  552. END Expression;
  553. PROCEDURE Data(CONST ident: ARRAY OF CHAR): BOOLEAN;
  554. VAR size,i,nr: LONGINT; x: Result; pos: Position; result: Result; patterns: ObjectFile.FixupPatterns;
  555. PROCEDURE Number(ch: CHAR; VAR nr: LONGINT): BOOLEAN;
  556. BEGIN
  557. IF (ch >= "0") & (ch <="9") THEN
  558. nr := ORD(ch)-ORD("0");
  559. RETURN TRUE
  560. ELSE
  561. RETURN FALSE
  562. END;
  563. END Number;
  564. BEGIN
  565. size := -1;
  566. IF (ident = "DB") OR (ident = "db") THEN size := 8
  567. ELSIF (ident="DW") OR (ident = "dw") THEN size := 16
  568. ELSIF (ident="DD") OR (ident = "dd") THEN size := 32
  569. ELSIF (ident="DQ") OR (ident = "dq") THEN size := 64
  570. ELSIF (CAP(ident[0]) ="D") THEN
  571. size := 0;i := 1;
  572. WHILE Number(ident[i],nr) DO
  573. size := size*10+nr; INC(i);
  574. END;
  575. IF ident[i] # 0X THEN size := -1 END;
  576. END;
  577. IF size = -1 THEN RETURN FALSE
  578. ELSE
  579. IF Trace THEN D.String("Data"); D.Ln; END;
  580. REPEAT
  581. pos := errorPosition;
  582. IF symbol.token = Scanner.String THEN
  583. IF (pass = MaxPasses) & (code.comments # NIL) THEN
  584. code.comments.String(ident); section.comments.String(' "');
  585. code.comments.String(symbol.string^);
  586. code.comments.String('"');
  587. code.comments.Ln;
  588. code.comments.Update
  589. END;
  590. i := 0;
  591. WHILE symbol.string[i] # 0X DO
  592. PutBitsIfLastPass(ORD(symbol.string[i]),size);
  593. INC(i);
  594. END;
  595. NextSymbol;
  596. ELSIF (symbol.token = Scanner.Identifier) & GetNonConstant(errorPosition,symbol.identifierString,result) THEN
  597. IF (pass = MaxPasses) & (code.comments # NIL) THEN
  598. code.comments.String(ident);
  599. code.comments.String(" ");
  600. code.comments.String(symbol.identifierString);
  601. code.comments.Ln;
  602. code.comments.Update
  603. END;
  604. (* if this is the last pass then enter the fixup to the generated code section *)
  605. IF pass = MaxPasses THEN
  606. result.fixup.SetFixupOffset(code.pc);
  607. code.fixupList.AddFixup(result.fixup);
  608. (* set fixup width *)
  609. NEW(patterns, 1);
  610. patterns[0].offset := 0; patterns[0].bits := size;
  611. result.fixup.InitFixup(result.fixup.mode, result.fixup.offset, result.fixup.symbol, result.fixup.symbolOffset, result.fixup.displacement, 0, patterns);
  612. END;
  613. PutBitsIfLastPass(0,size);
  614. NextSymbol;
  615. ELSIF Expression(x,FALSE) THEN
  616. IF x.type # ConstantInteger THEN Error(pos,"forbidden non-constant value") END;
  617. IF (pass = MaxPasses) & (code.comments # NIL) THEN
  618. code.comments.String(ident);
  619. code.comments.String(" ");
  620. (* code.comments.Int(x.value,1); *)
  621. (* print number in hexadecimal form *)
  622. code.comments.String("0");
  623. code.comments.Hex(x.value, -size DIV 4);
  624. code.comments.String("H");
  625. code.comments.Ln;
  626. code.comments.Update
  627. END;
  628. PutBitsIfLastPass(x.value,size);
  629. ELSE Error(pos,"expected string or expression");
  630. END;
  631. UNTIL error OR ~ThisToken(Scanner.Comma);
  632. END;
  633. RETURN TRUE
  634. END Data;
  635. PROCEDURE Reserve(CONST ident: ARRAY OF CHAR): BOOLEAN;
  636. BEGIN RETURN FALSE
  637. END Reserve;
  638. (** if the assembler is at the last pass: put bits into the binary code section, otherwise only increment the PC **)
  639. PROCEDURE PutBitsIfLastPass(data: LONGINT; size: BinaryCode.Bits);
  640. VAR
  641. oldPC: LONGINT;
  642. BEGIN
  643. IF pass = MaxPasses THEN
  644. code.PutBits(data, size)
  645. ELSE
  646. oldPC := code.pc;
  647. ASSERT(size MOD code.os.unit = 0);
  648. code.SetPC(oldPC + size DIV code.os.unit)
  649. END
  650. END PutBitsIfLastPass;
  651. PROCEDURE Instruction*(CONST mnemonic: ARRAY OF CHAR);
  652. VAR numberOperands: LONGINT;
  653. PROCEDURE ParseOperand(pos: Position; numberOperand: LONGINT);
  654. (* stub, must be overwritten by implementation *)
  655. VAR operand: OperandString;
  656. result: Result; first: BOOLEAN; str: ARRAY 256 OF CHAR;
  657. BEGIN
  658. first := TRUE;
  659. WHILE ~error & (symbol.token # Scanner.Ln) & (symbol.token # Scanner.Comma) DO
  660. IF (symbol.token = Scanner.Identifier) & GetNonConstant(errorPosition,symbol.identifierString,result) THEN
  661. D.String("(* non constant ");
  662. D.String(symbol.identifierString); D.String("="); DumpResult(D.Log,result);
  663. D.String("*)");
  664. ELSIF (symbol.token = Scanner.Identifier) & GetConstant(errorPosition,symbol.identifierString,result) THEN
  665. D.String("(* constant ");
  666. DumpResult(D.Log,result);
  667. D.String("*)");
  668. END;
  669. IF first THEN first := FALSE ELSE Strings.Append(operand," ") END;
  670. Scanner.SymbolToString(symbol, scanner.case, str);
  671. Strings.Append(operand, str);
  672. NextSymbol;
  673. END;
  674. IF Trace THEN
  675. D.String("operand= ");
  676. D.String(operand); IF symbol.token = Scanner.Comma THEN D.String(" , ") END;
  677. END;
  678. END ParseOperand;
  679. BEGIN
  680. IF Trace THEN
  681. D.String("Instruction= "); D.String(mnemonic); D.String(" ");
  682. END;
  683. numberOperands := 0;
  684. IF ~ThisToken(Scanner.Ln) THEN
  685. REPEAT
  686. ParseOperand(errorPosition,numberOperands);
  687. INC(numberOperands);
  688. UNTIL error OR ~ThisToken(Scanner.Comma);
  689. IF ~error & ExpectToken(Scanner.Ln) THEN END;
  690. END;
  691. IF Trace THEN D.Ln END
  692. END Instruction;
  693. PROCEDURE IgnoreNewLines;
  694. BEGIN
  695. WHILE ThisToken(Scanner.Ln) DO END;
  696. END IgnoreNewLines;
  697. PROCEDURE DoAssemble();
  698. VAR result: Result; pos: Position; line,orgCodePos: LONGINT; identifier: Scanner.IdentifierString; context: Scanner.Context;
  699. BEGIN
  700. IF Trace THEN
  701. D.Str("DoAssemble: ");
  702. IF section # NIL THEN Basic.WriteSegmentedName(D.Log,section.name); D.Ln END;
  703. END;
  704. NEW(labels);
  705. NEW(results);
  706. scanner.GetContext(context);
  707. NextSymbol;
  708. IgnoreNewLines;
  709. WHILE ~error & (symbol.token # Scanner.Period) & (symbol.token # Scanner.EndOfText) DO
  710. IF ThisToken(Scanner.Number) THEN
  711. line := symbol.integer;
  712. IF ThisToken(Scanner.Colon) THEN (* line number *)
  713. ELSE Error(symbol.position,"Identifier expected");
  714. END;
  715. END;
  716. IF ExpectIdentifier(pos,identifier) THEN
  717. IF ThisToken(Scanner.Colon) THEN (* label *)
  718. DefineLabel(pos,identifier)
  719. ELSIF ThisIdentifier("equ") OR ThisToken(Scanner.Equal) THEN
  720. IF Expression(result,FALSE) THEN DefineResult(pos,identifier,result) END;
  721. ELSE scanner.SkipToEndOfLine; NextSymbol;
  722. END;
  723. END;
  724. IgnoreNewLines;
  725. END;
  726. orgCodePos := code.pc;
  727. FOR pass := 1 TO MaxPasses DO
  728. labels.ResetDisplacements; (* this is important as the displacement is corrected by code emission in a cummulative way *)
  729. code.SetPC(orgCodePos);
  730. SetContext(context);
  731. IgnoreNewLines;
  732. WHILE ~error & (symbol.token # Scanner.EndOfText) & (symbol.token # Scanner.Period) DO
  733. IF ThisToken(Scanner.Number) THEN
  734. line := symbol.integer;
  735. IF ThisToken(Scanner.Colon) THEN (* line number *)
  736. ELSE Error(symbol.position,"Identifier expected");
  737. END;
  738. END;
  739. IF ExpectIdentifier(pos,identifier) THEN
  740. IF ThisToken(Scanner.Colon) THEN (* label *)
  741. SetLabel(pos,identifier);
  742. ELSIF ThisIdentifier("equ") OR ThisToken(Scanner.Equal) THEN (* constant definition *)
  743. IF Expression(result,FALSE) THEN SetResult(identifier,result) END;
  744. ELSE
  745. IF identifier = "section" THEN
  746. Section()
  747. ELSIF Data(identifier) THEN
  748. ELSIF Reserve(identifier) THEN
  749. ELSIF identifier = "fixed" THEN
  750. IF ExpectConstantInteger(result,TRUE) THEN
  751. code.SetAlignment(TRUE,result.value)
  752. END;
  753. ELSIF ~error THEN
  754. errorPosition := pos;
  755. Instruction(identifier);
  756. (*
  757. IF ~error & ExpectToken(Scanner.Ln) THEN END;
  758. *)
  759. END;
  760. END;
  761. END;
  762. IgnoreNewLines;
  763. END;
  764. END;
  765. IF Trace THEN
  766. D.Str("END Assemble"); D.Ln;
  767. END
  768. END DoAssemble;
  769. PROCEDURE InlineAssemble*(scanner: Scanner.AssemblerScanner; section: IntermediateCode.Section; scope: SyntaxTree.Scope; module: Sections.Module);
  770. BEGIN
  771. ASSERT(module # NIL); ASSERT(scanner # NIL); ASSERT(section # NIL);
  772. ASSERT(section.resolved # NIL);
  773. SELF.scope := scope;
  774. SELF.module := module;
  775. SELF.scanner := scanner;
  776. SELF.section := section;
  777. SELF.code := section.resolved;
  778. DoAssemble;
  779. END InlineAssemble;
  780. PROCEDURE Assemble*(scanner: Scanner.AssemblerScanner);
  781. BEGIN
  782. ASSERT(scanner # NIL);
  783. SELF.scanner := scanner;
  784. module := NIL; section := NIL; scope := NIL;
  785. scanner.SetContext(scanner.startContext);
  786. DoAssemble;
  787. END Assemble;
  788. PROCEDURE AllSections*;
  789. VAR pos: Position; sectionType, sectionName: Scanner.IdentifierString;
  790. BEGIN
  791. IF Trace THEN D.String("AllSections"); D.Ln END;
  792. SetContext(scanner.startContext);
  793. IgnoreNewLines;
  794. WHILE ThisToken(Scanner.Period) & ExpectIdentifier(pos,sectionType) & ExpectIdentifier(pos,sectionName) DO
  795. D.String("section "); D.String(sectionType); D.String(" "); D.String(sectionName); D.Ln;
  796. DoAssemble;
  797. END;
  798. END AllSections;
  799. PROCEDURE Text*(scanner: Scanner.AssemblerScanner);
  800. BEGIN
  801. ASSERT(scanner # NIL);
  802. SELF.scanner := scanner;
  803. module := NIL; section := NIL; scope := NIL;
  804. AllSections;
  805. END Text;
  806. END Assembler;
  807. PROCEDURE DumpResult*(w: Streams.Writer; result: Result);
  808. BEGIN
  809. CASE result.type OF
  810. ConstantInteger: w.String("i"); w.Int(result.sizeInBits,1);w.String(" ");w.Int(result.value,1);
  811. |ConstantFloat: w.String("f");w.Int(result.sizeInBits,1);w.String(" ");w.Float(result.value,20);
  812. |Offset: w.String("ofs "); w.Int(result.value,1);
  813. |Fixup: w.String("i"); w.Int(result.sizeInBits,1);w.String(" "); w.String("fixup ");
  814. result.fixup.Dump(w);
  815. END;
  816. END DumpResult;
  817. PROCEDURE Test*(context: Commands.Context);
  818. VAR scanner: Scanner.AssemblerScanner; diagnostics: Diagnostics.StreamDiagnostics; assembler: Assembler;
  819. BEGIN
  820. NEW(diagnostics,context.out);
  821. NEW(scanner,"command",context.arg,0,diagnostics);
  822. NEW(assembler,diagnostics);
  823. assembler.Text(scanner);
  824. (*
  825. assembler.Assemble(scanner);
  826. *)
  827. END Test;
  828. PROCEDURE TestScanner*(context: Commands.Context);
  829. VAR scanner: Scanner.AssemblerScanner; diagnostics: Diagnostics.StreamDiagnostics; symbol: Scanner.Symbol;
  830. BEGIN
  831. NEW(diagnostics,context.out);
  832. NEW(scanner,"command",context.arg,0,diagnostics);
  833. WHILE scanner.GetNextSymbol(symbol) & (symbol.token # Scanner.EndOfText) DO
  834. Scanner.OutSymbol(context.out, symbol); context.out.Ln;
  835. END;
  836. END TestScanner;
  837. END FoxAssembler.
  838. SystemTools.Free FoxAssembler ~
  839. FoxAssembler.Test
  840. ;---------------- intermediate code -----------------
  841. .module BitSets
  842. .imports SYSTEM
  843. .const BitSets.@moduleSelf offset=0
  844. 0: data u32 0
  845. .const BitSets.BitSet offset=0
  846. 0: data u32 0
  847. .code BitSets.BitSet.InitBitSet offset=0
  848. 0: enter 0, 0
  849. 1: mov u32 r1, u32 [fp+8]
  850. 2: mov s32 [r1], s32 [fp+12]
  851. 3: push s32 [fp+12]
  852. 4: mov u32 r2, u32 [fp+8]
  853. 5: add u32 r3, u32 [r2-4], u32 -88
  854. 6: push u32 r2
  855. 7: call u32 [r3], 8
  856. 8: leave 0
  857. 9: exit 8
  858. .code BitSets.BitSet.Zero offset=0
  859. 0: enter 0, 8
  860. 1: mov s32 [fp-4], s32 0
  861. 2: mov u32 r1, u32 [fp+8]
  862. 3: mov u32 r2, u32 [r1+4]
  863. 4: conv s32 r3, u32 [r2+12]
  864. 5: sub s32 r3, s32 r3, s32 1
  865. 6: mov s32 [fp-8], s32 r3
  866. 7: brlt u32 BitSets.BitSet.Zero:21, s32 [fp-8], s32 [fp-4]
  867. 8: br u32 BitSets.BitSet.Zero:9
  868. 9: conv u32 r4, s32 [fp-4]
  869. 10: mov u32 r5, u32 r4
  870. 11: mov u32 r6, u32 [fp+8]
  871. 12: mov u32 r7, u32 [r6+4]
  872. 13: brlt u32 BitSets.BitSet.Zero:15, u32 r4, u32 [r7+12]
  873. 14: trap 7
  874. 15: mul u32 r5, u32 r5, u32 4
  875. 16: add u32 r5, u32 r5, u32 r7+16
  876. 17: mov u32 [r5], u32 0
  877. 18: add s32 r8, s32 [fp-4], s32 1
  878. 19: mov s32 [fp-4], s32 r8
  879. 20: br u32 BitSets.BitSet.Zero:7
  880. 21: leave 0
  881. 22: exit 4
  882. .code BitSets.BitSet.Resize offset=0
  883. 0: enter 0, 12
  884. 1: brlt u32 BitSets.BitSet.Resize:3, s32 [fp+12], s32 0
  885. 2: br u32 BitSets.BitSet.Resize:4
  886. 3: trap 8
  887. 4: mov u32 r1, u32 [fp+8]
  888. 5: mov s32 [r1], s32 [fp+12]
  889. 6: sub s32 r2, s32 [fp+12], s32 1
  890. 7: brlt u32 BitSets.BitSet.Resize:10, s32 r2, s32 0
  891. 8: mov s32 r2, s32 r2
  892. 9: br u32 BitSets.BitSet.Resize:11
  893. 10: mov s32 r2, s32 0, s32 r2
  894. 11: shr s32 r2, s32 r2, s32 5
  895. 12: add s32 r2, s32 r2, s32 1
  896. 13: mov s32 [fp+12], s32 r2
  897. 14: mov u32 r3, u32 [fp+8]
  898. 15: breq u32 BitSets.BitSet.Resize:35, u32 [r3+4], u32 0
  899. 16: br u32 BitSets.BitSet.Resize:17
  900. 17: mov u32 r4, u32 [fp+8]
  901. 18: mov u32 r5, u32 [r4+4]
  902. 19: conv s32 r6, u32 [r5+12]
  903. 20: brlt u32 BitSets.BitSet.Resize:25, s32 r6, s32 [fp+12]
  904. 21: br u32 BitSets.BitSet.Resize:22
  905. 22: leave 0
  906. 23: exit 8
  907. 24: br u32 BitSets.BitSet.Resize:25
  908. 25: mov u32 r7, u32 [fp+8]
  909. 26: mov u32 r8, u32 [r7+4]
  910. 27: conv s32 r9, u32 [r8+12]
  911. 28: shl s32 r9, s32 r9, s32 1
  912. 29: brlt u32 BitSets.BitSet.Resize:32, s32 [fp+12], s32 r9
  913. 30: mov s32 r9, s32 [fp+12]
  914. 31: br u32 BitSets.BitSet.Resize:33
  915. 32: mov s32 r9, s32 r9, s32 r9
  916. 33: mov s32 [fp+12], s32 r9
  917. 34: br u32 BitSets.BitSet.Resize:35
  918. 35: brge u32 BitSets.BitSet.Resize:37, s32 [fp+12], s32 0
  919. 36: trap 9
  920. 37: push s32 [fp+12]
  921. 38: mov s32 r10, s32 [fp+12]
  922. 39: conv u32 r10, s32 r10
  923. 40: mul u32 r10, u32 r10, u32 4
  924. 41: add u32 r10, u32 r10, u32 16
  925. 42: push u32 fp-4
  926. 43: push u32 fp-4
  927. 44: push u32 r10
  928. 45: push u8 0
  929. 46: call u32 $SystemCall2:0, 0
  930. 47: pop u32 r11
  931. 48: mov u32 r12, u32 [r11]
  932. 49: breq u32 BitSets.BitSet.Resize:53, u32 r12, u32 0
  933. 50: pop u32 r13
  934. 51: mov u32 [r12+12], u32 r13
  935. 52: br u32 BitSets.BitSet.Resize:54
  936. 53: add u32 sp, u32 sp, u32 4
  937. 54: mov u32 r14, u32 [fp+8]
  938. 55: breq u32 BitSets.BitSet.Resize:85, u32 [r14+4], u32 0
  939. 56: br u32 BitSets.BitSet.Resize:57
  940. 57: mov s32 [fp-8], s32 0
  941. 58: mov u32 r15, u32 [fp+8]
  942. 59: mov u32 r16, u32 [r15+4]
  943. 60: conv s32 r17, u32 [r16+12]
  944. 61: sub s32 r17, s32 r17, s32 1
  945. 62: mov s32 [fp-12], s32 r17
  946. 63: brlt u32 BitSets.BitSet.Resize:84, s32 [fp-12], s32 [fp-8]
  947. 64: br u32 BitSets.BitSet.Resize:65
  948. 65: conv u32 r18, s32 [fp-8]
  949. 66: mov u32 r19, u32 r18
  950. 67: mov u32 r20, u32 [fp+8]
  951. 68: mov u32 r21, u32 [r20+4]
  952. 69: brlt u32 BitSets.BitSet.Resize:71, u32 r18, u32 [r21+12]
  953. 70: trap 7
  954. 71: mul u32 r19, u32 r19, u32 4
  955. 72: add u32 r19, u32 r19, u32 r21+16
  956. 73: conv u32 r22, s32 [fp-8]
  957. 74: mov u32 r23, u32 r22
  958. 75: mov u32 r24, u32 [fp-4]
  959. 76: brlt u32 BitSets.BitSet.Resize:78, u32 r22, u32 [r24+12]
  960. 77: trap 7
  961. 78: mul u32 r23, u32 r23, u32 4
  962. 79: add u32 r23, u32 r23, u32 r24+16
  963. 80: mov u32 [r23], u32 [r19]
  964. 81: add s32 r25, s32 [fp-8], s32 1
  965. 82: mov s32 [fp-8], s32 r25
  966. 83: br u32 BitSets.BitSet.Resize:63
  967. 84: br u32 BitSets.BitSet.Resize:85
  968. 85: mov u32 r26, u32 [fp+8]
  969. 86: mov u32 [r26+4], u32 [fp-4]
  970. 87: leave 0
  971. 88: exit 8
  972. .code BitSets.BitSet.GetSize offset=0
  973. 0: enter 0, 0
  974. 1: mov u32 r1, u32 [fp+8]
  975. 2: return s32 [r1]
  976. 3: leave 0
  977. 4: exit 4
  978. 5: trap 3