2
0

racpugas.pas 22 KB

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