Support negation, parentheses. Always zero-extend registers for bugless memory operand usage
This commit is contained in:
		
							parent
							
								
									fa40a78546
								
							
						
					
					
						commit
						012320569e
					
				
							
								
								
									
										56
									
								
								src/cg.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								src/cg.c
									
									
									
									
									
								
							| @ -5,6 +5,8 @@ | ||||
| #include<string.h> | ||||
| #include<assert.h> | ||||
| 
 | ||||
| #include"x86.h" | ||||
| 
 | ||||
| #define REGS 4 | ||||
| static const char *regs[REGS][3] = {{"al", "ax", "eax"}, {"bl", "bx", "ebx"}, {"cl", "cx", "ecx"}, {"dl", "dx", "edx"}}; | ||||
| 
 | ||||
| @ -51,7 +53,7 @@ static const char *specexpr(AST *e) { | ||||
| 	return spec(type_size(e->expression.type)); | ||||
| } | ||||
| 
 | ||||
| static const char *xv(VarTableEntry *v) { | ||||
| static const char *xv_sz(VarTableEntry *v, int sz) { | ||||
| 	assert(v->kind == VARTABLEENTRY_VAR); | ||||
| 	 | ||||
| #define XVBUFS 8 | ||||
| @ -64,7 +66,7 @@ static const char *xv(VarTableEntry *v) { | ||||
| #ifdef DEBUG | ||||
| 	snprintf(ret, XVBUFSZ, "@%i", v->data.var.color); | ||||
| #else | ||||
| 	snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(type_size(v->type))]); | ||||
| 	snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(sz)]); | ||||
| #endif | ||||
| 	 | ||||
| 	bufidx = (bufidx + 1) % XVBUFS; | ||||
| @ -72,6 +74,10 @@ static const char *xv(VarTableEntry *v) { | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const char *xv(VarTableEntry *v) { | ||||
| 	return xv_sz(v, type_size(v->type)); | ||||
| } | ||||
| 
 | ||||
| static const char *xj(BinaryOp op) { | ||||
| 	switch(op) { | ||||
| 	case BINOP_EQUAL: return "e"; | ||||
| @ -80,7 +86,7 @@ static const char *xj(BinaryOp op) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static const char *xop(AST *e) { | ||||
| static const char *xop_sz(AST *e, int sz) { | ||||
| #define XOPBUFS 16 | ||||
| #define XOPBUFSZ 24 | ||||
| 	static char bufs[XOPBUFS][XOPBUFSZ]; | ||||
| @ -92,25 +98,32 @@ static const char *xop(AST *e) { | ||||
| 		VarTableEntry *v = e->exprVar.thing; | ||||
| 		 | ||||
| 		if(v->kind == VARTABLEENTRY_VAR) { | ||||
| 			return xv(v); | ||||
| 			return xv_sz(v, sz); | ||||
| 		} else if(v->kind == VARTABLEENTRY_SYMBOL) { | ||||
| 			snprintf(ret, XOPBUFSZ, "[%s]", v->data.symbol.name); | ||||
| 		} else abort(); | ||||
| 	} else if(e->nodeKind == AST_EXPR_PRIMITIVE) { | ||||
| 		snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val); | ||||
| 	} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { | ||||
| 		snprintf(ret, XOPBUFSZ, "%s [%s + %s]", | ||||
| 			spec(sz), | ||||
| 			xv_sz(e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing, 4), | ||||
| 			xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4)); | ||||
| 	} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { | ||||
| 		snprintf(ret, XOPBUFSZ, "[%s + %s]", | ||||
| 		snprintf(ret, XOPBUFSZ, "%s [%s + %s]", | ||||
| 			spec(sz), | ||||
| 			e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, | ||||
| 			xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing)); | ||||
| 			xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4)); | ||||
| 	} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { | ||||
| 		snprintf(ret, XOPBUFSZ, "[%s + %i * %s]", | ||||
| 		snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]", | ||||
| 			spec(sz), | ||||
| 			e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, | ||||
| 			e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val, | ||||
| 			xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing)); | ||||
| 			xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4)); | ||||
| 	} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) { | ||||
| 		snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name); | ||||
| 	} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_VAR) { | ||||
| 		snprintf(ret, XOPBUFSZ, "[%s]", xv(e->exprUnOp.operand->exprVar.thing)); | ||||
| 		snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(e->exprUnOp.operand->exprVar.thing, 4)); | ||||
| 	} else { | ||||
| 		return NULL; | ||||
| 	} | ||||
| @ -120,6 +133,10 @@ static const char *xop(AST *e) { | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const char *xop(AST *e) { | ||||
| 	return xop_sz(e, type_size(e->expression.type)); | ||||
| } | ||||
| 
 | ||||
| void cg_chunk(AST *a) { | ||||
| 	AST *s = a->chunk.statementFirst; | ||||
| 	 | ||||
| @ -201,9 +218,24 @@ void cg_chunk(AST *a) { | ||||
| 						s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, | ||||
| 						xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing)); | ||||
| 					 | ||||
| 				} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR) { | ||||
| 					 | ||||
| 					printf("lea %s, [%s + %i]\n", | ||||
| 						xv_sz(s->stmtAssign.what->exprVar.thing, 4), | ||||
| 						xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4), | ||||
| 						s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val); | ||||
| 				 | ||||
| 				} else if(is_xop(s->stmtAssign.what) != NULL && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) { | ||||
| 					 | ||||
| 					printf("neg %s\n", xop(s->stmtAssign.what)); | ||||
| 					 | ||||
| 				} else { | ||||
| 				 | ||||
| 					printf("mov %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to)); | ||||
| 					if(is_xop(s->stmtAssign.to) == XOP_MEM && type_size(s->stmtAssign.what->expression.type) != type_size(s->stmtAssign.to->expression.type)) { | ||||
| 						printf("movzx %s, %s\n", xop_sz(s->stmtAssign.what, 4), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); | ||||
| 					} else { | ||||
| 						printf("mov %s, %s\n", xop(s->stmtAssign.what), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); | ||||
| 					} | ||||
| 					 | ||||
| 				} | ||||
| 			} | ||||
| @ -241,7 +273,7 @@ void cg_chunk(AST *a) { | ||||
| 			 | ||||
| 			size_t lbl = nextLocalLabel++; | ||||
| 			 | ||||
| 			printf("cmp %s %s, %s\n", specexpr(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1])); | ||||
| 			printf("cmp %s, %s\n", xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1])); | ||||
| 			printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl); | ||||
| 			 | ||||
| 			cg_chunk(s->stmtIf.then); | ||||
| @ -363,4 +395,4 @@ nextColor:; | ||||
| 	cg_chunk(a); | ||||
| 	 | ||||
| 	free(vars); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -11,37 +11,7 @@ | ||||
| // This pass, along with CG is strictly dependent on x86 and will fail for
 | ||||
