codegen: avoid table lookup in assembly expression

master
Andrew Kelley 2016-02-01 20:13:36 -07:00
parent 74eaf43768
commit a2035eefba
3 changed files with 42 additions and 38 deletions

View File

@ -535,6 +535,9 @@ struct AsmOutput {
Buf constraint;
Buf variable_name;
AstNode *return_type; // null unless "=r" and return
// populated by semantic analyzer
VariableTableEntry *variable;
};
struct AsmInput {

View File

@ -2431,19 +2431,6 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
return g->builtin_types.entry_invalid;
}
static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node, Buf *variable_name)
{
VariableTableEntry *var = find_variable(context, variable_name);
if (var) {
return var->type;
} else {
add_node_error(g, node,
buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
return g->builtin_types.entry_invalid;
}
}
static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
switch (op) {
case BinOpTypeAssign:
@ -4402,6 +4389,42 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
return return_type;
}
static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
node->data.asm_expr.return_count = 0;
TypeTableEntry *return_type = g->builtin_types.entry_void;
for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
if (asm_output->return_type) {
node->data.asm_expr.return_count += 1;
return_type = analyze_type_expr(g, import, context, asm_output->return_type);
if (node->data.asm_expr.return_count > 1) {
add_node_error(g, node,
buf_sprintf("inline assembly allows up to one output value"));
break;
}
} else {
Buf *variable_name = &asm_output->variable_name;
VariableTableEntry *var = find_variable(context, variable_name);
if (var) {
asm_output->variable = var;
return var->type;
} else {
add_node_error(g, node,
buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
return g->builtin_types.entry_invalid;
}
}
}
for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
analyze_expression(g, import, context, nullptr, asm_input->expr);
}
return return_type;
}
// When you call analyze_expression, the node you pass might no longer be the child node
// you thought it was due to implicit casting rewriting the AST.
static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@ -4441,30 +4464,8 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
return_type = analyze_continue_expr(g, import, context, expected_type, node);
break;
case NodeTypeAsmExpr:
{
node->data.asm_expr.return_count = 0;
return_type = g->builtin_types.entry_void;
for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
if (asm_output->return_type) {
node->data.asm_expr.return_count += 1;
return_type = analyze_type_expr(g, import, context, asm_output->return_type);
if (node->data.asm_expr.return_count > 1) {
add_node_error(g, node,
buf_sprintf("inline assembly allows up to one output value"));
break;
}
} else {
analyze_variable_name(g, import, context, node, &asm_output->variable_name);
}
}
for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
analyze_expression(g, import, context, nullptr, asm_input->expr);
}
break;
}
return_type = analyze_asm_expr(g, import, context, expected_type, node);
break;
case NodeTypeBinOpExpr:
return_type = analyze_bin_op_expr(g, import, context, expected_type, node);
break;

View File

@ -1822,7 +1822,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
}
if (!is_return) {
VariableTableEntry *variable = find_variable( node->block_context, &asm_output->variable_name);
VariableTableEntry *variable = asm_output->variable;
assert(variable);
param_types[param_index] = LLVMTypeOf(variable->value_ref);
param_values[param_index] = variable->value_ref;