FoxAssembler.Mod 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  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*: HUGEINT;
  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. token-: Scanner.Token;
  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); NextToken;
  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 NextToken*;
  159. BEGIN error := error OR ~scanner.GetNextToken(token); errorPosition := token.position;
  160. END NextToken;
  161. PROCEDURE ThisSymbol*(x: Scanner.Symbol): BOOLEAN;
  162. BEGIN
  163. IF ~error & (token.symbol = x) THEN NextToken; RETURN TRUE ELSE RETURN FALSE END;
  164. END ThisSymbol;
  165. PROCEDURE GetIdentifier*(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
  166. BEGIN
  167. pos := token.position;
  168. IF token.symbol # Scanner.Identifier THEN RETURN FALSE
  169. ELSE COPY(token.identifierString,identifier); NextToken; RETURN TRUE
  170. END;
  171. END GetIdentifier;
  172. PROCEDURE ThisIdentifier*(CONST this: ARRAY OF CHAR): BOOLEAN;
  173. BEGIN
  174. IF ~error & (token.symbol = Scanner.Identifier) & (this = token.identifierString) THEN NextToken; 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 ExpectSymbol*(x: Scanner.Symbol): BOOLEAN;
  183. VAR s: Basic.MessageString;
  184. BEGIN
  185. IF ThisSymbol(x) THEN RETURN TRUE
  186. ELSE
  187. s := "expected token "; Strings.Append(s,Scanner.symbols[x]); Strings.Append(s," but got "); Strings.Append(s,Scanner.symbols[token.symbol]);
  188. Error(errorPosition,s);RETURN FALSE
  189. END;
  190. END ExpectSymbol;
  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 ExpectSymbol(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. NextToken;
  278. IF ExpectSymbol(Scanner.Period) & (token.symbol = Scanner.Identifier) THEN
  279. identifier := SyntaxTree.NewIdentifier(token.identifierString);
  280. IF Trace THEN D.String("GetScopeSymbol :"); D.String(token.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): Basic.Fingerprint;
  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 ThisSymbol(Scanner.Number) THEN
  432. (* ASSERT(symbol.numberType = Scanner.Integer); *)
  433. IF token.numberType = Scanner.Integer THEN
  434. x.value := token.integer
  435. ELSIF token.numberType = Scanner.Hugeint THEN
  436. x.value := token.hugeint;
  437. (* ASSERT(x.value < 0); (* the resulting 32 bit integer must be negative when interpreted as a signed value *)*)
  438. END;
  439. x.type := ConstantInteger;
  440. RETURN TRUE;
  441. ELSIF ThisSymbol(Scanner.PC) THEN (* pc IN units ! *)
  442. x.value := code.pc;
  443. x.type := ConstantInteger; (* TODO: should it be 'x.type := Offset'? *)
  444. RETURN TRUE;
  445. ELSIF ThisSymbol(Scanner.PCOffset) THEN
  446. x.value := code.pc-orgOffset;
  447. x.type := ConstantInteger; (* TODO: should it be 'x.type := Offset'? *)
  448. RETURN TRUE;
  449. ELSIF GetIdentifier(pos,identifier) THEN
  450. label := labels.Find (identifier);
  451. IF label # NIL THEN
  452. x.value := label.offset;
  453. x.type := Offset;
  454. (*! deal with fixups ? / enter fixup ? *)
  455. RETURN TRUE;
  456. ELSIF GetConstant(errorPosition, identifier,x) THEN RETURN TRUE
  457. ELSIF ~critical & (pass # MaxPasses) THEN
  458. x.value := 0; x.type := ConstantInteger; RETURN TRUE
  459. ELSE Error(pos,"undefined symbol"); RETURN FALSE
  460. END;
  461. ELSIF ThisSymbol(Scanner.LeftParenthesis) THEN
  462. RETURN Expression (x, critical) & ExpectSymbol(Scanner.RightParenthesis);
  463. END;
  464. RETURN FALSE
  465. END Factor;
  466. (* term = Factor { ( "*" | "/" | "%" ) Factor } *)
  467. PROCEDURE Term (VAR x: Result; critical: BOOLEAN): BOOLEAN;
  468. VAR y: Result; op : LONGINT;
  469. BEGIN
  470. IF Factor (x, critical) THEN
  471. WHILE (token.symbol = Scanner.Times) OR (token.symbol = Scanner.Div) OR (token.symbol = Scanner.Mod) DO
  472. op := token.symbol; NextToken;
  473. IF Factor (y, critical) THEN
  474. IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
  475. IF op = Scanner.Times THEN x.value := x.value * y.value
  476. ELSIF op = Scanner.Div THEN x.value := x.value DIV y.value
  477. ELSE x.value := x.value MOD y.value
  478. END;
  479. ELSIF (x.type = ConstantFloat) OR (y.type = ConstantFloat) THEN
  480. IF op = Scanner.Times THEN x.valueR := x.valueR * y.valueR
  481. ELSIF op = Scanner.Div THEN x.valueR := x.valueR / y.valueR
  482. ELSE RETURN FALSE
  483. END;
  484. ELSE RETURN FALSE
  485. END;
  486. ELSE
  487. RETURN FALSE;
  488. END;
  489. END;
  490. RETURN TRUE;
  491. ELSE
  492. RETURN FALSE;
  493. END;
  494. END Term;
  495. (* Expression = [ "-" | "+" | "~" ] Term { ( "+" | "-" ) Term } *)
  496. PROCEDURE Expression*(VAR x: Result; critical: BOOLEAN): BOOLEAN;
  497. VAR y: Result; op : LONGINT;
  498. BEGIN
  499. op := token.symbol;
  500. IF ThisSymbol(Scanner.Minus) THEN
  501. IF Term (x, critical) THEN
  502. IF x.type IN ConstantIntegerOrOffset THEN
  503. x.value := -x.value; x.valueR := x.value
  504. ELSIF x.type = ConstantFloat THEN
  505. x.valueR := -x.valueR
  506. ELSE
  507. RETURN FALSE
  508. END;
  509. ELSE
  510. RETURN FALSE;
  511. END;
  512. ELSIF ThisSymbol(Scanner.Plus) THEN
  513. IF ~Term (x, critical) THEN RETURN FALSE
  514. ELSE
  515. RETURN (x.type IN ConstantIntegerOrOffset) OR (x.type = ConstantFloat)
  516. END;
  517. ELSIF ThisSymbol(Scanner.Not) THEN
  518. IF Term (x, critical) THEN
  519. IF x.type IN ConstantIntegerOrOffset THEN
  520. x.value := -x.value-1; x.valueR := x.value
  521. ELSE
  522. RETURN FALSE
  523. END
  524. END;
  525. ELSIF ~Term (x, critical) THEN RETURN FALSE
  526. END;
  527. WHILE (token.symbol = Scanner.Plus) OR (token.symbol = Scanner.Minus) DO
  528. op := token.symbol; NextToken;
  529. IF Term (y, critical) THEN
  530. IF op = Scanner.Plus THEN
  531. IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
  532. x.value := x.value+y.value; x.valueR := x.value;
  533. ELSIF (x.type = ConstantFloat) & (y.type = ConstantFloat) THEN
  534. x.valueR := x.valueR + y.valueR;
  535. ELSE RETURN FALSE
  536. END;
  537. ELSE
  538. IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
  539. x.value := x.value-y.value; x.valueR := x.value;
  540. ELSIF (x.type = ConstantFloat) & (y.type = ConstantFloat) THEN
  541. x.valueR := x.valueR - y.valueR;
  542. ELSE RETURN FALSE
  543. END;
  544. END;
  545. ELSE
  546. RETURN FALSE;
  547. END;
  548. END;
  549. RETURN TRUE;
  550. END Expression;
  551. PROCEDURE Data(CONST ident: ARRAY OF CHAR): BOOLEAN;
  552. VAR size,i,nr: LONGINT; x: Result; pos: Position; result: Result; patterns: ObjectFile.FixupPatterns;
  553. PROCEDURE Number(ch: CHAR; VAR nr: LONGINT): BOOLEAN;
  554. BEGIN
  555. IF (ch >= "0") & (ch <="9") THEN
  556. nr := ORD(ch)-ORD("0");
  557. RETURN TRUE
  558. ELSE
  559. RETURN FALSE
  560. END;
  561. END Number;
  562. BEGIN
  563. size := -1;
  564. IF (ident = "DB") OR (ident = "db") THEN size := 8
  565. ELSIF (ident="DW") OR (ident = "dw") THEN size := 16
  566. ELSIF (ident="DD") OR (ident = "dd") THEN size := 32
  567. ELSIF (ident="DQ") OR (ident = "dq") THEN size := 64
  568. ELSIF (CAP(ident[0]) ="D") THEN
  569. size := 0;i := 1;
  570. WHILE Number(ident[i],nr) DO
  571. size := size*10+nr; INC(i);
  572. END;
  573. IF ident[i] # 0X THEN size := -1 END;
  574. END;
  575. IF size = -1 THEN RETURN FALSE
  576. ELSE
  577. IF Trace THEN D.String("Data"); D.Ln; END;
  578. REPEAT
  579. pos := errorPosition;
  580. IF token.symbol = Scanner.String THEN
  581. IF (pass = MaxPasses) & (code.comments # NIL) THEN
  582. code.comments.String(ident); section.comments.String(' "');
  583. code.comments.String(token.string^);
  584. code.comments.String('"');
  585. code.comments.Ln;
  586. code.comments.Update
  587. END;
  588. i := 0;
  589. WHILE token.string[i] # 0X DO
  590. PutBitsIfLastPass(ORD(token.string[i]),size);
  591. INC(i);
  592. END;
  593. NextToken;
  594. ELSIF (token.symbol = Scanner.Identifier) & GetNonConstant(errorPosition,token.identifierString,result) THEN
  595. IF (pass = MaxPasses) & (code.comments # NIL) THEN
  596. code.comments.String(ident);
  597. code.comments.String(" ");
  598. code.comments.String(token.identifierString);
  599. code.comments.Ln;
  600. code.comments.Update
  601. END;
  602. (* if this is the last pass then enter the fixup to the generated code section *)
  603. IF pass = MaxPasses THEN
  604. result.fixup.SetFixupOffset(code.pc);
  605. code.fixupList.AddFixup(result.fixup);
  606. (* set fixup width *)
  607. NEW(patterns, 1);
  608. patterns[0].offset := 0; patterns[0].bits := size;
  609. result.fixup.InitFixup(result.fixup.mode, result.fixup.offset, result.fixup.symbol, result.fixup.symbolOffset, result.fixup.displacement, 0, patterns);
  610. END;
  611. PutBitsIfLastPass(0,size);
  612. NextToken;
  613. ELSIF Expression(x,FALSE) THEN
  614. IF x.type # ConstantInteger THEN Error(pos,"forbidden non-constant value") END;
  615. IF (pass = MaxPasses) & (code.comments # NIL) THEN
  616. code.comments.String(ident);
  617. code.comments.String(" ");
  618. (* code.comments.Int(x.value,1); *)
  619. (* print number in hexadecimal form *)
  620. code.comments.String("0");
  621. code.comments.Hex(x.value, -size DIV 4);
  622. code.comments.String("H");
  623. code.comments.Ln;
  624. code.comments.Update
  625. END;
  626. PutBitsIfLastPass(x.value,size);
  627. ELSE Error(pos,"expected string or expression");
  628. END;
  629. UNTIL error OR ~ThisSymbol(Scanner.Comma);
  630. END;
  631. RETURN TRUE
  632. END Data;
  633. PROCEDURE Reserve(CONST ident: ARRAY OF CHAR): BOOLEAN;
  634. BEGIN RETURN FALSE
  635. END Reserve;
  636. (** if the assembler is at the last pass: put bits into the binary code section, otherwise only increment the PC **)
  637. PROCEDURE PutBitsIfLastPass(data: HUGEINT; size: BinaryCode.Bits);
  638. VAR
  639. oldPC: LONGINT;
  640. BEGIN
  641. IF pass = MaxPasses THEN
  642. code.PutBits(data, size)
  643. ELSE
  644. oldPC := code.pc;
  645. ASSERT(size MOD code.os.unit = 0);
  646. code.SetPC(oldPC + size DIV code.os.unit)
  647. END
  648. END PutBitsIfLastPass;
  649. PROCEDURE Instruction*(CONST mnemonic: ARRAY OF CHAR);
  650. VAR numberOperands: LONGINT;
  651. PROCEDURE ParseOperand(pos: Position; numberOperand: LONGINT);
  652. (* stub, must be overwritten by implementation *)
  653. VAR operand: OperandString;
  654. result: Result; first: BOOLEAN; str: ARRAY 256 OF CHAR;
  655. BEGIN
  656. first := TRUE;
  657. WHILE ~error & (token.symbol # Scanner.Ln) & (token.symbol # Scanner.Comma) DO
  658. IF (token.symbol = Scanner.Identifier) & GetNonConstant(errorPosition,token.identifierString,result) THEN
  659. D.String("(* non constant ");
  660. D.String(token.identifierString); D.String("="); DumpResult(D.Log,result);
  661. D.String("*)");
  662. ELSIF (token.symbol = Scanner.Identifier) & GetConstant(errorPosition,token.identifierString,result) THEN
  663. D.String("(* constant ");
  664. DumpResult(D.Log,result);
  665. D.String("*)");
  666. END;
  667. IF first THEN first := FALSE ELSE Strings.Append(operand," ") END;
  668. Scanner.TokenToString(token, scanner.case, str);
  669. Strings.Append(operand, str);
  670. NextToken;
  671. END;
  672. IF Trace THEN
  673. D.String("operand= ");
  674. D.String(operand); IF token.symbol = Scanner.Comma THEN D.String(" , ") END;
  675. END;
  676. END ParseOperand;
  677. BEGIN
  678. IF Trace THEN
  679. D.String("Instruction= "); D.String(mnemonic); D.String(" ");
  680. END;
  681. numberOperands := 0;
  682. IF ~ThisSymbol(Scanner.Ln) THEN
  683. REPEAT
  684. ParseOperand(errorPosition,numberOperands);
  685. INC(numberOperands);
  686. UNTIL error OR ~ThisSymbol(Scanner.Comma);
  687. IF ~error & ExpectSymbol(Scanner.Ln) THEN END;
  688. END;
  689. IF Trace THEN D.Ln END
  690. END Instruction;
  691. PROCEDURE IgnoreNewLines;
  692. BEGIN
  693. WHILE ThisSymbol(Scanner.Ln) DO END;
  694. END IgnoreNewLines;
  695. PROCEDURE DoAssemble();
  696. VAR result: Result; pos: Position; line,orgCodePos: LONGINT; identifier: Scanner.IdentifierString; context: Scanner.Context;
  697. BEGIN
  698. IF Trace THEN
  699. D.Str("DoAssemble: ");
  700. IF section # NIL THEN Basic.WriteSegmentedName(D.Log,section.name); D.Ln END;
  701. END;
  702. NEW(labels);
  703. NEW(results);
  704. scanner.GetContext(context);
  705. NextToken;
  706. IgnoreNewLines;
  707. WHILE ~error & (token.symbol # Scanner.Period) & (token.symbol # Scanner.EndOfText) DO
  708. IF ThisSymbol(Scanner.Number) THEN
  709. line := token.integer;
  710. IF ThisSymbol(Scanner.Colon) THEN (* line number *)
  711. ELSE Error(token.position,"Identifier expected");
  712. END;
  713. END;
  714. IF ExpectIdentifier(pos,identifier) THEN
  715. IF ThisSymbol(Scanner.Colon) THEN (* label *)
  716. DefineLabel(pos,identifier)
  717. ELSIF ThisIdentifier("equ") OR ThisSymbol(Scanner.Equal) THEN
  718. IF Expression(result,FALSE) THEN DefineResult(pos,identifier,result) END;
  719. ELSE scanner.SkipToEndOfLine; NextToken;
  720. END;
  721. END;
  722. IgnoreNewLines;
  723. END;
  724. orgCodePos := code.pc;
  725. FOR pass := 1 TO MaxPasses DO
  726. labels.ResetDisplacements; (* this is important as the displacement is corrected by code emission in a cummulative way *)
  727. code.SetPC(orgCodePos);
  728. SetContext(context);
  729. IgnoreNewLines;
  730. WHILE ~error & (token.symbol # Scanner.EndOfText) & (token.symbol # Scanner.Period) DO
  731. IF ThisSymbol(Scanner.Number) THEN
  732. line := token.integer;
  733. IF ThisSymbol(Scanner.Colon) THEN (* line number *)
  734. ELSE Error(token.position,"Identifier expected");
  735. END;
  736. END;
  737. IF ExpectIdentifier(pos,identifier) THEN
  738. IF ThisSymbol(Scanner.Colon) THEN (* label *)
  739. SetLabel(pos,identifier);
  740. ELSIF ThisIdentifier("equ") OR ThisSymbol(Scanner.Equal) THEN (* constant definition *)
  741. IF Expression(result,FALSE) THEN SetResult(identifier,result) END;
  742. ELSE
  743. IF identifier = "section" THEN
  744. Section()
  745. ELSIF Data(identifier) THEN
  746. ELSIF Reserve(identifier) THEN
  747. ELSIF identifier = "fixed" THEN
  748. IF ExpectConstantInteger(result,TRUE) THEN
  749. code.SetAlignment(TRUE,LONGINT(result.value))
  750. END;
  751. ELSIF ~error THEN
  752. errorPosition := pos;
  753. Instruction(identifier);
  754. (*
  755. IF ~error & ExpectSymbol(Scanner.Ln) THEN END;
  756. *)
  757. END;
  758. END;
  759. END;
  760. IgnoreNewLines;
  761. END;
  762. END;
  763. IF Trace THEN
  764. D.Str("END Assemble"); D.Ln;
  765. END
  766. END DoAssemble;
  767. PROCEDURE InlineAssemble*(scanner: Scanner.AssemblerScanner; section: IntermediateCode.Section; scope: SyntaxTree.Scope; module: Sections.Module);
  768. BEGIN
  769. ASSERT(module # NIL); ASSERT(scanner # NIL); ASSERT(section # NIL);
  770. ASSERT(section.resolved # NIL);
  771. SELF.scope := scope;
  772. SELF.module := module;
  773. SELF.scanner := scanner;
  774. SELF.section := section;
  775. SELF.code := section.resolved;
  776. DoAssemble;
  777. END InlineAssemble;
  778. PROCEDURE Assemble*(scanner: Scanner.AssemblerScanner);
  779. BEGIN
  780. ASSERT(scanner # NIL);
  781. SELF.scanner := scanner;
  782. module := NIL; section := NIL; scope := NIL;
  783. scanner.SetContext(scanner.startContext);
  784. DoAssemble;
  785. END Assemble;
  786. PROCEDURE AllSections*;
  787. VAR pos: Position; sectionType, sectionName: Scanner.IdentifierString;
  788. BEGIN
  789. IF Trace THEN D.String("AllSections"); D.Ln END;
  790. SetContext(scanner.startContext);
  791. IgnoreNewLines;
  792. WHILE ThisSymbol(Scanner.Period) & ExpectIdentifier(pos,sectionType) & ExpectIdentifier(pos,sectionName) DO
  793. D.String("section "); D.String(sectionType); D.String(" "); D.String(sectionName); D.Ln;
  794. DoAssemble;
  795. END;
  796. END AllSections;
  797. PROCEDURE Text*(scanner: Scanner.AssemblerScanner);
  798. BEGIN
  799. ASSERT(scanner # NIL);
  800. SELF.scanner := scanner;
  801. module := NIL; section := NIL; scope := NIL;
  802. AllSections;
  803. END Text;
  804. END Assembler;
  805. PROCEDURE DumpResult*(w: Streams.Writer; result: Result);
  806. BEGIN
  807. CASE result.type OF
  808. ConstantInteger: w.String("i"); w.Int(result.sizeInBits,1);w.String(" ");w.Int(result.value,1);
  809. |ConstantFloat: w.String("f");w.Int(result.sizeInBits,1);w.String(" ");w.Float(result.value,20);
  810. |Offset: w.String("ofs "); w.Int(result.value,1);
  811. |Fixup: w.String("i"); w.Int(result.sizeInBits,1);w.String(" "); w.String("fixup ");
  812. result.fixup.Dump(w);
  813. END;
  814. END DumpResult;
  815. PROCEDURE Test*(context: Commands.Context);
  816. VAR scanner: Scanner.AssemblerScanner; diagnostics: Diagnostics.StreamDiagnostics; assembler: Assembler;
  817. BEGIN
  818. NEW(diagnostics,context.out);
  819. scanner := Scanner.NewAssemblerScanner("command",context.arg,0,diagnostics);
  820. NEW(assembler,diagnostics);
  821. assembler.Text(scanner);
  822. (*
  823. assembler.Assemble(scanner);
  824. *)
  825. END Test;
  826. PROCEDURE TestScanner*(context: Commands.Context);
  827. VAR scanner: Scanner.AssemblerScanner; diagnostics: Diagnostics.StreamDiagnostics; token: Scanner.Token;
  828. BEGIN
  829. NEW(diagnostics,context.out);
  830. scanner := Scanner.NewAssemblerScanner("command",context.arg,0,diagnostics);
  831. WHILE scanner.GetNextToken(token) & (token.symbol # Scanner.EndOfText) DO
  832. Scanner.PrintToken(context.out, token); context.out.Ln;
  833. END;
  834. END TestScanner;
  835. END FoxAssembler.
  836. System.Free FoxAssembler ~
  837. FoxAssembler.Test
  838. ;---------------- intermediate code -----------------
  839. .module BitSets
  840. .imports SYSTEM
  841. .const BitSets.@moduleSelf offset=0
  842. 0: data u32 0
  843. .const BitSets.BitSet offset=0
  844. 0: data u32 0
  845. .code BitSets.BitSet.InitBitSet offset=0
  846. 0: enter 0, 0
  847. 1: mov u32 r1, u32 [fp+8]
  848. 2: mov s32 [r1], s32 [fp+12]
  849. 3: push s32 [fp+12]
  850. 4: mov u32 r2, u32 [fp+8]
  851. 5: add u32 r3, u32 [r2-4], u32 -88
  852. 6: push u32 r2
  853. 7: call u32 [r3], 8
  854. 8: leave 0
  855. 9: exit 8
  856. .code BitSets.BitSet.Zero offset=0
  857. 0: enter 0, 8
  858. 1: mov s32 [fp-4], s32 0
  859. 2: mov u32 r1, u32 [fp+8]
  860. 3: mov u32 r2, u32 [r1+4]
  861. 4: conv s32 r3, u32 [r2+12]
  862. 5: sub s32 r3, s32 r3, s32 1
  863. 6: mov s32 [fp-8], s32 r3
  864. 7: brlt u32 BitSets.BitSet.Zero:21, s32 [fp-8], s32 [fp-4]
  865. 8: br u32 BitSets.BitSet.Zero:9
  866. 9: conv u32 r4, s32 [fp-4]
  867. 10: mov u32 r5, u32 r4
  868. 11: mov u32 r6, u32 [fp+8]
  869. 12: mov u32 r7, u32 [r6+4]
  870. 13: brlt u32 BitSets.BitSet.Zero:15, u32 r4, u32 [r7+12]
  871. 14: trap 7
  872. 15: mul u32 r5, u32 r5, u32 4
  873. 16: add u32 r5, u32 r5, u32 r7+16
  874. 17: mov u32 [r5], u32 0
  875. 18: add s32 r8, s32 [fp-4], s32 1
  876. 19: mov s32 [fp-4], s32 r8
  877. 20: br u32 BitSets.BitSet.Zero:7
  878. 21: leave 0
  879. 22: exit 4
  880. .code BitSets.BitSet.Resize offset=0
  881. 0: enter 0, 12
  882. 1: brlt u32 BitSets.BitSet.Resize:3, s32 [fp+12], s32 0
  883. 2: br u32 BitSets.BitSet.Resize:4
  884. 3: trap 8
  885. 4: mov u32 r1, u32 [fp+8]
  886. 5: mov s32 [r1], s32 [fp+12]
  887. 6: sub s32 r2, s32 [fp+12], s32 1
  888. 7: brlt u32 BitSets.BitSet.Resize:10, s32 r2, s32 0
  889. 8: mov s32 r2, s32 r2
  890. 9: br u32 BitSets.BitSet.Resize:11
  891. 10: mov s32 r2, s32 0, s32 r2
  892. 11: shr s32 r2, s32 r2, s32 5
  893. 12: add s32 r2, s32 r2, s32 1
  894. 13: mov s32 [fp+12], s32 r2
  895. 14: mov u32 r3, u32 [fp+8]
  896. 15: breq u32 BitSets.BitSet.Resize:35, u32 [r3+4], u32 0
  897. 16: br u32 BitSets.BitSet.Resize:17
  898. 17: mov u32 r4, u32 [fp+8]
  899. 18: mov u32 r5, u32 [r4+4]
  900. 19: conv s32 r6, u32 [r5+12]
  901. 20: brlt u32 BitSets.BitSet.Resize:25, s32 r6, s32 [fp+12]
  902. 21: br u32 BitSets.BitSet.Resize:22
  903. 22: leave 0
  904. 23: exit 8
  905. 24: br u32 BitSets.BitSet.Resize:25
  906. 25: mov u32 r7, u32 [fp+8]
  907. 26: mov u32 r8, u32 [r7+4]
  908. 27: conv s32 r9, u32 [r8+12]
  909. 28: shl s32 r9, s32 r9, s32 1
  910. 29: brlt u32 BitSets.BitSet.Resize:32, s32 [fp+12], s32 r9
  911. 30: mov s32 r9, s32 [fp+12]
  912. 31: br u32 BitSets.BitSet.Resize:33
  913. 32: mov s32 r9, s32 r9, s32 r9
  914. 33: mov s32 [fp+12], s32 r9
  915. 34: br u32 BitSets.BitSet.Resize:35
  916. 35: brge u32 BitSets.BitSet.Resize:37, s32 [fp+12], s32 0
  917. 36: trap 9
  918. 37: push s32 [fp+12]
  919. 38: mov s32 r10, s32 [fp+12]
  920. 39: conv u32 r10, s32 r10
  921. 40: mul u32 r10, u32 r10, u32 4
  922. 41: add u32 r10, u32 r10, u32 16
  923. 42: push u32 fp-4
  924. 43: push u32 fp-4
  925. 44: push u32 r10
  926. 45: push u8 0
  927. 46: call u32 $SystemCall2:0, 0
  928. 47: pop u32 r11
  929. 48: mov u32 r12, u32 [r11]
  930. 49: breq u32 BitSets.BitSet.Resize:53, u32 r12, u32 0
  931. 50: pop u32 r13
  932. 51: mov u32 [r12+12], u32 r13
  933. 52: br u32 BitSets.BitSet.Resize:54
  934. 53: add u32 sp, u32 sp, u32 4
  935. 54: mov u32 r14, u32 [fp+8]
  936. 55: breq u32 BitSets.BitSet.Resize:85, u32 [r14+4], u32 0
  937. 56: br u32 BitSets.BitSet.Resize:57
  938. 57: mov s32 [fp-8], s32 0
  939. 58: mov u32 r15, u32 [fp+8]
  940. 59: mov u32 r16, u32 [r15+4]
  941. 60: conv s32 r17, u32 [r16+12]
  942. 61: sub s32 r17, s32 r17, s32 1
  943. 62: mov s32 [fp-12], s32 r17
  944. 63: brlt u32 BitSets.BitSet.Resize:84, s32 [fp-12], s32 [fp-8]
  945. 64: br u32 BitSets.BitSet.Resize:65
  946. 65: conv u32 r18, s32 [fp-8]
  947. 66: mov u32 r19, u32 r18
  948. 67: mov u32 r20, u32 [fp+8]
  949. 68: mov u32 r21, u32 [r20+4]
  950. 69: brlt u32 BitSets.BitSet.Resize:71, u32 r18, u32 [r21+12]
  951. 70: trap 7
  952. 71: mul u32 r19, u32 r19, u32 4
  953. 72: add u32 r19, u32 r19, u32 r21+16
  954. 73: conv u32 r22, s32 [fp-8]
  955. 74: mov u32 r23, u32 r22
  956. 75: mov u32 r24, u32 [fp-4]
  957. 76: brlt u32 BitSets.BitSet.Resize:78, u32 r22, u32 [r24+12]
  958. 77: trap 7
  959. 78: mul u32 r23, u32 r23, u32 4
  960. 79: add u32 r23, u32 r23, u32 r24+16
  961. 80: mov u32 [r23], u32 [r19]
  962. 81: add s32 r25, s32 [fp-8], s32 1
  963. 82: mov s32 [fp-8], s32 r25
  964. 83: br u32 BitSets.BitSet.Resize:63
  965. 84: br u32 BitSets.BitSet.Resize:85
  966. 85: mov u32 r26, u32 [fp+8]
  967. 86: mov u32 [r26+4], u32 [fp-4]
  968. 87: leave 0
  969. 88: exit 8
  970. .code BitSets.BitSet.GetSize offset=0
  971. 0: enter 0, 0
  972. 1: mov u32 r1, u32 [fp+8]
  973. 2: return s32 [r1]
  974. 3: leave 0
  975. 4: exit 4
  976. 5: trap 3