racpugas.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Mazen NEIFER
  4. Does the parsing for the i386 GNU AS styled inline assembler.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit racpugas;
  19. {$i fpcdefs.inc}
  20. Interface
  21. uses
  22. raatt,racpu;
  23. type
  24. tSparcReader = class(tattreader)
  25. function is_asmopcode(const s: string):boolean;override;
  26. procedure handleopcode;override;
  27. procedure BuildReference(oper : tSparcoperand);
  28. procedure BuildOperand(oper : tSparcoperand);
  29. procedure BuildOpCode(instr : tSparcinstruction);
  30. procedure ReadPercent(oper : tSparcoperand);
  31. procedure ReadSym(oper : tSparcoperand);
  32. procedure ConvertCalljmp(instr : tSparcinstruction);
  33. procedure handlepercent;override;
  34. end;
  35. Implementation
  36. uses
  37. { helpers }
  38. cutils,
  39. { global }
  40. globtype,globals,verbose,
  41. systems,
  42. { aasm }
  43. cpubase,aasmbase,aasmtai,aasmcpu,
  44. { symtable }
  45. symconst,symsym,
  46. { parser }
  47. scanner,
  48. procinfo,
  49. rabase,rautils,
  50. cgbase,cgobj
  51. ;
  52. procedure TSparcReader.ReadSym(oper : tSparcoperand);
  53. var
  54. tempstr : string;
  55. typesize,l,k : aint;
  56. begin
  57. tempstr:=actasmpattern;
  58. Consume(AS_ID);
  59. { typecasting? }
  60. if (actasmtoken=AS_LPAREN) and
  61. SearchType(tempstr,typesize) then
  62. begin
  63. oper.hastype:=true;
  64. Consume(AS_LPAREN);
  65. BuildOperand(oper);
  66. Consume(AS_RPAREN);
  67. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  68. oper.SetSize(typesize,true);
  69. end
  70. else
  71. if not oper.SetupVar(tempstr,false) then
  72. Message1(sym_e_unknown_id,tempstr);
  73. { record.field ? }
  74. if actasmtoken=AS_DOT then
  75. begin
  76. BuildRecordOffsetSize(tempstr,l,k);
  77. inc(oper.opr.ref.offset,l);
  78. end;
  79. end;
  80. procedure TSparcReader.ReadPercent(oper : tSparcoperand);
  81. begin
  82. { check for ...@ }
  83. if actasmtoken=AS_AT then
  84. begin
  85. if (oper.opr.ref.symbol=nil) and
  86. (oper.opr.ref.offset = 0) then
  87. Message(asmr_e_invalid_reference_syntax);
  88. Consume(AS_AT);
  89. if actasmtoken=AS_ID then
  90. begin
  91. if upper(actasmpattern)='LO' then
  92. oper.opr.ref.refaddr:=addr_lo
  93. else if upper(actasmpattern)='HI' then
  94. oper.opr.ref.refaddr:=addr_hi
  95. else
  96. Message(asmr_e_invalid_reference_syntax);
  97. Consume(AS_ID);
  98. end
  99. else
  100. Message(asmr_e_invalid_reference_syntax);
  101. end;
  102. end;
  103. Procedure TSparcReader.BuildReference(oper : tSparcoperand);
  104. var
  105. l : aint;
  106. regs : byte;
  107. hasimm : boolean;
  108. begin
  109. oper.initref;
  110. regs:=0;
  111. hasimm:=false;
  112. Consume(AS_LBRACKET);
  113. repeat
  114. Case actasmtoken of
  115. AS_INTNUM,
  116. AS_MINUS,
  117. AS_PLUS:
  118. Begin
  119. if hasimm or (regs>1) then
  120. Begin
  121. Message(asmr_e_invalid_reference_syntax);
  122. RecoverConsume(true);
  123. break;
  124. End;
  125. oper.opr.Ref.Offset:=BuildConstExpression(false,true);
  126. hasimm:=true;
  127. End;
  128. AS_REGISTER:
  129. Begin
  130. if regs<2 then
  131. begin
  132. if regs=0 then
  133. oper.opr.ref.base:=actasmregister
  134. else
  135. oper.opr.ref.index:=actasmregister;
  136. inc(regs);
  137. end
  138. else
  139. begin
  140. Message(asmr_e_invalid_reference_syntax);
  141. RecoverConsume(true);
  142. break;
  143. end;
  144. Consume(AS_REGISTER);
  145. end;
  146. AS_ID:
  147. Begin
  148. l:=BuildConstExpression(true,true);
  149. inc(oper.opr.ref.offset,l);
  150. End;
  151. AS_RBRACKET:
  152. begin
  153. if (regs=0) and (not hasimm) then
  154. Message(asmr_e_invalid_reference_syntax);
  155. Consume(AS_RBRACKET);
  156. break;
  157. end;
  158. else
  159. Begin
  160. Message(asmr_e_invalid_reference_syntax);
  161. RecoverConsume(false);
  162. break;
  163. end;
  164. end;
  165. until false;
  166. end;
  167. procedure TSparcReader.handlepercent;
  168. var
  169. len : longint;
  170. begin
  171. len:=1;
  172. actasmpattern[len]:='%';
  173. c:=current_scanner.asmgetchar;
  174. { to be a register there must be a letter and not a number }
  175. while c in ['a'..'z','A'..'Z','0'..'9'] do
  176. Begin
  177. inc(len);
  178. actasmpattern[len]:=c;
  179. c:=current_scanner.asmgetchar;
  180. end;
  181. actasmpattern[0]:=chr(len);
  182. uppervar(actasmpattern);
  183. if is_register(actasmpattern) then
  184. exit;
  185. if (actasmpattern='%HI') then
  186. actasmtoken:=AS_HI
  187. else if (actasmpattern='%LO')then
  188. actasmtoken:=AS_LO
  189. else
  190. Message(asmr_e_invalid_register);
  191. end;
  192. Procedure TSparcReader.BuildOperand(oper : tSparcoperand);
  193. var
  194. expr : string;
  195. typesize,l : aint;
  196. procedure AddLabelOperand(hl:tasmlabel);
  197. begin
  198. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  199. is_calljmp(actopcode) then
  200. begin
  201. oper.opr.typ:=OPR_SYMBOL;
  202. oper.opr.symbol:=hl;
  203. end
  204. else
  205. begin
  206. oper.InitRef;
  207. oper.opr.ref.symbol:=hl;
  208. end;
  209. end;
  210. procedure MaybeRecordOffset;
  211. var
  212. hasdot : boolean;
  213. l,
  214. toffset,
  215. tsize : aint;
  216. begin
  217. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  218. exit;
  219. l:=0;
  220. hasdot:=(actasmtoken=AS_DOT);
  221. if hasdot then
  222. begin
  223. if expr<>'' then
  224. begin
  225. BuildRecordOffsetSize(expr,toffset,tsize);
  226. inc(l,toffset);
  227. oper.SetSize(tsize,true);
  228. end;
  229. end;
  230. if actasmtoken in [AS_PLUS,AS_MINUS] then
  231. inc(l,BuildConstExpression(true,false));
  232. case oper.opr.typ of
  233. OPR_LOCAL :
  234. begin
  235. { don't allow direct access to fields of parameters, because that
  236. will generate buggy code. Allow it only for explicit typecasting }
  237. if hasdot and
  238. (not oper.hastype) and
  239. (tvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
  240. (current_procinfo.procdef.proccalloption<>pocall_register) then
  241. Message(asmr_e_cannot_access_field_directly_for_parameters);
  242. inc(oper.opr.localsymofs,l)
  243. end;
  244. OPR_CONSTANT :
  245. inc(oper.opr.val,l);
  246. OPR_REFERENCE :
  247. inc(oper.opr.ref.offset,l);
  248. else
  249. internalerror(200309221);
  250. end;
  251. end;
  252. var
  253. tempreg : tregister;
  254. tempstr : string;
  255. hl : tasmlabel;
  256. gotplus,
  257. negative : boolean;
  258. Begin
  259. expr:='';
  260. gotplus:=true;
  261. negative:=false;
  262. repeat
  263. case actasmtoken of
  264. AS_MINUS :
  265. begin
  266. consume(AS_MINUS);
  267. negative:=true;
  268. gotplus:=true;
  269. end;
  270. AS_PLUS :
  271. begin
  272. consume(AS_PLUS);
  273. negative:=false;
  274. gotplus:=true;
  275. end;
  276. AS_INTNUM,
  277. AS_MOD:
  278. Begin
  279. if not gotplus then
  280. Message(asmr_e_invalid_reference_syntax);
  281. l:=BuildConstExpression(True,False);
  282. if negative then
  283. l:=-l;
  284. { Constant memory offset }
  285. oper.InitRef;
  286. oper.opr.ref.refaddr:=addr_full;
  287. oper.opr.ref.offset:=l;
  288. GotPlus:=(prevasmtoken=AS_PLUS) or
  289. (prevasmtoken=AS_MINUS);
  290. if GotPlus then
  291. negative:=(prevasmtoken=AS_MINUS);
  292. end;
  293. AS_LBRACKET :
  294. begin
  295. { memory reference }
  296. BuildReference(oper);
  297. gotplus:=false;
  298. end;
  299. AS_HI,
  300. AS_LO:
  301. begin
  302. { Low or High part of a constant (or constant
  303. memory location) }
  304. oper.InitRef;
  305. if actasmtoken=AS_LO then
  306. oper.opr.ref.refaddr:=addr_lo
  307. else
  308. oper.opr.ref.refaddr:=addr_hi;
  309. Consume(actasmtoken);
  310. Consume(AS_LPAREN);
  311. BuildConstSymbolExpression(false, true,false,l,tempstr);
  312. if not assigned(oper.opr.ref.symbol) then
  313. oper.opr.ref.symbol:=objectlibrary.newasmsymbol(tempstr,AB_EXTERNAL,AT_FUNCTION)
  314. else
  315. Message(asmr_e_cant_have_multiple_relocatable_symbols);
  316. case oper.opr.typ of
  317. OPR_CONSTANT :
  318. inc(oper.opr.val,l);
  319. OPR_LOCAL :
  320. inc(oper.opr.localsymofs,l);
  321. OPR_REFERENCE :
  322. inc(oper.opr.ref.offset,l);
  323. else
  324. internalerror(200309202);
  325. end;
  326. Consume(AS_RPAREN);
  327. gotplus:=false;
  328. end;
  329. AS_ID: { A constant expression, or a Variable ref. }
  330. Begin
  331. { Local Label ? }
  332. if is_locallabel(actasmpattern) then
  333. begin
  334. CreateLocalLabel(actasmpattern,hl,false);
  335. Consume(AS_ID);
  336. AddLabelOperand(hl);
  337. end
  338. else
  339. { Check for label }
  340. if SearchLabel(actasmpattern,hl,false) then
  341. begin
  342. Consume(AS_ID);
  343. AddLabelOperand(hl);
  344. end
  345. else
  346. { probably a variable or normal expression }
  347. { or a procedure (such as in CALL ID) }
  348. Begin
  349. { is it a constant ? }
  350. if SearchIConstant(actasmpattern,l) then
  351. Begin
  352. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  353. Message(asmr_e_invalid_operand_type);
  354. BuildConstantOperand(oper);
  355. end
  356. else
  357. begin
  358. expr:=actasmpattern;
  359. Consume(AS_ID);
  360. { typecasting? }
  361. if (actasmtoken=AS_LPAREN) and
  362. SearchType(expr,typesize) then
  363. begin
  364. oper.hastype:=true;
  365. Consume(AS_LPAREN);
  366. BuildOperand(oper);
  367. Consume(AS_RPAREN);
  368. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  369. oper.SetSize(typesize,true);
  370. end
  371. else
  372. begin
  373. if oper.SetupVar(expr,false) then
  374. ReadPercent(oper)
  375. else
  376. Begin
  377. { look for special symbols ... }
  378. if expr= '__HIGH' then
  379. begin
  380. consume(AS_LPAREN);
  381. if not oper.setupvar('high'+actasmpattern,false) then
  382. Message1(sym_e_unknown_id,'high'+actasmpattern);
  383. consume(AS_ID);
  384. consume(AS_RPAREN);
  385. end
  386. else
  387. if expr = '__RESULT' then
  388. oper.SetUpResult
  389. else
  390. if expr = '__SELF' then
  391. oper.SetupSelf
  392. else
  393. if expr = '__OLDEBP' then
  394. oper.SetupOldEBP
  395. else
  396. { check for direct symbolic names }
  397. { only if compiling the system unit }
  398. if (cs_compilesystem in aktmoduleswitches) then
  399. begin
  400. if not oper.SetupDirectVar(expr) then
  401. Begin
  402. { not found, finally ... add it anyways ... }
  403. Message1(asmr_w_id_supposed_external,expr);
  404. oper.InitRef;
  405. oper.opr.ref.symbol:=objectlibrary.newasmsymbol(expr,AB_EXTERNAL,AT_FUNCTION);
  406. end;
  407. end
  408. else
  409. Message1(sym_e_unknown_id,expr);
  410. end;
  411. end;
  412. end;
  413. if actasmtoken=AS_DOT then
  414. MaybeRecordOffset;
  415. { add a constant expression? }
  416. if (actasmtoken=AS_PLUS) then
  417. begin
  418. l:=BuildConstExpression(true,false);
  419. case oper.opr.typ of
  420. OPR_CONSTANT :
  421. inc(oper.opr.val,l);
  422. OPR_LOCAL :
  423. inc(oper.opr.localsymofs,l);
  424. OPR_REFERENCE :
  425. inc(oper.opr.ref.offset,l);
  426. else
  427. internalerror(200309202);
  428. end;
  429. end
  430. end;
  431. gotplus:=false;
  432. end;
  433. AS_REGISTER: { Register, a variable reference or a constant reference }
  434. Begin
  435. { save the type of register used. }
  436. tempreg:=actasmregister;
  437. Consume(AS_REGISTER);
  438. if (oper.opr.typ in [OPR_REGISTER,OPR_REFERENCE]) and gotplus then
  439. begin
  440. oper.initref;
  441. oper.opr.ref.refaddr:=addr_full;
  442. if oper.opr.ref.base<>NR_NO then
  443. oper.opr.ref.base:=tempreg
  444. else
  445. if oper.opr.ref.index<>NR_NO then
  446. oper.opr.ref.index:=tempreg
  447. else
  448. Message(asmr_e_multiple_index);
  449. end
  450. else
  451. begin
  452. if (oper.opr.typ<>OPR_NONE) then
  453. Message(asmr_e_invalid_operand_type);
  454. oper.opr.typ:=OPR_REGISTER;
  455. oper.opr.reg:=tempreg;
  456. end;
  457. gotplus:=false;
  458. end;
  459. AS_END,
  460. AS_SEPARATOR,
  461. AS_COMMA:
  462. break;
  463. else
  464. Begin
  465. Message(asmr_e_syn_operand);
  466. Consume(actasmtoken);
  467. end;
  468. end; { end case }
  469. until false;
  470. end;
  471. {*****************************************************************************
  472. TSparcReader
  473. *****************************************************************************}
  474. procedure TSparcReader.BuildOpCode(instr : tSparcinstruction);
  475. var
  476. operandnum : longint;
  477. Begin
  478. { opcode }
  479. if (actasmtoken<>AS_OPCODE) then
  480. Begin
  481. Message(asmr_e_invalid_or_missing_opcode);
  482. RecoverConsume(true);
  483. exit;
  484. end;
  485. { Fill the instr object with the current state }
  486. with instr do
  487. begin
  488. Opcode:=ActOpcode;
  489. condition:=ActCondition;
  490. end;
  491. { We are reading operands, so opcode will be an AS_ID }
  492. operandnum:=1;
  493. Consume(AS_OPCODE);
  494. { Zero operand opcode ? }
  495. if actasmtoken in [AS_SEPARATOR,AS_END] then
  496. begin
  497. operandnum:=0;
  498. exit;
  499. end;
  500. { delayslot annulled? }
  501. if (actasmtoken=AS_COMMA) then
  502. begin
  503. consume(AS_COMMA);
  504. if actasmpattern='A' then
  505. instr.delayslot_annulled:=true;
  506. { force reading of AS_COMMA instead of AS_ID, otherwise
  507. a label .L0 will first read a AS_DOT instead of AS_ID }
  508. actasmtoken:=AS_COMMA;
  509. consume(AS_COMMA);
  510. end;
  511. { Read the operands }
  512. repeat
  513. case actasmtoken of
  514. AS_COMMA: { Operand delimiter }
  515. Begin
  516. if operandnum>Max_Operands then
  517. Message(asmr_e_too_many_operands)
  518. else
  519. begin
  520. { condition operands doesn't set the operand but write to the
  521. condition field of the instruction
  522. }
  523. if instr.Operands[operandnum].opr.typ<>OPR_NONE then
  524. Inc(operandnum);
  525. end;
  526. Consume(AS_COMMA);
  527. end;
  528. AS_SEPARATOR,
  529. AS_END : { End of asm operands for this opcode }
  530. begin
  531. break;
  532. end;
  533. else
  534. BuildOperand(instr.Operands[operandnum] as tSparcoperand);
  535. end; { end case }
  536. until false;
  537. if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
  538. dec(operandnum);
  539. instr.Ops:=operandnum;
  540. end;
  541. function TSparcReader.is_asmopcode(const s: string):boolean;
  542. var
  543. str2opEntry: tstr2opEntry;
  544. cond:TAsmCond;
  545. Begin
  546. { making s a value parameter would break other assembler readers }
  547. is_asmopcode:=false;
  548. { clear op code }
  549. actopcode:=A_None;
  550. { clear condition }
  551. fillchar(actcondition,sizeof(actcondition),0);
  552. str2opentry:=tstr2opentry(iasmops.search(s));
  553. if assigned(str2opentry) then
  554. begin
  555. actopcode:=str2opentry.op;
  556. actasmtoken:=AS_OPCODE;
  557. is_asmopcode:=true;
  558. end
  559. { not found, check branch instructions }
  560. else if (Upcase(s[1])='B') or
  561. ((Upcase(s[1])='F') and (Upcase(s[2])='B')) then
  562. begin
  563. { we can search here without an extra table which is sorted by string length
  564. because we take the whole remaining string without the leading B }
  565. if (Upcase(s[1])='F') then
  566. actopcode := A_FBxx
  567. else
  568. actopcode := A_Bxx;
  569. for cond:=low(TAsmCond) to high(TAsmCond) do
  570. if (Upper(copy(s,2,length(s)-1))=Upper(Cond2Str[cond])) then
  571. begin
  572. actasmtoken:=AS_OPCODE;
  573. actcondition:=cond;
  574. is_asmopcode:=true;
  575. end;
  576. end;
  577. end;
  578. procedure TSparcReader.ConvertCalljmp(instr : tSparcinstruction);
  579. var
  580. newopr : toprrec;
  581. begin
  582. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  583. with newopr do
  584. begin
  585. typ:=OPR_SYMBOL;
  586. symbol:=instr.Operands[1].opr.ref.symbol;
  587. symofs:=instr.Operands[1].opr.ref.offset;
  588. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  589. (instr.Operands[1].opr.ref.index<>NR_NO) or
  590. (instr.Operands[1].opr.ref.refaddr<>addr_full) then
  591. Message(asmr_e_syn_operand);
  592. instr.Operands[1].opr:=newopr;
  593. end;
  594. end;
  595. procedure TSparcReader.handleopcode;
  596. var
  597. instr : tSparcinstruction;
  598. begin
  599. instr:=TSparcInstruction.Create(TSparcOperand);
  600. BuildOpcode(instr);
  601. with instr do
  602. begin
  603. condition := actcondition;
  604. if is_calljmp(opcode) then
  605. ConvertCalljmp(instr);
  606. ConcatInstruction(curlist);
  607. Free;
  608. end;
  609. end;
  610. {*****************************************************************************
  611. Initialize
  612. *****************************************************************************}
  613. const
  614. asmmode_Sparc_att_info : tasmmodeinfo =
  615. (
  616. id : asmmode_Sparc_gas;
  617. idtxt : 'GAS';
  618. casmreader : TSparcReader;
  619. );
  620. asmmode_Sparc_standard_info : tasmmodeinfo =
  621. (
  622. id : asmmode_standard;
  623. idtxt : 'STANDARD';
  624. casmreader : TSparcReader;
  625. );
  626. initialization
  627. RegisterAsmMode(asmmode_Sparc_att_info);
  628. RegisterAsmMode(asmmode_Sparc_standard_info);
  629. end.
  630. {
  631. $Log$
  632. Revision 1.10 2004-06-20 08:55:32 florian
  633. * logs truncated
  634. Revision 1.9 2004/06/16 20:07:11 florian
  635. * dwarf branch merged
  636. Revision 1.8.2.4 2004/06/02 20:59:05 peter
  637. * fix negative consts
  638. Revision 1.8.2.3 2004/05/25 21:38:53 peter
  639. * assembler reader/writer updates
  640. Revision 1.8.2.2 2004/05/18 20:24:03 florian
  641. * fixed crash with unknown symbols
  642. Revision 1.8.2.1 2004/05/01 23:36:47 peter
  643. * assembler reader 64bit fixes
  644. }