authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 12:25:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 12:25:30-07:00
log2f0e4e9cb26df7a6f6251d0e865d0d964680831e
tree24716849a69bdc49d82e87a599f58d2b4e6c50f3
parent3e06ed0e8cdfba69e28600a2fcf52d795a86f3bb

codegen does signed, unsigned, and floating point math


4 files changed, 106 insertions(+), 15 deletions(-)

src/codegen.cpp+86-15
...@@ -210,6 +210,10 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -210,6 +210,10 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
210 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);210 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
211 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);211 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
212212
213 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
214 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
215 assert(op1_type == op2_type);
216
213 switch (node->data.bin_op_expr.bin_op) {217 switch (node->data.bin_op_expr.bin_op) {
214 case BinOpTypeBinOr:218 case BinOpTypeBinOr:
215 add_debug_source_node(g, node);219 add_debug_source_node(g, node);
...@@ -224,29 +228,51 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -224,29 +228,51 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
224 add_debug_source_node(g, node);228 add_debug_source_node(g, node);
225 return LLVMBuildShl(g->builder, val1, val2, "");229 return LLVMBuildShl(g->builder, val1, val2, "");
226 case BinOpTypeBitShiftRight:230 case BinOpTypeBitShiftRight:
227 // TODO implement type system so that we know whether to do
228 // logical or arithmetic shifting here.
229 // signed -> arithmetic, unsigned -> logical
230 add_debug_source_node(g, node);231 add_debug_source_node(g, node);
231 return LLVMBuildLShr(g->builder, val1, val2, "");232 if (op1_type->is_signed_int) {
233 return LLVMBuildAShr(g->builder, val1, val2, "");
234 } else {
235 return LLVMBuildLShr(g->builder, val1, val2, "");
236 }
232 case BinOpTypeAdd:237 case BinOpTypeAdd:
233 add_debug_source_node(g, node);238 add_debug_source_node(g, node);
234 return LLVMBuildAdd(g->builder, val1, val2, "");239 if (op1_type->is_float) {
240 return LLVMBuildFAdd(g->builder, val1, val2, "");
241 } else {
242 return LLVMBuildNSWAdd(g->builder, val1, val2, "");
243 }
235 case BinOpTypeSub:244 case BinOpTypeSub:
236 add_debug_source_node(g, node);245 add_debug_source_node(g, node);
237 return LLVMBuildSub(g->builder, val1, val2, "");246 if (op1_type->is_float) {
247 return LLVMBuildFSub(g->builder, val1, val2, "");
248 } else {
249 return LLVMBuildNSWSub(g->builder, val1, val2, "");
250 }
238 case BinOpTypeMult:251 case BinOpTypeMult:
239 // TODO types so we know float vs int
240 add_debug_source_node(g, node);252 add_debug_source_node(g, node);
241 return LLVMBuildMul(g->builder, val1, val2, "");253 if (op1_type->is_float) {
254 return LLVMBuildFMul(g->builder, val1, val2, "");
255 } else {
256 return LLVMBuildNSWMul(g->builder, val1, val2, "");
257 }
242 case BinOpTypeDiv:258 case BinOpTypeDiv:
243 // TODO types so we know float vs int and signed vs unsigned
244 add_debug_source_node(g, node);259 add_debug_source_node(g, node);
245 return LLVMBuildSDiv(g->builder, val1, val2, "");260 if (op1_type->is_float) {
261 return LLVMBuildFDiv(g->builder, val1, val2, "");
262 } else if (op1_type->is_signed_int) {
263 return LLVMBuildSDiv(g->builder, val1, val2, "");
264 } else {
265 return LLVMBuildUDiv(g->builder, val1, val2, "");
266 }
246 case BinOpTypeMod:267 case BinOpTypeMod:
247 // TODO types so we know float vs int and signed vs unsigned
248 add_debug_source_node(g, node);268 add_debug_source_node(g, node);
249 return LLVMBuildSRem(g->builder, val1, val2, "");269 if (op1_type->is_float) {
270 return LLVMBuildFRem(g->builder, val1, val2, "");
271 } else if (op1_type->is_signed_int) {
272 return LLVMBuildSRem(g->builder, val1, val2, "");
273 } else {
274 return LLVMBuildURem(g->builder, val1, val2, "");
275 }
250 case BinOpTypeBoolOr:276 case BinOpTypeBoolOr:
251 case BinOpTypeBoolAnd:277 case BinOpTypeBoolAnd:
252 case BinOpTypeCmpEq:278 case BinOpTypeCmpEq:
...@@ -281,16 +307,43 @@ static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed...@@ -281,16 +307,43 @@ static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed
281 }307 }
282}308}
283309
310static LLVMRealPredicate cmp_op_to_real_predicate(BinOpType cmp_op) {
311 switch (cmp_op) {
312 case BinOpTypeCmpEq:
313 return LLVMRealOEQ;
314 case BinOpTypeCmpNotEq:
315 return LLVMRealONE;
316 case BinOpTypeCmpLessThan:
317 return LLVMRealOLT;
318 case BinOpTypeCmpGreaterThan:
319 return LLVMRealOGT;
320 case BinOpTypeCmpLessOrEq:
321 return LLVMRealOLE;
322 case BinOpTypeCmpGreaterOrEq:
323 return LLVMRealOGE;
324 default:
325 zig_unreachable();
326 }
327}
328
284static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {329static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {
285 assert(node->type == NodeTypeBinOpExpr);330 assert(node->type == NodeTypeBinOpExpr);
286331
287 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);332 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
288 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);333 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
289334
290 // TODO implement type system so that we know whether to do signed or unsigned comparison here335 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
291 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, true);336 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
337 assert(op1_type == op2_type);
338
292 add_debug_source_node(g, node);339 add_debug_source_node(g, node);
293 return LLVMBuildICmp(g->builder, pred, val1, val2, "");340 if (op1_type->is_float) {
341 LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op);
342 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
343 } else {
344 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, op1_type->is_signed_int);
345 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
346 }
294}347}
295348
296static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {349static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
...@@ -847,12 +900,26 @@ static void define_primitive_types(CodeGen *g) {...@@ -847,12 +900,26 @@ static void define_primitive_types(CodeGen *g) {
847 buf_init_from_str(&entry->name, "i32");900 buf_init_from_str(&entry->name, "i32");
848 entry->size_in_bits = 32;901 entry->size_in_bits = 32;
849 entry->align_in_bits = 32;902 entry->align_in_bits = 32;
903 entry->is_signed_int = true;
850 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),904 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
851 entry->size_in_bits, entry->align_in_bits,905 entry->size_in_bits, entry->align_in_bits,
852 LLVMZigEncoding_DW_ATE_signed());906 LLVMZigEncoding_DW_ATE_signed());
853 g->type_table.put(&entry->name, entry);907 g->type_table.put(&entry->name, entry);
854 g->builtin_types.entry_i32 = entry;908 g->builtin_types.entry_i32 = entry;
855 }909 }
910 {
911 TypeTableEntry *entry = new_type_table_entry();
912 entry->type_ref = LLVMFloatType();
913 buf_init_from_str(&entry->name, "f32");
914 entry->size_in_bits = 32;
915 entry->align_in_bits = 32;
916 entry->is_float = true;
917 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
918 entry->size_in_bits, entry->align_in_bits,
919 LLVMZigEncoding_DW_ATE_float());
920 g->type_table.put(&entry->name, entry);
921 g->builtin_types.entry_f32 = entry;
922 }
856 {923 {
857 TypeTableEntry *entry = new_type_table_entry();924 TypeTableEntry *entry = new_type_table_entry();
858 entry->type_ref = LLVMVoidType();925 entry->type_ref = LLVMVoidType();
...@@ -918,6 +985,8 @@ static void init(CodeGen *g, Buf *source_path) {...@@ -918,6 +985,8 @@ static void init(CodeGen *g, Buf *source_path) {
918 g->builder = LLVMCreateBuilder();985 g->builder = LLVMCreateBuilder();
919 g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);986 g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
920987
988 LLVMZigSetFastMath(g->builder, true);
989
921990
922 define_primitive_types(g);991 define_primitive_types(g);
923992
...@@ -1058,6 +1127,8 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {...@@ -1058,6 +1127,8 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
1058 } else if (type_entry == g->builtin_types.entry_i32) {1127 } else if (type_entry == g->builtin_types.entry_i32) {
1059 g->c_stdint_used = true;1128 g->c_stdint_used = true;
1060 buf_init_from_str(out_buf, "int32_t");1129 buf_init_from_str(out_buf, "int32_t");
1130 } else if (type_entry == g->builtin_types.entry_f32) {
1131 buf_init_from_str(out_buf, "float");
1061 } else if (type_entry == g->builtin_types.entry_unreachable) {1132 } else if (type_entry == g->builtin_types.entry_unreachable) {
1062 buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void");1133 buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void");
1063 } else if (type_entry == g->builtin_types.entry_bool) {1134 } else if (type_entry == g->builtin_types.entry_bool) {
src/semantic_info.hpp+3
...@@ -21,6 +21,8 @@ struct TypeTableEntry {...@@ -21,6 +21,8 @@ struct TypeTableEntry {
21 LLVMZigDIType *di_type;21 LLVMZigDIType *di_type;
22 uint64_t size_in_bits;22 uint64_t size_in_bits;
23 uint64_t align_in_bits;23 uint64_t align_in_bits;
24 bool is_signed_int;
25 bool is_float;
2426
25 TypeTableEntry *pointer_child;27 TypeTableEntry *pointer_child;
26 bool pointer_is_const;28 bool pointer_is_const;
...@@ -82,6 +84,7 @@ struct CodeGen {...@@ -82,6 +84,7 @@ struct CodeGen {
82 TypeTableEntry *entry_bool;84 TypeTableEntry *entry_bool;
83 TypeTableEntry *entry_u8;85 TypeTableEntry *entry_u8;
84 TypeTableEntry *entry_i32;86 TypeTableEntry *entry_i32;
87 TypeTableEntry *entry_f32;
85 TypeTableEntry *entry_string_literal;88 TypeTableEntry *entry_string_literal;
86 TypeTableEntry *entry_void;89 TypeTableEntry *entry_void;
87 TypeTableEntry *entry_unreachable;90 TypeTableEntry *entry_unreachable;
src/zig_llvm.cpp+14
...@@ -185,6 +185,10 @@ unsigned LLVMZigEncoding_DW_ATE_signed(void) {...@@ -185,6 +185,10 @@ unsigned LLVMZigEncoding_DW_ATE_signed(void) {
185 return dwarf::DW_ATE_signed;185 return dwarf::DW_ATE_signed;
186}186}
187187
188unsigned LLVMZigEncoding_DW_ATE_float(void) {
189 return dwarf::DW_ATE_float;
190}
191
188unsigned LLVMZigLang_DW_LANG_C99(void) {192unsigned LLVMZigLang_DW_LANG_C99(void) {
189 return dwarf::DW_LANG_C99;193 return dwarf::DW_LANG_C99;
190}194}
...@@ -322,6 +326,16 @@ LLVMZigDILocation *LLVMZigGetDebugLoc(unsigned line, unsigned col, LLVMZigDIScop...@@ -322,6 +326,16 @@ LLVMZigDILocation *LLVMZigGetDebugLoc(unsigned line, unsigned col, LLVMZigDIScop
322 return reinterpret_cast<LLVMZigDILocation*>(debug_loc.get());326 return reinterpret_cast<LLVMZigDILocation*>(debug_loc.get());
323}327}
324328
329void LLVMZigSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {
330 if (on_state) {
331 FastMathFlags fmf;
332 fmf.setUnsafeAlgebra();
333 unwrap(builder_wrapped)->SetFastMathFlags(fmf);
334 } else {
335 unwrap(builder_wrapped)->clearFastMathFlags();
336 }
337}
338
325//------------------------------------339//------------------------------------
326340
327enum FloatAbi {341enum FloatAbi {
src/zig_llvm.hpp+3
...@@ -55,6 +55,7 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder...@@ -55,6 +55,7 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder
5555
56unsigned LLVMZigEncoding_DW_ATE_unsigned(void);56unsigned LLVMZigEncoding_DW_ATE_unsigned(void);
57unsigned LLVMZigEncoding_DW_ATE_signed(void);57unsigned LLVMZigEncoding_DW_ATE_signed(void);
58unsigned LLVMZigEncoding_DW_ATE_float(void);
58unsigned LLVMZigLang_DW_LANG_C99(void);59unsigned LLVMZigLang_DW_LANG_C99(void);
59unsigned LLVMZigTag_DW_auto_variable(void);60unsigned LLVMZigTag_DW_auto_variable(void);
60unsigned LLVMZigTag_DW_arg_variable(void);61unsigned LLVMZigTag_DW_arg_variable(void);
...@@ -96,6 +97,8 @@ LLVMValueRef LLVMZigInsertDeclare(LLVMZigDIBuilder *dibuilder, LLVMValueRef stor...@@ -96,6 +97,8 @@ LLVMValueRef LLVMZigInsertDeclare(LLVMZigDIBuilder *dibuilder, LLVMValueRef stor
96 LLVMZigDILocalVariable *var_info, LLVMZigDILocation *debug_loc, LLVMValueRef insert_before_instr);97 LLVMZigDILocalVariable *var_info, LLVMZigDILocation *debug_loc, LLVMValueRef insert_before_instr);
97LLVMZigDILocation *LLVMZigGetDebugLoc(unsigned line, unsigned col, LLVMZigDIScope *scope);98LLVMZigDILocation *LLVMZigGetDebugLoc(unsigned line, unsigned col, LLVMZigDIScope *scope);
9899
100void LLVMZigSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
101
99102
100/*103/*
101 * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here.104 * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here.