FoxAssembler.Mod 35 KB

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