| // any other architecture.
 | ||||
| 
 | ||||
| // Can expression be expressed as a single x86 operand?
 | ||||
| #define XOP_NOT_XOP 0 | ||||
| #define XOP_NOT_MEM 1 | ||||
| #define XOP_MEM 2 | ||||
| static int is_xop(AST *e) { | ||||
| 	if(e->nodeKind == AST_EXPR_PRIMITIVE) { | ||||
| 		return XOP_NOT_MEM; | ||||
| 	} else if(e->nodeKind == AST_EXPR_VAR) { | ||||
| 		return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM; | ||||
| 	} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) { | ||||
| 		return XOP_NOT_MEM; | ||||
| 	} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { | ||||
| 		AST *c = e->exprUnOp.operand; | ||||
| 		 | ||||
| 		if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) { | ||||
| 			return XOP_MEM; | ||||
| 		} else if(c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) { | ||||
| 			if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { | ||||
| 				return XOP_MEM; | ||||
| 			} else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { | ||||
| 				int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val; | ||||
| 				 | ||||
| 				if(scale == 1 || scale == 2 || scale == 4 || scale == 8) { | ||||
| 					return XOP_MEM; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	return XOP_NOT_XOP; | ||||
| } | ||||
| #include"x86.h" | ||||
| 
 | ||||
| static void varify_change_usedefs(AST *e, AST *oldStmt, AST *newStmt) { | ||||
| 	if(e->nodeKind == AST_EXPR_VAR) { | ||||
| @ -185,6 +155,28 @@ static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { | ||||
| 	return varify(tlc, chunk, stmtPrev, stmt, e); | ||||
| } | ||||
| 
 | ||||
| static UseDef *get_last_usedef_before_stmt(AST *tlc, VarTableEntry *v, AST *stmt) { | ||||
| 	assert(v->kind == VARTABLEENTRY_VAR); | ||||
| 	 | ||||
| 	UseDef *ud = v->data.var.usedefFirst; | ||||
| 	 | ||||
| 	if(!ud) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	 | ||||
| 	UseDef *udPrev = NULL; | ||||
| 	 | ||||
| 	while(ud) { | ||||
| 		if(ast_stmt_is_after(tlc, ud->stmt, stmt)) { | ||||
| 			break; | ||||
| 		} | ||||
| 		udPrev = ud; | ||||
| 		ud = ud->next; | ||||
| 	} | ||||
| 	 | ||||
| 	return udPrev; | ||||
| } | ||||
| 
 | ||||
| static int dumben_chunk(AST *tlc, AST *chu) { | ||||
| 	AST *sPrev = NULL; | ||||
| 	AST *s = chu->chunk.statementFirst; | ||||
| @ -238,6 +230,59 @@ static int dumben_chunk(AST *tlc, AST *chu) { | ||||
| 				effective = 1; | ||||
| 			} | ||||
| 			 | ||||
| 			if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && (s->stmtAssign.to->exprUnOp.operand->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing != s->stmtAssign.to->exprUnOp.operand->exprVar.thing)) { | ||||
| 				// Turn this:
 | ||||
| 				//  a = -b
 | ||||
| 				// into
 | ||||
| 				//  a = b
 | ||||
| 				//  a = -a
 | ||||
| 				// While keeping UD-chain valid.
 | ||||
| 				 | ||||
| 				// Currently only for variables. While this could work for any XOP, it requires the ability to deep-copy `a`, which is not trivial when taking into account UD-chains.
 | ||||
| 				// TODO: Scrap incremental UD-chain modifications. Simply rebuild them after each pass.
 | ||||
| 				 | ||||
| 				ASTExprVar *ev[2]; | ||||
| 				for(int i = 0; i < 2; i++) { | ||||
| 					ev[i] = malloc(sizeof(ASTExprVar)); | ||||
| 					ev[i]->nodeKind = AST_EXPR_VAR; | ||||
| 					ev[i]->type = s->stmtAssign.what->expression.type; | ||||
| 					ev[i]->thing = s->stmtAssign.what->exprVar.thing; | ||||
| 				} | ||||
| 				 | ||||
| 				AST *negation = s->stmtAssign.to; | ||||
| 				 | ||||
| 				s->stmtAssign.to = negation->exprUnOp.operand; | ||||
| 				negation->exprUnOp.operand = ev[0]; | ||||
| 				 | ||||
| 				AST *assign2 = malloc(sizeof(ASTStmtAssign)); | ||||
| 				assign2->nodeKind = AST_STMT_ASSIGN; | ||||
| 				assign2->stmtAssign.what = ev[1]; | ||||
| 				assign2->stmtAssign.to = negation; | ||||
| 				 | ||||
| 				assign2->statement.next = s->statement.next; | ||||
| 				s->statement.next = assign2; | ||||
| 
 | ||||
| 				UseDef *link = get_last_usedef_before_stmt(tlc, ev[0]->thing, assign2->statement.next); | ||||
| 				 | ||||
| 				UseDef *ud[2]; | ||||
| 				ud[0] = malloc(sizeof(UseDef)); | ||||
| 				ud[1] = malloc(sizeof(UseDef)); | ||||
| 
 | ||||
| 				ud[0]->stmt = assign2; | ||||
| 				ud[0]->use = (AST*) ev[1]; | ||||
| 				ud[0]->def = s; | ||||
| 				ud[0]->next = ud[1]; | ||||
| 
 | ||||
| 				ud[1]->stmt = assign2; | ||||
| 				ud[1]->use = (AST*) ev[0]; | ||||
| 				ud[1]->def = s; | ||||
| 				ud[1]->next = link->next; | ||||
| 				 | ||||
| 				link->next = ud[0]; | ||||
| 				 | ||||
| 				effective = 1; | ||||
| 			} | ||||
| 			 | ||||
| 		} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) { | ||||
| 			 | ||||
| 			int argCount = s->stmtExpr.expr->exprCall.what->expression.type->function.argCount; | ||||
| @ -260,4 +305,4 @@ static int dumben_chunk(AST *tlc, AST *chu) { | ||||
| 
 | ||||
| void dumben_go(AST* tlc) { | ||||
| 	while(dumben_chunk(tlc, tlc)); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -285,6 +285,10 @@ AST *nct_parse_expression(Parser *P, int lOP) { | ||||
| 			ret->length = tok.length; | ||||
| 			 | ||||
| 			return (AST*) ret; | ||||
| 		} else if(maybe(P, TOKEN_PAREN_L)) { | ||||
| 			AST *e = nct_parse_expression(P, 0); | ||||
| 			expect(P, TOKEN_PAREN_R); | ||||
| 			return e; | ||||
| 		} | ||||
| 	} else if(lOP == 4) { | ||||
| 		if(maybe(P, TOKEN_STAR)) { | ||||
|  | ||||
| @ -1,2 +1,6 @@ | ||||
| u32 x: 123; | ||||
| u33 y: 5; | ||||
| u33 y: 5; | ||||
| 
 | ||||
| u3 *o = 5000; | ||||
| u3 z = *o; | ||||
| u3 p = *(o + z); | ||||
|  | ||||
| @ -2,10 +2,11 @@ u16 x: 5; | ||||
| loop { | ||||
| 	u16* y = 257; | ||||
| 	u9 w = -4; | ||||
| 	u4 z = 3 + *y; | ||||
| 	u16 p = *y; | ||||
| 	u4 z = p + 3; | ||||
| 	u2 o = -w; | ||||
| 	 | ||||
| 	if(x != 0) { | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -4,4 +4,6 @@ loop { | ||||
| 	a = 3; | ||||
| 	 | ||||
| 	u8 b = 1; | ||||
| 	 | ||||
| 	u8 c = 2; | ||||
| } | ||||
| @ -1,5 +1,5 @@ | ||||
| u8 a = 5; | ||||
| if(a) { | ||||
| if(a != 0) { | ||||
| 	u8 a = 10; /* Should not cause scoping errors. */ | ||||
| } | ||||
| u8 b = 15; /* `a` in the if statement scope should be free'd. */ | ||||
| u8 b = 15; /* `a` in the if statement scope should be free'd. */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 mid
						mid