| ... | ... | @@ -210,6 +210,10 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 210 | 210 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 211 | 211 | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); |
| 212 | 212 | |
| 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 | 217 | switch (node->data.bin_op_expr.bin_op) { |
| 214 | 218 | case BinOpTypeBinOr: |
| 215 | 219 | add_debug_source_node(g, node); |
| ... | ... | @@ -224,29 +228,51 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 224 | 228 | add_debug_source_node(g, node); |
| 225 | 229 | return LLVMBuildShl(g->builder, val1, val2, ""); |
| 226 | 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 | 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 | 237 | case BinOpTypeAdd: |
| 233 | 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 | 244 | case BinOpTypeSub: |
| 236 | 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 | 251 | case BinOpTypeMult: |
| 239 | | // TODO types so we know float vs int |
| 240 | 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 | 258 | case BinOpTypeDiv: |
| 243 | | // TODO types so we know float vs int and signed vs unsigned |
| 244 | 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 | 267 | case BinOpTypeMod: |
| 247 | | // TODO types so we know float vs int and signed vs unsigned |
| 248 | 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 | 276 | case BinOpTypeBoolOr: |
| 251 | 277 | case BinOpTypeBoolAnd: |
| 252 | 278 | case BinOpTypeCmpEq: |
| ... | ... | @@ -281,16 +307,43 @@ static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed |
| 281 | 307 | } |
| 282 | 308 | } |
| 283 | 309 | |
| 310 | static 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 | |
| 284 | 329 | static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { |
| 285 | 330 | assert(node->type == NodeTypeBinOpExpr); |
| 286 | 331 | |
| 287 | 332 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 288 | 333 | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); |
| 289 | 334 | |
| 290 | | // TODO implement type system so that we know whether to do signed or unsigned comparison here |
| 291 | | LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, true); |
| 335 | TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); |
| 336 | TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); |
| 337 | assert(op1_type == op2_type); |
| 338 | |
| 292 | 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 | } |
| 295 | 348 | |
| 296 | 349 | static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { |
| ... | ... | @@ -847,12 +900,26 @@ static void define_primitive_types(CodeGen *g) { |
| 847 | 900 | buf_init_from_str(&entry->name, "i32"); |
| 848 | 901 | entry->size_in_bits = 32; |
| 849 | 902 | entry->align_in_bits = 32; |
| 903 | entry->is_signed_int = true; |
| 850 | 904 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 851 | 905 | entry->size_in_bits, entry->align_in_bits, |
| 852 | 906 | LLVMZigEncoding_DW_ATE_signed()); |
| 853 | 907 | g->type_table.put(&entry->name, entry); |
| 854 | 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 | 924 | TypeTableEntry *entry = new_type_table_entry(); |
| 858 | 925 | entry->type_ref = LLVMVoidType(); |
| ... | ... | @@ -918,6 +985,8 @@ static void init(CodeGen *g, Buf *source_path) { |
| 918 | 985 | g->builder = LLVMCreateBuilder(); |
| 919 | 986 | g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); |
| 920 | 987 | |
| 988 | LLVMZigSetFastMath(g->builder, true); |
| 989 | |
| 921 | 990 | |
| 922 | 991 | define_primitive_types(g); |
| 923 | 992 | |
| ... | ... | @@ -1058,6 +1127,8 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { |
| 1058 | 1127 | } else if (type_entry == g->builtin_types.entry_i32) { |
| 1059 | 1128 | g->c_stdint_used = true; |
| 1060 | 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 | 1132 | } else if (type_entry == g->builtin_types.entry_unreachable) { |
| 1062 | 1133 | buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void"); |
| 1063 | 1134 | } else if (type_entry == g->builtin_types.entry_bool) { |