FoxAssembler.Mod 35 KB

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